diff --git a/forge-ai/src/main/java/forge/ai/AiAttackController.java b/forge-ai/src/main/java/forge/ai/AiAttackController.java
index 51798704399..dbb8567af57 100644
--- a/forge-ai/src/main/java/forge/ai/AiAttackController.java
+++ b/forge-ai/src/main/java/forge/ai/AiAttackController.java
@@ -464,7 +464,7 @@ public class AiAttackController {
final CardCollectionView beastions = ai.getCardsIn(ZoneType.Battlefield, "Beastmaster Ascension");
int minCreatures = 7;
for (final Card beastion : beastions) {
- final int counters = beastion.getCounters(CounterType.QUEST);
+ final int counters = beastion.getCounters(CounterEnumType.QUEST);
minCreatures = Math.min(minCreatures, 7 - counters);
}
if (this.attackers.size() >= minCreatures) {
@@ -1065,7 +1065,7 @@ public class AiAttackController {
}
}
// if enough damage: switch to next planeswalker or player
- if (damage >= pw.getCounters(CounterType.LOYALTY)) {
+ if (damage >= pw.getCounters(CounterEnumType.LOYALTY)) {
List pwDefending = combat.getDefendingPlaneswalkers();
boolean found = false;
// look for next planeswalker
@@ -1192,7 +1192,7 @@ public class AiAttackController {
if (isWorthLessThanAllKillers || canKillAllDangerous || numberOfPossibleBlockers < 2) {
numberOfPossibleBlockers += 1;
if (isWorthLessThanAllKillers && ComputerUtilCombat.canDestroyAttacker(ai, attacker, defender, combat, false)
- && !(attacker.hasKeyword(Keyword.UNDYING) && attacker.getCounters(CounterType.P1P1) == 0)) {
+ && !(attacker.hasKeyword(Keyword.UNDYING) && attacker.getCounters(CounterEnumType.P1P1) == 0)) {
canBeKilledByOne = true; // there is a single creature on the battlefield that can kill the creature
// see if the defending creature is of higher or lower
// value. We don't want to attack only to lose value
diff --git a/forge-ai/src/main/java/forge/ai/AiBlockController.java b/forge-ai/src/main/java/forge/ai/AiBlockController.java
index bef6eaa8961..7f1104d95fd 100644
--- a/forge-ai/src/main/java/forge/ai/AiBlockController.java
+++ b/forge-ai/src/main/java/forge/ai/AiBlockController.java
@@ -228,9 +228,9 @@ public class AiBlockController {
// 3.Blockers that can destroy the attacker and have an upside when dying
killingBlockers = getKillingBlockers(combat, attacker, blockers);
for (Card b : killingBlockers) {
- if ((b.hasKeyword(Keyword.UNDYING) && b.getCounters(CounterType.P1P1) == 0) || b.hasSVar("SacMe")
- || (b.hasKeyword(Keyword.VANISHING) && b.getCounters(CounterType.TIME) == 1)
- || (b.hasKeyword(Keyword.FADING) && b.getCounters(CounterType.FADE) == 0)
+ if ((b.hasKeyword(Keyword.UNDYING) && b.getCounters(CounterEnumType.P1P1) == 0) || b.hasSVar("SacMe")
+ || (b.hasKeyword(Keyword.VANISHING) && b.getCounters(CounterEnumType.TIME) == 1)
+ || (b.hasKeyword(Keyword.FADING) && b.getCounters(CounterEnumType.FADE) == 0)
|| b.hasSVar("EndOfTurnLeavePlay")) {
blocker = b;
break;
@@ -299,8 +299,8 @@ public class AiBlockController {
final List blockers = getPossibleBlockers(combat, attacker, blockersLeft, true);
for (Card b : blockers) {
- if ((b.hasKeyword(Keyword.VANISHING) && b.getCounters(CounterType.TIME) == 1)
- || (b.hasKeyword(Keyword.FADING) && b.getCounters(CounterType.FADE) == 0)
+ if ((b.hasKeyword(Keyword.VANISHING) && b.getCounters(CounterEnumType.TIME) == 1)
+ || (b.hasKeyword(Keyword.FADING) && b.getCounters(CounterEnumType.FADE) == 0)
|| b.hasSVar("EndOfTurnLeavePlay")) {
blocker = b;
if (!ComputerUtilCombat.canDestroyAttacker(ai, attacker, blocker, combat, false)) {
@@ -851,7 +851,7 @@ public class AiBlockController {
damageToPW += ComputerUtilCombat.predictDamageTo((Card) def, pwatkr.getNetCombatDamage(), pwatkr, true);
}
}
- if ((!onlyIfLethal && damageToPW > 0) || damageToPW >= def.getCounters(CounterType.LOYALTY)) {
+ if ((!onlyIfLethal && damageToPW > 0) || damageToPW >= def.getCounters(CounterEnumType.LOYALTY)) {
threatenedPWs.add((Card) def);
}
}
@@ -909,7 +909,7 @@ public class AiBlockController {
damageToPW += ComputerUtilCombat.predictDamageTo(pw, pwAtk.getNetCombatDamage(), pwAtk, true);
}
}
- if (!isFullyBlocked && damageToPW >= pw.getCounters(CounterType.LOYALTY)) {
+ if (!isFullyBlocked && damageToPW >= pw.getCounters(CounterEnumType.LOYALTY)) {
for (Card chump : pwDefenders) {
if (chosenChumpBlockers.contains(chump)) {
combat.removeFromCombat(chump);
diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java
index b8777e5be1c..8f941ed6886 100644
--- a/forge-ai/src/main/java/forge/ai/AiController.java
+++ b/forge-ai/src/main/java/forge/ai/AiController.java
@@ -177,7 +177,7 @@ public class AiController {
&& CardFactoryUtil.isCounterable(host)) {
return true;
} else if ("ChaliceOfTheVoid".equals(curse) && sa.isSpell() && CardFactoryUtil.isCounterable(host)
- && host.getCMC() == c.getCounters(CounterType.CHARGE)) {
+ && host.getCMC() == c.getCounters(CounterEnumType.CHARGE)) {
return true;
} else if ("BazaarOfWonders".equals(curse) && sa.isSpell() && CardFactoryUtil.isCounterable(host)) {
String hostName = host.getName();
@@ -1801,7 +1801,7 @@ public class AiController {
throw new UnsupportedOperationException("AI is not supposed to reach this code at the moment");
}
- public CardCollection chooseCardsForEffect(CardCollectionView pool, SpellAbility sa, int min, int max, boolean isOptional) {
+ public CardCollection chooseCardsForEffect(CardCollectionView pool, SpellAbility sa, int min, int max, boolean isOptional, Map params) {
if (sa == null || sa.getApi() == null) {
throw new UnsupportedOperationException();
}
@@ -1834,7 +1834,7 @@ public class AiController {
default:
CardCollection editablePool = new CardCollection(pool);
for (int i = 0; i < max; i++) {
- Card c = player.getController().chooseSingleEntityForEffect(editablePool, sa, null, isOptional);
+ Card c = player.getController().chooseSingleEntityForEffect(editablePool, sa, null, isOptional, params);
if (c != null) {
result.add(c);
editablePool.remove(c);
diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java
index 95a967e337c..ee480003207 100644
--- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java
+++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java
@@ -16,6 +16,7 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.cost.*;
import forge.game.player.Player;
@@ -627,41 +628,41 @@ public class AiCostDecision extends CostDecisionMakerBase {
// the first things are benefit from removing counters
// try to remove +1/+1 counter from undying creature
- List prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterType.P1P1, c),
+ List prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.P1P1, c),
CardPredicates.hasKeyword("Undying"));
if (!prefs.isEmpty()) {
- Collections.sort(prefs, CardPredicates.compareByCounterType(CounterType.P1P1));
+ Collections.sort(prefs, CardPredicates.compareByCounterType(CounterEnumType.P1P1));
PaymentDecision result = PaymentDecision.card(prefs);
- result.ct = CounterType.P1P1;
+ result.ct = CounterType.get(CounterEnumType.P1P1);
return result;
}
// try to remove -1/-1 counter from persist creature
- prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterType.M1M1, c),
+ prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.M1M1, c),
CardPredicates.hasKeyword("Persist"));
if (!prefs.isEmpty()) {
- Collections.sort(prefs, CardPredicates.compareByCounterType(CounterType.M1M1));
+ Collections.sort(prefs, CardPredicates.compareByCounterType(CounterEnumType.M1M1));
PaymentDecision result = PaymentDecision.card(prefs);
- result.ct = CounterType.M1M1;
+ result.ct = CounterType.get(CounterEnumType.M1M1);
return result;
}
// try to remove Time counter from Chronozoa, it will generate more
- prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterType.TIME, c),
+ prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.TIME, c),
CardPredicates.nameEquals("Chronozoa"));
if (!prefs.isEmpty()) {
- Collections.sort(prefs, CardPredicates.compareByCounterType(CounterType.TIME));
+ Collections.sort(prefs, CardPredicates.compareByCounterType(CounterEnumType.TIME));
PaymentDecision result = PaymentDecision.card(prefs);
- result.ct = CounterType.TIME;
+ result.ct = CounterType.get(CounterEnumType.TIME);
return result;
}
// try to remove Quest counter on something with enough counters for the
// effect to continue
- prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterType.QUEST, c));
+ prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.QUEST, c));
if (!prefs.isEmpty()) {
prefs = CardLists.filter(prefs, new Predicate() {
@@ -673,12 +674,12 @@ public class AiCostDecision extends CostDecisionMakerBase {
if (crd.hasSVar("MaxQuestEffect")) {
e = Integer.parseInt(crd.getSVar("MaxQuestEffect"));
}
- return crd.getCounters(CounterType.QUEST) >= e + c;
+ return crd.getCounters(CounterEnumType.QUEST) >= e + c;
}
});
- Collections.sort(prefs, Collections.reverseOrder(CardPredicates.compareByCounterType(CounterType.QUEST)));
+ Collections.sort(prefs, Collections.reverseOrder(CardPredicates.compareByCounterType(CounterEnumType.QUEST)));
PaymentDecision result = PaymentDecision.card(prefs);
- result.ct = CounterType.QUEST;
+ result.ct = CounterType.get(CounterEnumType.QUEST);
return result;
}
@@ -775,7 +776,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
@Override
public boolean apply(final Card crd) {
for (Map.Entry e : crd.getCounters().entrySet()) {
- if (e.getValue() >= c && (ctr.equals("ANY") || e.getKey() == CounterType.valueOf(ctr))) {
+ if (e.getValue() >= c && (ctr.equals("ANY") || e.getKey().equals(CounterType.getType(ctr)))) {
return true;
}
}
@@ -787,7 +788,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
PaymentDecision result = PaymentDecision.card(card);
for (Map.Entry e : card.getCounters().entrySet()) {
- if (e.getValue() >= c && (ctr.equals("ANY") || e.getKey() == CounterType.valueOf(ctr))) {
+ if (e.getValue() >= c && (ctr.equals("ANY") || e.getKey().equals(CounterType.getType(ctr)))) {
result.ct = e.getKey();
break;
}
diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java
index d87c8a68802..5cd886aaf7f 100644
--- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java
+++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java
@@ -6,12 +6,12 @@
* 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 .
*/
@@ -65,7 +65,7 @@ import java.util.*;
*
* ComputerUtil class.
*
- *
+ *
* @author Forge
* @version $Id$
*/
@@ -213,7 +213,7 @@ public class ComputerUtil {
sa.setActivatingPlayer(ai);
if (!ComputerUtilCost.canPayCost(sa, ai))
return false;
-
+
final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) {
sa.setHostCard(game.getAction().moveToStack(source, sa));
@@ -349,8 +349,8 @@ public class ComputerUtil {
for (int ip = 0; ip < 6; ip++) {
final int priority = 6 - ip;
if (priority == 2 && ai.isCardInPlay("Crucible of Worlds")) {
- CardCollection landsInPlay = CardLists.getType(typeList, "Land");
- if (!landsInPlay.isEmpty()) {
+ CardCollection landsInPlay = CardLists.getType(typeList, "Land");
+ if (!landsInPlay.isEmpty()) {
// Don't need more land.
return ComputerUtilCard.getWorstLand(landsInPlay);
}
@@ -379,16 +379,16 @@ public class ComputerUtil {
return ComputerUtilCard.getWorstLand(landsInPlay);
}
}
-
+
// try everything when about to die
- if (game.getPhaseHandler().getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS)
- && ComputerUtilCombat.lifeInSeriousDanger(ai, game.getCombat())) {
- final CardCollection nonCreatures = CardLists.getNotType(typeList, "Creature");
- if (!nonCreatures.isEmpty()) {
- return ComputerUtilCard.getWorstAI(nonCreatures);
- } else if (!typeList.isEmpty()) {
- return ComputerUtilCard.getWorstAI(typeList);
- }
+ if (game.getPhaseHandler().getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS)
+ && ComputerUtilCombat.lifeInSeriousDanger(ai, game.getCombat())) {
+ final CardCollection nonCreatures = CardLists.getNotType(typeList, "Creature");
+ if (!nonCreatures.isEmpty()) {
+ return ComputerUtilCard.getWorstAI(nonCreatures);
+ } else if (!typeList.isEmpty()) {
+ return ComputerUtilCard.getWorstAI(typeList);
+ }
}
}
else if (pref.contains("DiscardCost")) { // search for permanents with DiscardMe
@@ -450,14 +450,14 @@ public class ComputerUtil {
return ComputerUtilCard.getWorstLand(landsInHand);
}
}
-
+
// try everything when about to die
if (activate != null && "Reality Smasher".equals(activate.getName()) ||
- game.getPhaseHandler().getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS)
- && ComputerUtilCombat.lifeInSeriousDanger(ai, game.getCombat())) {
- if (!typeList.isEmpty()) {
- return ComputerUtilCard.getWorstAI(typeList);
- }
+ game.getPhaseHandler().getPhase().equals(PhaseType.COMBAT_DECLARE_BLOCKERS)
+ && ComputerUtilCombat.lifeInSeriousDanger(ai, game.getCombat())) {
+ if (!typeList.isEmpty()) {
+ return ComputerUtilCard.getWorstAI(typeList);
+ }
}
} else if (pref.contains("DonateMe")) {
// search for permanents with DonateMe. priority 1 is the lowest, priority 5 the highest
@@ -540,7 +540,7 @@ public class ComputerUtil {
public static CardCollection chooseExileFrom(final Player ai, final ZoneType zone, final String type, final Card activate,
final Card target, final int amount) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null);
-
+
if ((target != null) && target.getController() == ai) {
typeList.remove(target); // don't exile the card we're pumping
}
@@ -561,7 +561,7 @@ public class ComputerUtil {
public static CardCollection choosePutToLibraryFrom(final Player ai, final ZoneType zone, final String type, final Card activate,
final Card target, final int amount) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null);
-
+
if ((target != null) && target.getController() == ai) {
typeList.remove(target); // don't move the card we're pumping
}
@@ -572,11 +572,11 @@ public class ComputerUtil {
CardLists.sortByPowerAsc(typeList);
final CardCollection list = new CardCollection();
-
+
if (zone != ZoneType.Hand) {
Collections.reverse(typeList);
}
-
+
for (int i = 0; i < amount; i++) {
list.add(typeList.get(i));
}
@@ -636,7 +636,7 @@ public class ComputerUtil {
}
ComputerUtilCard.sortByEvaluateCreature(typeList);
Collections.reverse(typeList);
-
+
final CardCollection tapList = new CardCollection();
// Accumulate from "worst" creature
@@ -709,7 +709,7 @@ public class ComputerUtil {
return returnList;
}
- public static CardCollection choosePermanentsToSacrifice(final Player ai, final CardCollectionView cardlist, final int amount, final SpellAbility source,
+ public static CardCollection choosePermanentsToSacrifice(final Player ai, final CardCollectionView cardlist, final int amount, final SpellAbility source,
final boolean destroy, final boolean isOptional) {
CardCollection remaining = new CardCollection(cardlist);
final CardCollection sacrificed = new CardCollection();
@@ -718,9 +718,9 @@ public class ComputerUtil {
final int considerSacThreshold = getAIPreferenceParameter(host, "CreatureEvalThreshold");
if ("OpponentOnly".equals(source.getParam("AILogic"))) {
- if(!source.getActivatingPlayer().isOpponentOf(ai)) {
- return sacrificed; // sacrifice none
- }
+ if(!source.getActivatingPlayer().isOpponentOf(ai)) {
+ return sacrificed; // sacrifice none
+ }
} else if ("DesecrationDemon".equals(source.getParam("AILogic"))) {
if (!SpecialCardAi.DesecrationDemon.considerSacrificingCreature(ai, source)) {
return sacrificed; // don't sacrifice unless in special conditions specified by DesecrationDemon AI
@@ -738,27 +738,27 @@ public class ComputerUtil {
boolean removedSelf = false;
if (isOptional && source.hasParam("Devour") || source.hasParam("Exploit") || considerSacLogic) {
- if (source.hasParam("Exploit")) {
- for (Trigger t : host.getTriggers()) {
- if (t.getMode() == TriggerType.Exploited) {
- final String execute = t.getParam("Execute");
- if (execute == null) {
- continue;
- }
- final SpellAbility exSA = AbilityFactory.getAbility(host.getSVar(execute), host);
+ if (source.hasParam("Exploit")) {
+ for (Trigger t : host.getTriggers()) {
+ if (t.getMode() == TriggerType.Exploited) {
+ final String execute = t.getParam("Execute");
+ if (execute == null) {
+ continue;
+ }
+ final SpellAbility exSA = AbilityFactory.getAbility(host.getSVar(execute), host);
- exSA.setActivatingPlayer(ai);
- exSA.setTrigger(true);
+ exSA.setActivatingPlayer(ai);
+ exSA.setTrigger(true);
- // Run non-mandatory trigger.
- // These checks only work if the Executing SpellAbility is an Ability_Sub.
- if ((exSA instanceof AbilitySub) && !SpellApiToAi.Converter.get(exSA.getApi()).doTriggerAI(ai, exSA, false)) {
- // AI would not run this trigger if given the chance
- return sacrificed;
- }
- }
- }
- }
+ // Run non-mandatory trigger.
+ // These checks only work if the Executing SpellAbility is an Ability_Sub.
+ if ((exSA instanceof AbilitySub) && !SpellApiToAi.Converter.get(exSA.getApi()).doTriggerAI(ai, exSA, false)) {
+ // AI would not run this trigger if given the chance
+ return sacrificed;
+ }
+ }
+ }
+ }
remaining = CardLists.filter(remaining, new Predicate() {
@Override
public boolean apply(final Card c) {
@@ -819,7 +819,7 @@ public class ComputerUtil {
if (ai.isOpponentOf(c.getController()))
return c;
}
-
+
if (destroy) {
final CardCollection indestructibles = CardLists.getKeyword(remaining, Keyword.INDESTRUCTIBLE);
if (!indestructibles.isEmpty()) {
@@ -909,7 +909,7 @@ public class ComputerUtil {
} catch (final Exception ex) {
throw new RuntimeException(TextUtil.concatNoSpace("There is an error in the card code for ", c.getName(), ":", ex.getMessage()), ex);
- }
+ }
}
}
@@ -958,16 +958,16 @@ public class ComputerUtil {
final Card card = sa.getHostCard();
if (card.hasSVar("PlayMain1")) {
- if (card.getSVar("PlayMain1").equals("ALWAYS") || sa.getPayCosts().hasNoManaCost()) {
- return true;
- } else if (card.getSVar("PlayMain1").equals("OPPONENTCREATURES")) {
- //Only play these main1 when the opponent has creatures (stealing and giving them haste)
- if (!ai.getOpponents().getCreaturesInPlay().isEmpty()) {
- return true;
- }
- } else if (!card.getController().getCreaturesInPlay().isEmpty()) {
- return true;
- }
+ if (card.getSVar("PlayMain1").equals("ALWAYS") || sa.getPayCosts().hasNoManaCost()) {
+ return true;
+ } else if (card.getSVar("PlayMain1").equals("OPPONENTCREATURES")) {
+ //Only play these main1 when the opponent has creatures (stealing and giving them haste)
+ if (!ai.getOpponents().getCreaturesInPlay().isEmpty()) {
+ return true;
+ }
+ } else if (!card.getController().getCreaturesInPlay().isEmpty()) {
+ return true;
+ }
}
// try not to cast Raid creatures in main 1 if an attack is likely
@@ -980,7 +980,7 @@ public class ComputerUtil {
}
if (card.getManaCost().isZero()) {
- return true;
+ return true;
}
if (card.hasKeyword(Keyword.RIOT) && ChooseGenericEffectAi.preferHasteForRiot(sa, ai)) {
@@ -1008,9 +1008,9 @@ public class ComputerUtil {
&& (card.hasKeyword(Keyword.HASTE) || ComputerUtil.hasACardGivingHaste(ai, true) || sa.isDash())) {
return true;
}
-
+
if (card.hasKeyword(Keyword.EXALTED)) {
- return true;
+ return true;
}
//cast equipments in Main1 when there are creatures to equip and no other unequipped equipment
@@ -1140,7 +1140,7 @@ public class ComputerUtil {
if (discard.hasSVar("DiscardMe")) {
return true;
}
-
+
final Game game = ai.getGame();
final CardCollection landsInPlay = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS);
final CardCollection landsInHand = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS);
@@ -1240,11 +1240,11 @@ public class ComputerUtil {
}
}
} // AntiBuffedBy
-
- if (sub != null) {
+
+ if (sub != null) {
return castSpellInMain1(ai, sub);
}
-
+
return false;
}
@@ -1253,7 +1253,7 @@ public class ComputerUtil {
int activations = sa.getActivationsThisTurn();
if (!sa.isIntrinsic()) {
- return MyRandom.getRandom().nextFloat() >= .95; // Abilities created by static abilities have no memory
+ return MyRandom.getRandom().nextFloat() >= .95; // Abilities created by static abilities have no memory
}
if (activations < 10) { //10 activations per turn should still be acceptable
@@ -1270,27 +1270,27 @@ public class ComputerUtil {
return false;
}
if (abCost.hasTapCost() && source.hasSVar("AITapDown")) {
- return true;
+ return true;
} else if (sa.hasParam("Planeswalker") && ai.getGame().getPhaseHandler().is(PhaseType.MAIN2)) {
- for (final CostPart part : abCost.getCostParts()) {
- if (part instanceof CostPutCounter) {
- return true;
- }
- }
+ for (final CostPart part : abCost.getCostParts()) {
+ if (part instanceof CostPutCounter) {
+ return true;
+ }
+ }
}
for (final CostPart part : abCost.getCostParts()) {
if (part instanceof CostSacrifice) {
final CostSacrifice sac = (CostSacrifice) part;
-
+
final String type = sac.getType();
-
+
if (type.equals("CARDNAME")) {
if (source.getSVar("SacMe").equals("6")) {
return true;
}
continue;
}
-
+
final CardCollection typeList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(","), source.getController(), source, sa);
for (Card c : typeList) {
@@ -1325,14 +1325,14 @@ public class ComputerUtil {
Map params = stAb.getMapParams();
if ("Continuous".equals(params.get("Mode")) && params.containsKey("AddKeyword")
&& params.get("AddKeyword").contains("Haste")) {
-
+
if (c.isEquipment() && c.getEquipping() == null) {
return true;
}
final String affected = params.get("Affected");
if (affected.contains("Creature.YouCtrl")
- || affected.contains("Other+YouCtrl")) {
+ || affected.contains("Other+YouCtrl")) {
return true;
} else if (affected.contains("Creature.PairedWith") && !c.isPaired()) {
return true;
@@ -1341,10 +1341,10 @@ public class ComputerUtil {
}
for (Trigger t : c.getTriggers()) {
- Map params = t.getMapParams();
+ Map params = t.getMapParams();
if (!"ChangesZone".equals(params.get("Mode"))
- || !"Battlefield".equals(params.get("Destination"))
- || !params.containsKey("ValidCard")) {
+ || !"Battlefield".equals(params.get("Destination"))
+ || !params.containsKey("ValidCard")) {
continue;
}
@@ -1360,10 +1360,10 @@ public class ComputerUtil {
}
}
}
-
+
all.addAll(ai.getCardsActivableInExternalZones(true));
all.addAll(ai.getCardsIn(ZoneType.Hand));
-
+
for (final Card c : all) {
for (final SpellAbility sa : c.getSpellAbilities()) {
if (sa.getApi() == ApiType.Pump && sa.hasParam("KW") && sa.getParam("KW").contains("Haste")) {
@@ -1398,10 +1398,10 @@ public class ComputerUtil {
public static boolean hasAFogEffect(final Player ai) {
final CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield));
-
+
all.addAll(ai.getCardsActivableInExternalZones(true));
all.addAll(ai.getCardsIn(ZoneType.Hand));
-
+
for (final Card c : all) {
for (final SpellAbility sa : c.getSpellAbilities()) {
if (sa.getApi() != ApiType.Fog) {
@@ -1431,7 +1431,7 @@ public class ComputerUtil {
final CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield));
all.addAll(ai.getCardsActivableInExternalZones(true));
all.addAll(CardLists.filter(ai.getCardsIn(ZoneType.Hand), Predicates.not(Presets.PERMANENTS)));
-
+
for (final Card c : all) {
for (final SpellAbility sa : c.getSpellAbilities()) {
if (sa.getApi() != ApiType.DealDamage) {
@@ -1490,7 +1490,7 @@ public class ComputerUtil {
/**
* Returns list of objects threatened by effects on the stack
- *
+ *
* @param ai
* calling player
* @param sa
@@ -1505,7 +1505,7 @@ public class ComputerUtil {
if (game.getStack().isEmpty()) {
return objects;
}
-
+
// check stack for something that will kill this
for (SpellAbilityStackInstance si : game.getStack()) {
// iterate from top of stack to find SpellAbility, including sub-abilities,
@@ -1523,8 +1523,8 @@ public class ComputerUtil {
if (top) {
break; // only evaluate top-stack
}
- }
-
+ }
+
return objects;
}
@@ -1536,14 +1536,14 @@ public class ComputerUtil {
int toughness = 0;
boolean grantIndestructible = false;
boolean grantShroud = false;
-
+
if (topStack == null) {
return objects;
}
-
+
final Card source = topStack.getHostCard();
final ApiType threatApi = topStack.getApi();
-
+
// Can only Predict things from AFs
if (threatApi == null) {
return threatened;
@@ -1557,7 +1557,7 @@ public class ComputerUtil {
CardCollectionView battleField = aiPlayer.getCardsIn(ZoneType.Battlefield);
objects = CardLists.getValidCards(battleField, topStack.getParam("ValidCards").split(","), source.getController(), source, topStack);
} else {
- return threatened;
+ return threatened;
}
} else {
objects = topStack.getTargets().getTargets();
@@ -1571,7 +1571,7 @@ public class ComputerUtil {
}
}
if (canBeTargeted.isEmpty()) {
- return threatened;
+ return threatened;
}
objects = canBeTargeted;
}
@@ -1640,7 +1640,7 @@ public class ComputerUtil {
}
// don't use it on creatures that can't be regenerated
- if ((saviourApi == ApiType.Regenerate || saviourApi == ApiType.RegenerateAll) &&
+ if ((saviourApi == ApiType.Regenerate || saviourApi == ApiType.RegenerateAll) &&
(!c.canBeShielded() || noRegen)) {
continue;
}
@@ -1652,14 +1652,14 @@ public class ComputerUtil {
continue;
}
}
-
+
if (saviourApi == ApiType.PutCounter || saviourApi == ApiType.PutCounterAll) {
boolean canSave = ComputerUtilCombat.predictDamageTo(c, dmg - toughness, source, false) < ComputerUtilCombat.getDamageToKill(c);
if (!canSave) {
continue;
}
}
-
+
// cannot protect against source
if (saviourApi == ApiType.Protection && (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue;
@@ -1670,7 +1670,7 @@ public class ComputerUtil {
if (saviourApi == ApiType.ChangeZone && (c.getOwner().isOpponentOf(aiPlayer) || c.isToken())) {
continue;
}
-
+
if (ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c)) {
threatened.add(c);
}
@@ -1689,7 +1689,7 @@ public class ComputerUtil {
}
// -Toughness Curse
else if ((threatApi == ApiType.Pump || threatApi == ApiType.PumpAll && topStack.isCurse())
- && (saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll
+ && (saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll
|| saviourApi == ApiType.Protection || saviourApi == ApiType.PutCounter || saviourApi == ApiType.PutCounterAll
|| saviourApi == null)) {
final int dmg = -AbilityUtils.calculateAmount(topStack.getHostCard(),
@@ -1702,7 +1702,7 @@ public class ComputerUtil {
if (!canRemove) {
continue;
}
-
+
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) {
final boolean cantSave = c.getNetToughness() + toughness <= dmg
|| (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && c.getShieldCount() == 0 && !grantIndestructible
@@ -1711,14 +1711,14 @@ public class ComputerUtil {
continue;
}
}
-
+
if (saviourApi == ApiType.PutCounter || saviourApi == ApiType.PutCounterAll) {
boolean canSave = c.getNetToughness() + toughness > dmg;
if (!canSave) {
continue;
}
}
-
+
if (saviourApi == ApiType.Protection) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue;
@@ -1812,9 +1812,9 @@ public class ComputerUtil {
}
}
//GainControl
- else if ((threatApi == ApiType.GainControl
- || (threatApi == ApiType.Attach && topStack.hasParam("AILogic") && topStack.getParam("AILogic").equals("GainControl") ))
- && (saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll
+ else if ((threatApi == ApiType.GainControl
+ || (threatApi == ApiType.Attach && topStack.hasParam("AILogic") && topStack.getParam("AILogic").equals("GainControl") ))
+ && (saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll
|| saviourApi == ApiType.Protection || saviourApi == null)) {
for (final Object o : objects) {
if (o instanceof Card) {
@@ -1931,7 +1931,7 @@ public class ComputerUtil {
public static int scoreHand(CardCollectionView handList, Player ai, int cardsToReturn) {
// TODO Improve hand scoring in relation to cards to return.
// If final hand size is 5, score a hand based on what that 5 would be.
- // Or if this is really really fast, determine what the 5 would be based on scoring
+ // Or if this is really really fast, determine what the 5 would be based on scoring
// All of the possibilities
final AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
@@ -2014,16 +2014,16 @@ public class ComputerUtil {
final CardCollectionView handList = ai.getCardsIn(ZoneType.Hand);
return scoreHand(handList, ai, cardsToReturn) <= 0;
}
-
+
public static CardCollection getPartialParisCandidates(Player ai) {
// Commander no longer uses partial paris.
final CardCollection candidates = new CardCollection();
final CardCollectionView handList = ai.getCardsIn(ZoneType.Hand);
-
+
final CardCollection lands = CardLists.getValidCards(handList, "Card.Land", ai, null);
final CardCollection nonLands = CardLists.getValidCards(handList, "Card.nonLand", ai, null);
CardLists.sortByCmcDesc(nonLands);
-
+
if (lands.size() >= 3 && lands.size() <= 4) {
return candidates;
}
@@ -2031,7 +2031,7 @@ public class ComputerUtil {
//Not enough lands!
int tgtCandidates = Math.max(Math.abs(lands.size()-nonLands.size()), 3);
System.out.println("Partial Paris: " + ai.getName() + " lacks lands, aiming to exile " + tgtCandidates + " cards.");
-
+
for (int i=0;i manaArts = Arrays.asList("Mox Pearl", "Mox Sapphire", "Mox Jet", "Mox Ruby", "Mox Emerald");
-
+
// evaluate creatures available in deck
CardCollectionView allCreatures = CardLists.filter(allCards, Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.isOwner(player)));
int numCards = allCreatures.size();
@@ -2185,7 +2185,7 @@ public class ComputerUtil {
}
Collections.sort(goodChoices, CardLists.TextLenComparator);
-
+
CardLists.sortByCmcDesc(goodChoices);
dChoices.add(goodChoices.get(0));
@@ -2196,7 +2196,7 @@ public class ComputerUtil {
if (p == aiChooser) { // ask that ai player what he would like to discard
final AiController aic = ((PlayerControllerAi)p.getController()).getAi();
return aic.getCardsToDiscard(min, max, validCards, sa);
- }
+ }
// no special options for human or remote friends
return getCardsToDiscardFromOpponent(aiChooser, p, sa, validCards, min, max);
}
@@ -2245,7 +2245,7 @@ public class ComputerUtil {
chosen = ComputerUtilCard.getMostProminentType(ai.getCardsIn(ZoneType.Battlefield), valid);
}
else if (logic.equals("MostProminentOppControls")) {
- CardCollection list = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents());
+ CardCollection list = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents());
chosen = ComputerUtilCard.getMostProminentType(list, valid);
if (!CardType.isACreatureType(chosen) || invalidTypes.contains(chosen)) {
list = CardLists.filterControlledBy(game.getCardsInGame(), ai.getOpponents());
@@ -2272,11 +2272,11 @@ public class ComputerUtil {
chosen = ComputerUtilCard.getMostProminentType(list, valid);
} else if (logic.equals("MostNeededType")) {
- // Choose a type that is in the deck, but not in hand or on the battlefield
+ // Choose a type that is in the deck, but not in hand or on the battlefield
final List basics = new ArrayList<>(CardType.Constant.BASIC_TYPES);
CardCollectionView presentCards = CardCollection.combine(ai.getCardsIn(ZoneType.Battlefield), ai.getCardsIn(ZoneType.Hand));
CardCollectionView possibleCards = ai.getAllCards();
-
+
for (String b : basics) {
if (!Iterables.any(presentCards, CardPredicates.isType(b)) && Iterables.any(possibleCards, CardPredicates.isType(b))) {
chosen = b;
@@ -2333,6 +2333,8 @@ public class ComputerUtil {
boolean opponent = controller.isOpponentOf(ai);
+ final CounterType p1p1Type = CounterType.get(CounterEnumType.P1P1);
+
if (!sa.hasParam("AILogic")) {
return Aggregates.random(options);
}
@@ -2386,7 +2388,7 @@ public class ComputerUtil {
}
}
// is it can't receive counters, choose +1/+1 ones
- if (!source.canReceiveCounters(CounterType.P1P1)) {
+ if (!source.canReceiveCounters(p1p1Type)) {
return opponent ? "Feather" : "Quill";
}
// if source is not on the battlefield anymore, choose +1/+1
@@ -2418,7 +2420,7 @@ public class ComputerUtil {
Card token = TokenAi.spawnToken(controller, saToken);
// is it can't receive counters, choose +1/+1 ones
- if (!source.canReceiveCounters(CounterType.P1P1)) {
+ if (!source.canReceiveCounters(p1p1Type)) {
return opponent ? "Strength" : "Numbers";
}
@@ -2441,11 +2443,11 @@ public class ComputerUtil {
Card sourceNumbers = CardUtil.getLKICopy(source);
Card sourceStrength = CardUtil.getLKICopy(source);
- sourceNumbers.setCounters(CounterType.P1P1, sourceNumbers.getCounters(CounterType.P1P1) + numStrength);
+ sourceNumbers.setCounters(p1p1Type, sourceNumbers.getCounters(p1p1Type) + numStrength);
sourceNumbers.setZone(source.getZone());
- sourceStrength.setCounters(CounterType.P1P1,
- sourceStrength.getCounters(CounterType.P1P1) + numStrength + 1);
+ sourceStrength.setCounters(p1p1Type,
+ sourceStrength.getCounters(p1p1Type) + numStrength + 1);
sourceStrength.setZone(source.getZone());
int scoreStrength = ComputerUtilCard.evaluateCreature(sourceStrength) + tokenScore * numNumbers;
@@ -2467,7 +2469,7 @@ public class ComputerUtil {
}
// is it can't receive counters, choose +1/+1 ones
- if (!source.canReceiveCounters(CounterType.P1P1)) {
+ if (!source.canReceiveCounters(p1p1Type)) {
return opponent ? "Sprout" : "Harvest";
}
@@ -2544,11 +2546,11 @@ public class ComputerUtil {
});
return ComputerUtilCard.getBestCreatureAI(killables);
}
-
+
public static int predictDamageFromSpell(final SpellAbility sa, final Player targetPlayer) {
int damage = -1; // returns -1 if the spell does not deal damage
final Card card = sa.getHostCard();
-
+
SpellAbility ab = sa;
while (ab != null) {
if (ab.getApi() == ApiType.DealDamage) {
@@ -2567,12 +2569,12 @@ public class ComputerUtil {
}
ab = ab.getSubAbility();
}
-
+
return damage;
}
-
+
public static int getDamageForPlaying(final Player player, final SpellAbility sa) {
-
+
// check for bad spell cast triggers
int damage = 0;
final Game game = player.getGame();
@@ -2602,7 +2604,7 @@ public class ComputerUtil {
continue;
}
}
-
+
if (trigParams.containsKey("ValidActivatingPlayer")) {
if (!player.isValid(trigParams.get("ValidActivatingPlayer"), source.getController(), source, sa)) {
continue;
@@ -2662,7 +2664,7 @@ public class ComputerUtil {
}
}
}
-
+
return damage;
}
@@ -2685,7 +2687,7 @@ public class ComputerUtil {
if (!trigger.requirementsCheck(game)) {
continue;
}
- if (trigParams.containsKey("CheckOnTriggeredCard")
+ if (trigParams.containsKey("CheckOnTriggeredCard")
&& AbilityUtils.getDefinedCards(permanent, source.getSVar(trigParams.get("CheckOnTriggeredCard").split(" ")[0]), null).isEmpty()) {
continue;
}
@@ -2759,27 +2761,27 @@ public class ComputerUtil {
}
public static boolean isNegativeCounter(CounterType type, Card c) {
- return type == CounterType.AGE || type == CounterType.BRIBERY || type == CounterType.DOOM
- || type == CounterType.M1M1 || type == CounterType.M0M2 || type == CounterType.M0M1
- || type == CounterType.M1M0 || type == CounterType.M2M1 || type == CounterType.M2M2
+ return type.is(CounterEnumType.AGE) || type.is(CounterEnumType.BRIBERY) || type.is(CounterEnumType.DOOM)
+ || type.is(CounterEnumType.M1M1) || type.is(CounterEnumType.M0M2) || type.is(CounterEnumType.M0M1)
+ || type.is(CounterEnumType.M1M0) || type.is(CounterEnumType.M2M1) || type.is(CounterEnumType.M2M2)
// Blaze only hurts Lands
- || (type == CounterType.BLAZE && c.isLand())
+ || (type.is(CounterEnumType.BLAZE) && c.isLand())
// Iceberg does use Ice as Storage
- || (type == CounterType.ICE && !"Iceberg".equals(c.getName()))
+ || (type.is(CounterEnumType.ICE) && !"Iceberg".equals(c.getName()))
// some lands does use Depletion as Storage Counter
- || (type == CounterType.DEPLETION && c.hasKeyword("CARDNAME doesn't untap during your untap step."))
+ || (type.is(CounterEnumType.DEPLETION) && c.hasKeyword("CARDNAME doesn't untap during your untap step."))
// treat Time Counters on suspended Cards as Bad,
// and also on Chronozoa
- || (type == CounterType.TIME && (!c.isInPlay() || "Chronozoa".equals(c.getName())))
- || type == CounterType.GOLD || type == CounterType.MUSIC || type == CounterType.PUPA
- || type == CounterType.PARALYZATION || type == CounterType.SHELL || type == CounterType.SLEEP
- || type == CounterType.SLUMBER || type == CounterType.SLEIGHT || type == CounterType.WAGE;
+ || (type.is(CounterEnumType.TIME) && (!c.isInPlay() || "Chronozoa".equals(c.getName())))
+ || type.is(CounterEnumType.GOLD) || type.is(CounterEnumType.MUSIC) || type.is(CounterEnumType.PUPA)
+ || type.is(CounterEnumType.PARALYZATION) || type.is(CounterEnumType.SHELL) || type.is(CounterEnumType.SLEEP)
+ || type.is(CounterEnumType.SLUMBER) || type.is(CounterEnumType.SLEIGHT) || type.is(CounterEnumType.WAGE);
}
// this countertypes has no effect
public static boolean isUselessCounter(CounterType type) {
- return type == CounterType.AWAKENING || type == CounterType.MANIFESTATION || type == CounterType.PETRIFICATION
- || type == CounterType.TRAINING;
+ return type.is(CounterEnumType.AWAKENING) || type.is(CounterEnumType.MANIFESTATION) || type.is(CounterEnumType.PETRIFICATION)
+ || type.is(CounterEnumType.TRAINING);
}
public static Player evaluateBoardPosition(final List listToEvaluate) {
@@ -2891,7 +2893,7 @@ public class ComputerUtil {
return false;
}
-
+
public static boolean targetPlayableSpellCard(final Player ai, CardCollection options, final SpellAbility sa, final boolean withoutPayingManaCost) {
// determine and target a card with a SA that the AI can afford and will play
AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java
index ca62736912f..3009dca985a 100644
--- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java
+++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java
@@ -1422,8 +1422,8 @@ public class ComputerUtilCard {
if (combat.isAttacking(c) && opp.getLife() > 0) {
int dmg = ComputerUtilCombat.damageIfUnblocked(c, opp, combat, true);
int pumpedDmg = ComputerUtilCombat.damageIfUnblocked(pumped, opp, pumpedCombat, true);
- int poisonOrig = opp.canReceiveCounters(CounterType.POISON) ? ComputerUtilCombat.poisonIfUnblocked(c, ai) : 0;
- int poisonPumped = opp.canReceiveCounters(CounterType.POISON) ? ComputerUtilCombat.poisonIfUnblocked(pumped, ai) : 0;
+ int poisonOrig = opp.canReceiveCounters(CounterEnumType.POISON) ? ComputerUtilCombat.poisonIfUnblocked(c, ai) : 0;
+ int poisonPumped = opp.canReceiveCounters(CounterEnumType.POISON) ? ComputerUtilCombat.poisonIfUnblocked(pumped, ai) : 0;
// predict Infect
if (pumpedDmg == 0 && c.hasKeyword(Keyword.INFECT)) {
@@ -1446,7 +1446,7 @@ public class ComputerUtilCard {
}
if (pumpedDmg > dmg) {
if ((!c.hasKeyword(Keyword.INFECT) && pumpedDmg >= opp.getLife())
- || (c.hasKeyword(Keyword.INFECT) && opp.canReceiveCounters(CounterType.POISON) && pumpedDmg >= opp.getPoisonCounters())
+ || (c.hasKeyword(Keyword.INFECT) && opp.canReceiveCounters(CounterEnumType.POISON) && pumpedDmg >= opp.getPoisonCounters())
|| ("PumpForTrample".equals(sa.getParam("AILogic")))) {
return true;
}
@@ -1765,10 +1765,10 @@ public class ComputerUtilCard {
}
public static boolean hasActiveUndyingOrPersist(final Card c) {
- if (c.hasKeyword(Keyword.UNDYING) && c.getCounters(CounterType.P1P1) == 0) {
+ if (c.hasKeyword(Keyword.UNDYING) && c.getCounters(CounterEnumType.P1P1) == 0) {
return true;
}
- if (c.hasKeyword(Keyword.PERSIST) && c.getCounters(CounterType.M1M1) == 0) {
+ if (c.hasKeyword(Keyword.PERSIST) && c.getCounters(CounterEnumType.M1M1) == 0) {
return true;
}
return false;
diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java
index 0b2ac9d2f5e..baffff9cc5a 100644
--- a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java
+++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java
@@ -328,7 +328,7 @@ public class ComputerUtilCombat {
public static int resultingPoison(final Player ai, final Combat combat) {
// ai can't get poision counters, so the value can't change
- if (!ai.canReceiveCounters(CounterType.POISON)) {
+ if (!ai.canReceiveCounters(CounterEnumType.POISON)) {
return ai.getPoisonCounters();
}
@@ -931,7 +931,7 @@ public class ComputerUtilCombat {
if (dealsFirstStrikeDamage(attacker, withoutAbilities, null)
&& (attacker.hasKeyword(Keyword.WITHER) || attacker.hasKeyword(Keyword.INFECT))
&& !dealsFirstStrikeDamage(blocker, withoutAbilities, null)
- && !blocker.canReceiveCounters(CounterType.M1M1)) {
+ && !blocker.canReceiveCounters(CounterEnumType.M1M1)) {
power -= attacker.getNetCombatDamage();
}
@@ -1058,7 +1058,7 @@ public class ComputerUtilCombat {
continue;
}
- if (ability.hasParam("Adapt") && blocker.getCounters(CounterType.P1P1) > 0) {
+ if (ability.hasParam("Adapt") && blocker.getCounters(CounterEnumType.P1P1) > 0) {
continue;
}
@@ -1234,7 +1234,7 @@ public class ComputerUtilCombat {
continue;
}
- if (ability.hasParam("Adapt") && blocker.getCounters(CounterType.P1P1) > 0) {
+ if (ability.hasParam("Adapt") && blocker.getCounters(CounterEnumType.P1P1) > 0) {
continue;
}
@@ -1296,7 +1296,7 @@ public class ComputerUtilCombat {
if (ComputerUtilCombat.dealsFirstStrikeDamage(blocker, withoutAbilities, combat)
&& (blocker.hasKeyword(Keyword.WITHER) || blocker.hasKeyword(Keyword.INFECT))
&& !ComputerUtilCombat.dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
- && !attacker.canReceiveCounters(CounterType.M1M1)) {
+ && !attacker.canReceiveCounters(CounterEnumType.M1M1)) {
power -= blocker.getNetCombatDamage();
}
theTriggers.addAll(blocker.getTriggers());
@@ -1456,7 +1456,7 @@ public class ComputerUtilCombat {
continue;
}
- if (ability.hasParam("Adapt") && attacker.getCounters(CounterType.P1P1) > 0) {
+ if (ability.hasParam("Adapt") && attacker.getCounters(CounterEnumType.P1P1) > 0) {
continue;
}
@@ -1693,7 +1693,7 @@ public class ComputerUtilCombat {
continue;
}
- if (ability.hasParam("Adapt") && attacker.getCounters(CounterType.P1P1) > 0) {
+ if (ability.hasParam("Adapt") && attacker.getCounters(CounterEnumType.P1P1) > 0) {
continue;
}
@@ -1848,10 +1848,10 @@ public class ComputerUtilCombat {
if (((attacker.hasKeyword(Keyword.INDESTRUCTIBLE) || (ComputerUtil.canRegenerate(ai, attacker) && !withoutAbilities))
&& !(blocker.hasKeyword(Keyword.WITHER) || blocker.hasKeyword(Keyword.INFECT)))
- || (attacker.hasKeyword(Keyword.PERSIST) && !attacker.canReceiveCounters(CounterType.M1M1) && (attacker
- .getCounters(CounterType.M1M1) == 0))
- || (attacker.hasKeyword(Keyword.UNDYING) && !attacker.canReceiveCounters(CounterType.P1P1) && (attacker
- .getCounters(CounterType.P1P1) == 0))) {
+ || (attacker.hasKeyword(Keyword.PERSIST) && !attacker.canReceiveCounters(CounterEnumType.M1M1) && (attacker
+ .getCounters(CounterEnumType.M1M1) == 0))
+ || (attacker.hasKeyword(Keyword.UNDYING) && !attacker.canReceiveCounters(CounterEnumType.P1P1) && (attacker
+ .getCounters(CounterEnumType.P1P1) == 0))) {
return false;
}
@@ -2080,10 +2080,10 @@ public class ComputerUtilCombat {
if (((blocker.hasKeyword(Keyword.INDESTRUCTIBLE) || (ComputerUtil.canRegenerate(ai, blocker) && !withoutAbilities)) && !(attacker
.hasKeyword(Keyword.WITHER) || attacker.hasKeyword(Keyword.INFECT)))
- || (blocker.hasKeyword(Keyword.PERSIST) && !blocker.canReceiveCounters(CounterType.M1M1) && (blocker
- .getCounters(CounterType.M1M1) == 0))
- || (blocker.hasKeyword(Keyword.UNDYING) && !blocker.canReceiveCounters(CounterType.P1P1) && (blocker
- .getCounters(CounterType.P1P1) == 0))) {
+ || (blocker.hasKeyword(Keyword.PERSIST) && !blocker.canReceiveCounters(CounterEnumType.M1M1) && (blocker
+ .getCounters(CounterEnumType.M1M1) == 0))
+ || (blocker.hasKeyword(Keyword.UNDYING) && !blocker.canReceiveCounters(CounterEnumType.P1P1) && (blocker
+ .getCounters(CounterEnumType.P1P1) == 0))) {
return false;
}
diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java
index 89b6ddf4436..78de56e6988 100644
--- a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java
+++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java
@@ -45,7 +45,7 @@ public class ComputerUtilCost {
final CostPutCounter addCounter = (CostPutCounter) part;
final CounterType type = addCounter.getCounter();
- if (type.equals(CounterType.M1M1)) {
+ if (type.equals(CounterEnumType.M1M1)) {
return false;
}
}
@@ -75,7 +75,7 @@ public class ComputerUtilCost {
final CounterType type = remCounter.counter;
if (!part.payCostFromSource()) {
- if (CounterType.P1P1.equals(type)) {
+ if (CounterEnumType.P1P1.equals(type)) {
return false;
}
continue;
@@ -97,7 +97,7 @@ public class ComputerUtilCost {
// check the sa what the PaymentDecision is.
// ignore Loyality abilities with Zero as Cost
- if (sa != null && !CounterType.LOYALTY.equals(type)) {
+ if (sa != null && !CounterEnumType.LOYALTY.equals(type)) {
final AiCostDecision decision = new AiCostDecision(sa.getActivatingPlayer(), sa);
PaymentDecision pay = decision.visit(remCounter);
if (pay == null || pay.c <= 0) {
@@ -106,7 +106,7 @@ public class ComputerUtilCost {
}
//don't kill the creature
- if (CounterType.P1P1.equals(type) && source.getLethalDamage() <= 1
+ if (CounterEnumType.P1P1.equals(type) && source.getLethalDamage() <= 1
&& !source.hasKeyword(Keyword.UNDYING)) {
return false;
}
diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java
index 28e5eaf9835..f90a554dbc6 100644
--- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java
+++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java
@@ -371,7 +371,7 @@ public class ComputerUtilMana {
adjustManaCostToAvoidNegEffects(cost, sa.getHostCard(), ai);
List manaSpentToPay = test ? new ArrayList<>() : sa.getPayingMana();
boolean purePhyrexian = cost.containsOnlyPhyrexianMana();
- int testEnergyPool = ai.getCounters(CounterType.ENERGY);
+ int testEnergyPool = ai.getCounters(CounterEnumType.ENERGY);
List paymentList = Lists.newArrayList();
diff --git a/forge-ai/src/main/java/forge/ai/CreatureEvaluator.java b/forge-ai/src/main/java/forge/ai/CreatureEvaluator.java
index de339fad5c4..917012b236d 100644
--- a/forge-ai/src/main/java/forge/ai/CreatureEvaluator.java
+++ b/forge-ai/src/main/java/forge/ai/CreatureEvaluator.java
@@ -5,7 +5,7 @@ import com.google.common.base.Function;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.cost.CostPayEnergy;
import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface;
@@ -246,7 +246,7 @@ public class CreatureEvaluator implements Function {
// Electrostatic Pummeler, can be expanded for similar cards
int initPower = getEffectivePower(sa.getHostCard());
int pumpedPower = initPower;
- int energy = sa.getHostCard().getController().getCounters(CounterType.ENERGY);
+ int energy = sa.getHostCard().getController().getCounters(CounterEnumType.ENERGY);
if (energy > 0) {
int numActivations = energy / 3;
for (int i = 0; i < numActivations; i++) {
diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java
index baadb5e76c9..600bbe41d7d 100644
--- a/forge-ai/src/main/java/forge/ai/GameState.java
+++ b/forge-ai/src/main/java/forge/ai/GameState.java
@@ -1091,11 +1091,11 @@ public abstract class GameState {
}
private void applyCountersToGameEntity(GameEntity entity, String counterString) {
- entity.setCounters(Maps.newEnumMap(CounterType.class));
+ entity.setCounters(Maps.newHashMap());
String[] allCounterStrings = counterString.split(",");
for (final String counterPair : allCounterStrings) {
String[] pair = counterPair.split("=", 2);
- entity.addCounter(CounterType.valueOf(pair[0]), Integer.parseInt(pair[1]), null, false, false, null);
+ entity.addCounter(CounterType.getType(pair[0]), Integer.parseInt(pair[1]), null, false, false, null);
}
}
@@ -1137,7 +1137,7 @@ public abstract class GameState {
Map counters = c.getCounters();
// Note: Not clearCounters() since we want to keep the counters
// var as-is.
- c.setCounters(Maps.newEnumMap(CounterType.class));
+ c.setCounters(Maps.newHashMap());
if (c.isAura()) {
// dummy "enchanting" to indicate that the card will be force-attached elsewhere
// (will be overridden later, so the actual value shouldn't matter)
diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java
index 9c5d555a2e2..924cdcd9d80 100644
--- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java
+++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java
@@ -145,12 +145,12 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
- public CardCollectionView chooseCardsForEffect(CardCollectionView sourceList, SpellAbility sa, String title, int min, int max, boolean isOptional) {
- return brains.chooseCardsForEffect(sourceList, sa, min, max, isOptional);
+ public CardCollectionView chooseCardsForEffect(CardCollectionView sourceList, SpellAbility sa, String title, int min, int max, boolean isOptional, Map params) {
+ return brains.chooseCardsForEffect(sourceList, sa, min, max, isOptional, params);
}
@Override
- public T chooseSingleEntityForEffect(FCollectionView optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer) {
+ public T chooseSingleEntityForEffect(FCollectionView optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player targetedPlayer, Map params) {
if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
}
@@ -158,13 +158,13 @@ public class PlayerControllerAi extends PlayerController {
if (null == api) {
throw new InvalidParameterException("SA is not api-based, this is not supported yet");
}
- return SpellApiToAi.Converter.get(api).chooseSingleEntity(player, sa, (FCollection)optionList, isOptional, targetedPlayer);
+ return SpellApiToAi.Converter.get(api).chooseSingleEntity(player, sa, (FCollection)optionList, isOptional, targetedPlayer, params);
}
@Override
public List chooseEntitiesForEffect(
FCollectionView optionList, int min, int max, DelayedReveal delayedReveal, SpellAbility sa, String title,
- Player targetedPlayer) {
+ Player targetedPlayer, Map params) {
if (delayedReveal != null) {
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
}
@@ -172,7 +172,7 @@ public class PlayerControllerAi extends PlayerController {
List selecteds = new ArrayList<>();
T selected;
do {
- selected = chooseSingleEntityForEffect(remaining, null, sa, title, selecteds.size()>=min, targetedPlayer);
+ selected = chooseSingleEntityForEffect(remaining, null, sa, title, selecteds.size()>=min, targetedPlayer, params);
if ( selected != null ) {
remaining.remove(selected);
selecteds.add(selected);
@@ -182,7 +182,23 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
- public SpellAbility chooseSingleSpellForEffect(java.util.List spells, SpellAbility sa, String title,
+ public List chooseSpellAbilitiesForEffect(List spells, SpellAbility sa, String title,
+ int num, Map params) {
+ List remaining = Lists.newArrayList(spells);
+ List selecteds = Lists.newArrayList();
+ SpellAbility selected;
+ do {
+ selected = chooseSingleSpellForEffect(remaining, sa, title, params);
+ if ( selected != null ) {
+ remaining.remove(selected);
+ selecteds.add(selected);
+ }
+ } while ( (selected != null ) && (selecteds.size() < num) );
+ return selecteds;
+ }
+
+ @Override
+ public SpellAbility chooseSingleSpellForEffect(List spells, SpellAbility sa, String title,
Map params) {
ApiType api = sa.getApi();
if (null == api) {
diff --git a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java
index f5f4435c491..5ed62460108 100644
--- a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java
+++ b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java
@@ -327,7 +327,7 @@ public class SpecialCardAi {
boolean canTrample = source.hasKeyword(Keyword.TRAMPLE);
if (!isBlocking && combat.getDefenderByAttacker(source) instanceof Card) {
- int loyalty = combat.getDefenderByAttacker(source).getCounters(CounterType.LOYALTY);
+ int loyalty = combat.getDefenderByAttacker(source).getCounters(CounterEnumType.LOYALTY);
int totalDamageToPW = 0;
for (Card atk : (combat.getAttackersOf(combat.getDefenderByAttacker(source)))) {
if (combat.isUnblocked(atk)) {
@@ -407,7 +407,7 @@ public class SpecialCardAi {
}
public static Pair getPumpedPT(Player ai, int power, int toughness) {
- int energy = ai.getCounters(CounterType.ENERGY);
+ int energy = ai.getCounters(CounterEnumType.ENERGY);
if (energy > 0) {
int numActivations = energy / 3;
for (int i = 0; i < numActivations; i++) {
@@ -708,7 +708,7 @@ public class SpecialCardAi {
// if there's another reanimator card currently suspended, don't cast a new one until the previous
// one resolves, otherwise the reanimation attempt will be ruined (e.g. Living End)
for (Card ex : ai.getCardsIn(ZoneType.Exile)) {
- if (ex.hasSVar("IsReanimatorCard") && ex.getCounters(CounterType.TIME) > 0) {
+ if (ex.hasSVar("IsReanimatorCard") && ex.getCounters(CounterEnumType.TIME) > 0) {
return false;
}
}
@@ -767,7 +767,7 @@ public class SpecialCardAi {
Player controller = c.getController();
boolean wasCaged = false;
for (Card caged : CardLists.filter(controller.getCardsIn(ZoneType.Exile),
- CardPredicates.hasCounter(CounterType.CAGE))) {
+ CardPredicates.hasCounter(CounterEnumType.CAGE))) {
if (c.getName().equals(caged.getName())) {
wasCaged = true;
break;
@@ -1073,7 +1073,7 @@ public class SpecialCardAi {
// Sarkhan the Mad
public static class SarkhanTheMad {
public static boolean considerDig(final Player ai, final SpellAbility sa) {
- return sa.getHostCard().getCounters(CounterType.LOYALTY) == 1;
+ return sa.getHostCard().getCounters(CounterEnumType.LOYALTY) == 1;
}
public static boolean considerMakeDragon(final Player ai, final SpellAbility sa) {
@@ -1109,7 +1109,7 @@ public class SpecialCardAi {
// Sorin, Vengeful Bloodlord
public static class SorinVengefulBloodlord {
public static boolean consider(final Player ai, final SpellAbility sa) {
- int loyalty = sa.getHostCard().getCounters(CounterType.LOYALTY);
+ int loyalty = sa.getHostCard().getCounters(CounterEnumType.LOYALTY);
CardCollection creaturesToGet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard),
Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.lessCMC(loyalty - 1), new Predicate() {
@Override
@@ -1365,7 +1365,7 @@ public class SpecialCardAi {
Card source = sa.getHostCard();
Game game = source.getGame();
- final int loyalty = source.getCounters(CounterType.LOYALTY);
+ final int loyalty = source.getCounters(CounterEnumType.LOYALTY);
int x = -1, best = 0;
Card single = null;
for (int i = 0; i < loyalty; i++) {
diff --git a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java
index 61d161caace..665e8881f4f 100644
--- a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java
+++ b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java
@@ -307,7 +307,7 @@ public abstract class SpellAbilityAi {
}
@SuppressWarnings("unchecked")
- public T chooseSingleEntity(Player ai, SpellAbility sa, Collection options, boolean isOptional, Player targetedPlayer) {
+ public T chooseSingleEntity(Player ai, SpellAbility sa, Collection options, boolean isOptional, Player targetedPlayer, Map params) {
boolean hasPlayer = false;
boolean hasCard = false;
boolean hasPlaneswalker = false;
@@ -324,11 +324,11 @@ public abstract class SpellAbilityAi {
}
if (hasPlayer && hasPlaneswalker) {
- return (T) chooseSinglePlayerOrPlaneswalker(ai, sa, (Collection) options);
+ return (T) chooseSinglePlayerOrPlaneswalker(ai, sa, (Collection) options, params);
} else if (hasCard) {
- return (T) chooseSingleCard(ai, sa, (Collection) options, isOptional, targetedPlayer);
+ return (T) chooseSingleCard(ai, sa, (Collection) options, isOptional, targetedPlayer, params);
} else if (hasPlayer) {
- return (T) chooseSinglePlayer(ai, sa, (Collection) options);
+ return (T) chooseSinglePlayer(ai, sa, (Collection) options, params);
}
return null;
@@ -339,17 +339,17 @@ public abstract class SpellAbilityAi {
return spells.get(0);
}
- protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSingleCard is used by " + sa.getHostCard().getName() + " for " + this.getClass().getName() + ". Consider declaring an overloaded method");
return Iterables.getFirst(options, null);
}
- protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options) {
+ protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSinglePlayer is used by " + sa.getHostCard().getName() + " for " + this.getClass().getName() + ". Consider declaring an overloaded method");
return Iterables.getFirst(options, null);
}
- protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options) {
+ protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSinglePlayerOrPlaneswalker is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
return Iterables.getFirst(options, null);
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/AmassAi.java b/forge-ai/src/main/java/forge/ai/ability/AmassAi.java
index 0fd0319c3ef..ab54f83224d 100644
--- a/forge-ai/src/main/java/forge/ai/ability/AmassAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/AmassAi.java
@@ -1,5 +1,7 @@
package forge.ai.ability;
+import java.util.Map;
+
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
@@ -23,7 +25,7 @@ public class AmassAi extends SpellAbilityAi {
final Game game = ai.getGame();
if (!aiArmies.isEmpty()) {
- return CardLists.count(aiArmies, CardPredicates.canReceiveCounters(CounterType.P1P1)) > 0;
+ return CardLists.count(aiArmies, CardPredicates.canReceiveCounters(CounterEnumType.P1P1)) > 0;
} else {
final String tokenScript = "b_0_0_zombie_army";
final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa);
@@ -44,8 +46,8 @@ public class AmassAi extends SpellAbilityAi {
CardCollection preList = new CardCollection(token);
game.getAction().checkStaticAbilities(false, Sets.newHashSet(token), preList);
- if (token.canReceiveCounters(CounterType.P1P1)) {
- token.setCounters(CounterType.P1P1, amount);
+ if (token.canReceiveCounters(CounterEnumType.P1P1)) {
+ token.setCounters(CounterEnumType.P1P1, amount);
}
if (token.isCreature() && token.getNetToughness() < 1) {
@@ -86,8 +88,8 @@ public class AmassAi extends SpellAbilityAi {
}
@Override
- protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
- Iterable better = CardLists.filter(options, CardPredicates.canReceiveCounters(CounterType.P1P1));
+ protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
+ Iterable better = CardLists.filter(options, CardPredicates.canReceiveCounters(CounterEnumType.P1P1));
if (Iterables.isEmpty(better)) {
better = options;
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java
index 1bc5028175f..37602483b41 100644
--- a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java
@@ -1704,12 +1704,12 @@ public class AttachAi extends SpellAbilityAi {
}
@Override
- protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
return attachToCardAIPreferences(ai, sa, true);
}
@Override
- protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options) {
+ protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) {
return attachToPlayerAIPreferences(ai, sa, true);
}
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/BondAi.java b/forge-ai/src/main/java/forge/ai/ability/BondAi.java
index 03c950d3f2e..8619983df69 100644
--- a/forge-ai/src/main/java/forge/ai/ability/BondAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/BondAi.java
@@ -17,6 +17,8 @@
*/
package forge.ai.ability;
+import java.util.Map;
+
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
@@ -50,7 +52,7 @@ public final class BondAi extends SpellAbilityAi {
@Override
- protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
return ComputerUtilCard.getBestCreatureAI(options);
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeCombatantsAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeCombatantsAi.java
index 3e4228c09bd..1187dc81cdc 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ChangeCombatantsAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ChangeCombatantsAi.java
@@ -8,6 +8,7 @@ import forge.game.player.PlayerPredicates;
import forge.game.spellability.SpellAbility;
import java.util.Collection;
+import java.util.Map;
public class ChangeCombatantsAi extends SpellAbilityAi {
/* (non-Javadoc)
@@ -45,7 +46,7 @@ public class ChangeCombatantsAi extends SpellAbilityAi {
}
@Override
- public T chooseSingleEntity(Player ai, SpellAbility sa, Collection options, boolean isOptional, Player targetedPlayer) {
+ public T chooseSingleEntity(Player ai, SpellAbility sa, Collection options, boolean isOptional, Player targetedPlayer, Map params) {
PlayerCollection targetableOpps = new PlayerCollection();
for (GameEntity p : options) {
if (p instanceof Player && !p.equals(sa.getHostCard().getController())) {
diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java
index 160066bea92..2894660612a 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java
@@ -142,7 +142,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
*
* @param sa
* a {@link forge.game.spellability.SpellAbility} object.
- *
+ *
* @return a boolean.
*/
@Override
@@ -170,7 +170,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
* a {@link forge.game.spellability.SpellAbility} object.
* @param mandatory
* a boolean.
- *
+ *
* @return a boolean.
*/
@Override
@@ -370,10 +370,10 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (!activateForCost && list.isEmpty()) {
return false;
}
- if ("Atarka's Command".equals(sourceName)
- && (list.size() < 2 || ai.getLandsPlayedThisTurn() < 1)) {
- // be strict on playing lands off charms
- return false;
+ if ("Atarka's Command".equals(sourceName)
+ && (list.size() < 2 || ai.getLandsPlayedThisTurn() < 1)) {
+ // be strict on playing lands off charms
+ return false;
}
String num = sa.getParam("ChangeNum");
@@ -385,7 +385,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
source.setSVar("PayX", Integer.toString(xPay));
}
}
-
+
if (sourceName.equals("Temur Sabertooth")) {
// activated bounce + pump
if (ComputerUtilCard.shouldPumpCard(ai, sa.getSubAbility(), source, 0, 0, Arrays.asList("Indestructible")) ||
@@ -400,9 +400,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
}
-
+
if (ComputerUtil.playImmediately(ai, sa)) {
- return true;
+ return true;
}
// don't use fetching to top of library/graveyard before main2
@@ -418,9 +418,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
if (ComputerUtil.waitForBlocking(sa)) {
- return false;
+ return false;
}
-
+
final AbilitySub subAb = sa.getSubAbility();
return subAb == null || SpellApiToAi.Converter.get(subAb.getApi()).chkDrawbackWithSubs(ai, subAb);
}
@@ -551,7 +551,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
* basicManaFixing.
*
* @param ai
- *
+ *
* @param list
* a List object.
* @return a {@link forge.game.card.Card} object.
@@ -584,7 +584,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (minType != null) {
result = CardLists.getType(list, minType);
}
-
+
// pick dual lands if available
if (Iterables.any(result, Predicates.not(CardPredicates.Presets.BASIC_LANDS))) {
result = CardLists.filter(result, Predicates.not(CardPredicates.Presets.BASIC_LANDS));
@@ -597,7 +597,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
*
* areAllBasics.
*
- *
+ *
* @param types
* a {@link java.lang.String} object.
* @return a boolean.
@@ -617,8 +617,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
* @return Card
*/
private static Card chooseCreature(final Player ai, CardCollection list) {
- // Creating a new combat for testing purposes.
- final Player opponent = ai.getWeakestOpponent();
+ // Creating a new combat for testing purposes.
+ final Player opponent = ai.getWeakestOpponent();
Combat combat = new Combat(opponent);
for (Card att : opponent.getCreaturesInPlay()) {
combat.addAttacker(att, ai);
@@ -742,7 +742,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see
* forge.ai.SpellAbilityAi#checkPhaseRestrictions(forge.game.player.Player,
* forge.game.spellability.SpellAbility, forge.game.phase.PhaseHandler)
@@ -781,7 +781,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
return false;
}
}
-
+
//don't unearth after attacking is possible
if (sa.hasParam("Unearth") && ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return false;
@@ -895,7 +895,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (list.size() < tgt.getMinTargets(sa.getHostCard(), sa)) {
return false;
}
-
+
immediately |= ComputerUtil.playImmediately(ai, sa);
// Narrow down the list:
@@ -926,7 +926,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
CardCollection blockers = currCombat.getBlockers(attacker);
// Save my attacker by bouncing a blocker
if (attacker.getController().equals(ai) && attacker.getShieldCount() == 0
- && ComputerUtilCombat.attackerWouldBeDestroyed(ai, attacker, currCombat)
+ && ComputerUtilCombat.attackerWouldBeDestroyed(ai, attacker, currCombat)
&& !currCombat.getBlockers(attacker).isEmpty()) {
ComputerUtilCard.sortByEvaluateCreature(blockers);
Combat combat = new Combat(ai);
@@ -970,9 +970,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
sa.getTargets().add(tobounce);
- boolean saheeliFelidarCombo = sa.getHostCard().getName().equals("Felidar Guardian")
+ boolean saheeliFelidarCombo = sa.getHostCard().getName().equals("Felidar Guardian")
&& tobounce.getName().equals("Saheeli Rai")
- && CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals("Felidar Guardian")).size() <
+ && CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals("Felidar Guardian")).size() <
CardLists.filter(ai.getOpponents().getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Creature")).size() + ai.getOpponentsGreatestLifeTotal() + 10;
// remember that the card was bounced already unless it's a special combo case
@@ -985,20 +985,20 @@ public class ChangeZoneAi extends SpellAbilityAi {
// bounce opponent's stuff
list = CardLists.filterControlledBy(list, ai.getOpponents());
if (!CardLists.getNotType(list, "Land").isEmpty()) {
- // When bouncing opponents stuff other than lands, don't bounce cards with CMC 0
- list = CardLists.filter(list, new Predicate() {
- @Override
- public boolean apply(final Card c) {
- for (Card aura : c.getEnchantedBy()) {
+ // When bouncing opponents stuff other than lands, don't bounce cards with CMC 0
+ list = CardLists.filter(list, new Predicate() {
+ @Override
+ public boolean apply(final Card c) {
+ for (Card aura : c.getEnchantedBy()) {
return aura.getController().isOpponentOf(ai);
- }
- if (blink) {
- return c.isToken();
- } else {
- return c.isToken() || c.getCMC() > 0;
- }
- }
- });
+ }
+ if (blink) {
+ return c.isToken();
+ } else {
+ return c.isToken() || c.getCMC() > 0;
+ }
+ }
+ });
}
// TODO: Blink permanents with ETB triggers
/*else if (!sa.isTrigger() && SpellAbilityAi.playReusable(ai, sa)) {
@@ -1023,7 +1023,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
} else if (origin.contains(ZoneType.Graveyard)) {
- if (destination.equals(ZoneType.Exile) || destination.equals(ZoneType.Library)) {
+ if (destination.equals(ZoneType.Exile) || destination.equals(ZoneType.Library)) {
// Don't use these abilities before main 2 if possible
if (!immediately && game.getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2)
&& !sa.hasParam("ActivationPhases") && !ComputerUtil.castSpellInMain1(ai, sa)) {
@@ -1035,7 +1035,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
&& !ComputerUtil.activateForCost(sa, ai)) {
return false;
}
- } else if (destination.equals(ZoneType.Hand)) {
+ } else if (destination.equals(ZoneType.Hand)) {
// only retrieve cards from computer graveyard
list = CardLists.filterControlledBy(list, ai);
} else if (sa.hasParam("AttachedTo")) {
@@ -1096,10 +1096,10 @@ public class ChangeZoneAi extends SpellAbilityAi {
// Only care about combatants during combat
if (game.getPhaseHandler().inCombat() && origin.contains(ZoneType.Battlefield)) {
- CardCollection newList = CardLists.getValidCards(list, "Card.attacking,Card.blocking", null, null);
- if (!newList.isEmpty() || !sa.isTrigger()) {
- list = newList;
- }
+ CardCollection newList = CardLists.getValidCards(list, "Card.attacking,Card.blocking", null, null);
+ if (!newList.isEmpty() || !sa.isTrigger()) {
+ list = newList;
+ }
}
boolean doWithoutTarget = sa.hasParam("Planeswalker") && sa.usesTargeting()
@@ -1251,7 +1251,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
return true;
}
-
+
/**
* Checks if a permanent threatened by a stack ability or in combat can
* be saved by bouncing.
@@ -1324,11 +1324,11 @@ public class ChangeZoneAi extends SpellAbilityAi {
Collections.sort(aiPlaneswalkers, new Comparator() {
@Override
public int compare(final Card a, final Card b) {
- return a.getCounters(CounterType.LOYALTY) - b.getCounters(CounterType.LOYALTY);
+ return a.getCounters(CounterEnumType.LOYALTY) - b.getCounters(CounterEnumType.LOYALTY);
}
});
for (Card pw : aiPlaneswalkers) {
- int curLoyalty = pw.getCounters(CounterType.LOYALTY);
+ int curLoyalty = pw.getCounters(CounterEnumType.LOYALTY);
int freshLoyalty = Integer.valueOf(pw.getCurrentState().getBaseLoyalty());
if (freshLoyalty - curLoyalty >= loyaltyDiff && curLoyalty <= maxLoyaltyToConsider) {
return pw;
@@ -1506,10 +1506,10 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (type == null) {
type = "Card";
}
-
+
Card c = null;
final Player activator = sa.getActivatingPlayer();
-
+
CardLists.shuffle(fetchList);
// Save a card as a default, in case we can't find anything suitable.
Card first = fetchList.get(0);
@@ -1614,19 +1614,19 @@ public class ChangeZoneAi extends SpellAbilityAi {
// AI was never asked
return true;
}
-
+
@Override
- public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
// Called when looking for creature to attach aura or equipment
return ComputerUtilCard.getBestAI(options);
}
-
+
/* (non-Javadoc)
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayer(forge.game.player.Player, forge.card.spellability.SpellAbility, java.util.List)
*/
@Override
- public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options) {
+ public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) {
// Currently only used by Curse of Misfortunes, so this branch should never get hit
// But just in case it does, just select the first option
return Iterables.getFirst(options, null);
@@ -1801,7 +1801,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (causeSa != null && (causeSub = causeSa.getSubAbility()) != null) {
ApiType subApi = causeSub.getApi();
-
+
if (subApi == ApiType.ChangeZone && "Exile".equals(causeSub.getParam("Origin"))
&& "Battlefield".equals(causeSub.getParam("Destination"))) {
// A blink effect implemented using ChangeZone API
@@ -1817,7 +1817,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} else return causeSa.getHostCard() == null || !causeSa.getHostCard().equals(sa.getReplacingObject(AbilityKey.Card))
|| !causeSa.getActivatingPlayer().equals(aiPlayer);
}
-
+
// Normally we want the commander back in Command zone to recast him later
return true;
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java
index 1f9343599df..296a695b871 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java
@@ -11,6 +11,7 @@ import forge.util.MyRandom;
import forge.util.collect.FCollection;
import java.util.List;
+import java.util.Map;
public class CharmAi extends SpellAbilityAi {
@Override
@@ -232,7 +233,7 @@ public class CharmAi extends SpellAbilityAi {
}
@Override
- public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable opponents) {
+ public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable opponents, Map params) {
return Aggregates.random(opponents);
}
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java
index e16e748ed8a..f8a48d2ec25 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java
@@ -2,6 +2,7 @@ package forge.ai.ability;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
@@ -20,7 +21,7 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.combat.Combat;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseType;
@@ -99,7 +100,7 @@ public class ChooseCardAi extends SpellAbilityAi {
});
return !choices.isEmpty();
} else if (aiLogic.equals("Ashiok")) {
- final int loyalty = host.getCounters(CounterType.LOYALTY) - 1;
+ final int loyalty = host.getCounters(CounterEnumType.LOYALTY) - 1;
for (int i = loyalty; i >= 0; i--) {
host.setSVar("ChosenX", "Number$" + i);
choices = ai.getGame().getCardsIn(choiceZone);
@@ -140,12 +141,12 @@ public class ChooseCardAi extends SpellAbilityAi {
}
return checkApiLogic(ai, sa);
}
-
+
/* (non-Javadoc)
* @see forge.card.ability.SpellAbilityAi#chooseSingleCard(forge.card.spellability.SpellAbility, java.util.List, boolean)
*/
@Override
- public Card chooseSingleCard(final Player ai, final SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ public Card chooseSingleCard(final Player ai, final SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
final Card host = sa.getHostCard();
final Player ctrl = host.getController();
final String logic = sa.getParam("AILogic");
@@ -191,7 +192,7 @@ public class ChooseCardAi extends SpellAbilityAi {
if (combat == null || !combat.isAttacking(c, ai) || !combat.isUnblocked(c)) {
return false;
}
- int ref = ComputerUtilAbility.getAbilitySourceName(sa).equals("Forcefield") ? 1 : 0;
+ int ref = ComputerUtilAbility.getAbilitySourceName(sa).equals("Forcefield") ? 1 : 0;
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
}
});
diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseCardNameAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseCardNameAi.java
index ff0bfc2ceaa..f9c3b3d9798 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ChooseCardNameAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ChooseCardNameAi.java
@@ -1,6 +1,7 @@
package forge.ai.ability;
import java.util.List;
+import java.util.Map;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -23,7 +24,6 @@ public class ChooseCardNameAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
- Card source = sa.getHostCard();
if (sa.hasParam("AILogic")) {
// Don't tap creatures that may be able to block
if (ComputerUtil.waitForBlocking(sa)) {
@@ -60,7 +60,7 @@ public class ChooseCardNameAi extends SpellAbilityAi {
* @see forge.card.ability.SpellAbilityAi#chooseSingleCard(forge.card.spellability.SpellAbility, java.util.List, boolean)
*/
@Override
- public Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ public Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
return ComputerUtilCard.getBestAI(options);
}
@@ -86,7 +86,7 @@ public class ChooseCardNameAi extends SpellAbilityAi {
if (rules.getSplitType() == CardSplitType.Split) {
Card copy = CardUtil.getLKICopy(card);
- // for calcing i need only one split side
+ // for calcing i need only one split side
if (isOther) {
copy.getCurrentState().copyFrom(card.getState(CardStateName.RightSplit), true);
} else {
diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseCompanionAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseCompanionAi.java
index 7f6d1484608..1240d9ab54f 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ChooseCompanionAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ChooseCompanionAi.java
@@ -8,6 +8,7 @@ import forge.game.spellability.SpellAbility;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
public class ChooseCompanionAi extends SpellAbilityAi {
@@ -15,7 +16,7 @@ public class ChooseCompanionAi extends SpellAbilityAi {
* @see forge.card.ability.SpellAbilityAi#chooseSingleCard(forge.card.spellability.SpellAbility, java.util.List, boolean)
*/
@Override
- public Card chooseSingleCard(final Player ai, final SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ public Card chooseSingleCard(final Player ai, final SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
List cards = Lists.newArrayList(options);
if (cards.isEmpty()) {
return null;
diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java
index 3a1a87200ab..b814b347224 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java
@@ -180,25 +180,25 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
Card imprinted = host.getImprintedCards().getFirst();
int dmg = imprinted.getCMC();
Player owner = imprinted.getOwner();
-
+
//useless cards in hand
if (imprinted.getName().equals("Bridge from Below") ||
imprinted.getName().equals("Haakon, Stromgald Scourge")) {
return allow;
}
-
+
//bad cards when are thrown from the library to the graveyard, but Yixlid can prevent that
if (!player.getGame().isCardInPlay("Yixlid Jailer") && (
imprinted.getName().equals("Gaea's Blessing") ||
imprinted.getName().equals("Narcomoeba"))) {
return allow;
}
-
+
// milling against Tamiyo is pointless
if (owner.isCardInCommand("Emblem - Tamiyo, the Moon Sage")) {
return allow;
}
-
+
// milling a land against Gitrog result in card draw
if (imprinted.isLand() && owner.isCardInPlay("The Gitrog Monster")) {
// try to mill owner
@@ -207,19 +207,19 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
}
return allow;
}
-
+
// milling a creature against Sidisi result in more creatures
if (imprinted.isCreature() && owner.isCardInPlay("Sidisi, Brood Tyrant")) {
return allow;
}
- //if Iona does prevent from casting, allow it to draw
+ //if Iona does prevent from casting, allow it to draw
for (final Card io : player.getCardsIn(ZoneType.Battlefield, "Iona, Shield of Emeria")) {
if (CardUtil.getColors(imprinted).hasAnyColor(MagicColor.fromName(io.getChosenColor()))) {
return allow;
}
}
-
+
if (dmg == 0) {
// If CMC = 0, mill it!
return deny;
@@ -244,7 +244,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
SpellAbility counterSA = spells.get(0), tokenSA = spells.get(1);
// check for something which might prevent the counters to be placed on host
- if (!host.canReceiveCounters(CounterType.P1P1)) {
+ if (!host.canReceiveCounters(CounterEnumType.P1P1)) {
return tokenSA;
}
@@ -256,7 +256,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
// need a copy for one with extra +1/+1 counter boost,
// without causing triggers to run
final Card copy = CardUtil.getLKICopy(host);
- copy.setCounters(CounterType.P1P1, copy.getCounters(CounterType.P1P1) + n);
+ copy.setCounters(CounterEnumType.P1P1, copy.getCounters(CounterEnumType.P1P1) + n);
copy.setZone(host.getZone());
// if host would put into the battlefield attacking
@@ -283,7 +283,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
// in this cases Token might be prefered even if they would not survive
final Card tokenCard = TokenAi.spawnToken(player, tokenSA);
- // Token would not survive
+ // Token would not survive
if (!tokenCard.isCreature() || tokenCard.getNetToughness() < 1) {
return counterSA;
}
@@ -336,7 +336,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
filtered.add(sp);
}
}
-
+
// TODO find better way to check
if (!filtered.isEmpty()) {
return filtered.get(0);
@@ -362,7 +362,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
game.getAction().checkStaticAbilities(false);
// can't gain counters, use Haste
- if (!copy.canReceiveCounters(CounterType.P1P1)) {
+ if (!copy.canReceiveCounters(CounterEnumType.P1P1)) {
return true;
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/ChoosePlayerAi.java b/forge-ai/src/main/java/forge/ai/ability/ChoosePlayerAi.java
index ddb90e701f1..5b98b108cda 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ChoosePlayerAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ChoosePlayerAi.java
@@ -9,6 +9,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.List;
+import java.util.Map;
public class ChoosePlayerAi extends SpellAbilityAi {
@Override
@@ -27,7 +28,7 @@ public class ChoosePlayerAi extends SpellAbilityAi {
}
@Override
- public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable choices) {
+ public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable choices, Map params) {
Player chosen = null;
if ("Curse".equals(sa.getParam("AILogic"))) {
for (Player pc : choices) {
diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java
index f7a694e0c67..038f9a843ab 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java
@@ -1,6 +1,7 @@
package forge.ai.ability;
import java.util.List;
+import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
@@ -126,7 +127,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
@Override
- public Card chooseSingleCard(final Player aiChoser, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ public Card chooseSingleCard(final Player aiChoser, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
if ("NeedsPrevention".equals(sa.getParam("AILogic"))) {
final Player ai = sa.getActivatingPlayer();
final Game game = ai.getGame();
diff --git a/forge-ai/src/main/java/forge/ai/ability/ClashAi.java b/forge-ai/src/main/java/forge/ai/ability/ClashAi.java
index 5800ecefb32..b9f7e8d7e6f 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ClashAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ClashAi.java
@@ -1,6 +1,8 @@
package forge.ai.ability;
+import java.util.Map;
+
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtilCard;
@@ -56,7 +58,7 @@ public class ClashAi extends SpellAbilityAi {
* forge.game.spellability.SpellAbility, java.lang.Iterable)
*/
@Override
- protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options) {
+ protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) {
for (Player p : options) {
if (p.getCardsIn(ZoneType.Library).size() == 0)
return p;
@@ -82,7 +84,7 @@ public class ClashAi extends SpellAbilityAi {
PlayerCollection players = ai.getOpponents().filter(PlayerPredicates.isTargetableBy(sa));
// use chooseSinglePlayer function to the select player
- Player chosen = chooseSinglePlayer(ai, sa, players);
+ Player chosen = chooseSinglePlayer(ai, sa, players, null);
if (chosen != null) {
sa.resetTargets();
sa.getTargets().add(chosen);
diff --git a/forge-ai/src/main/java/forge/ai/ability/CloneAi.java b/forge-ai/src/main/java/forge/ai/ability/CloneAi.java
index 3d6870d033d..3a3de604029 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CloneAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CloneAi.java
@@ -15,6 +15,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.List;
+import java.util.Map;
public class CloneAi extends SpellAbilityAi {
@@ -169,7 +170,7 @@ public class CloneAi extends SpellAbilityAi {
*/
@Override
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional,
- Player targetedPlayer) {
+ Player targetedPlayer, Map params) {
final Card host = sa.getHostCard();
final Player ctrl = host.getController();
diff --git a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java
index 7a29ee98068..617da8098eb 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java
@@ -18,6 +18,7 @@
package forge.ai.ability;
import java.util.List;
+import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@@ -302,7 +303,7 @@ public class ControlGainAi extends SpellAbilityAi {
} // pumpDrawbackAI()
@Override
- protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options) {
+ protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) {
final List cards = Lists.newArrayList();
for (Player p : options) {
cards.addAll(p.getCreaturesInPlay());
diff --git a/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java b/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java
index 7ce9dfbc473..e455230988f 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java
@@ -19,6 +19,7 @@ import forge.game.zone.ZoneType;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
public class CopyPermanentAi extends SpellAbilityAi {
@Override
@@ -204,7 +205,7 @@ public class CopyPermanentAi extends SpellAbilityAi {
* @see forge.card.ability.SpellAbilityAi#chooseSingleCard(forge.game.player.Player, forge.card.spellability.SpellAbility, java.util.List, boolean)
*/
@Override
- public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
// Select a card to attach to
CardCollection betterOptions = getBetterOptions(ai, sa, options, isOptional);
if (!betterOptions.isEmpty()) {
@@ -223,7 +224,7 @@ public class CopyPermanentAi extends SpellAbilityAi {
}
@Override
- protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options) {
+ protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) {
final List cards = new PlayerCollection(options).getCreaturesInPlay();
Card chosen = ComputerUtilCard.getBestCreatureAI(cards);
return chosen != null ? chosen.getController() : Iterables.getFirst(options, null);
diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersAi.java
index 2535c29505d..659b05de3cd 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CountersAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CountersAi.java
@@ -6,12 +6,12 @@
* 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 .
*/
@@ -26,7 +26,7 @@ import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.keyword.Keyword;
import forge.util.Aggregates;
@@ -35,7 +35,7 @@ import forge.util.Aggregates;
*
* AbilityFactory_Counters class.
*
- *
+ *
* @author Forge
* @version $Id$
*/
@@ -46,7 +46,7 @@ public abstract class CountersAi {
*
* chooseCursedTarget.
*
- *
+ *
* @param list
* a {@link forge.CardList} object.
* @param type
@@ -77,7 +77,7 @@ public abstract class CountersAi {
*
* chooseBoonTarget.
*
- *
+ *
* @param list
* a {@link forge.CardList} object.
* @param type
@@ -97,7 +97,7 @@ public abstract class CountersAi {
final CardCollection boon = CardLists.filter(list, new Predicate() {
@Override
public boolean apply(final Card c) {
- return c.getCounters(CounterType.DIVINITY) == 0;
+ return c.getCounters(CounterEnumType.DIVINITY) == 0;
}
});
choice = ComputerUtilCard.getMostExpensivePermanentAI(boon, null, false);
diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java
index bf142184a33..b6e75e62b91 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java
@@ -42,14 +42,14 @@ public class CountersMoveAi extends SpellAbilityAi {
protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph) {
final Card host = sa.getHostCard();
final String type = sa.getParam("CounterType");
- final CounterType cType = "Any".equals(type) ? null : CounterType.valueOf(type);
+ final CounterType cType = "Any".equals(type) ? null : CounterType.getType(type);
// Don't tap creatures that may be able to block
if (ComputerUtil.waitForBlocking(sa)) {
return false;
}
- if (CounterType.P1P1.equals(cType) && sa.hasParam("Source")) {
+ if (CounterEnumType.P1P1.equals(cType) && sa.hasParam("Source")) {
int amount = calcAmount(sa, cType);
final List srcCards = AbilityUtils.getDefinedCards(host, sa.getParam("Source"), sa);
if (ph.getPlayerTurn().isOpponentOf(ai)) {
@@ -92,7 +92,7 @@ public class CountersMoveAi extends SpellAbilityAi {
// for Simic Fluxmage and other
return ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN);
- } else if (CounterType.P1P1.equals(cType) && sa.hasParam("Defined")) {
+ } else if (CounterEnumType.P1P1.equals(cType) && sa.hasParam("Defined")) {
// something like Cyptoplast Root-kin
if (ph.getPlayerTurn().isOpponentOf(ai)) {
if (ph.inCombat() && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
@@ -115,6 +115,7 @@ public class CountersMoveAi extends SpellAbilityAi {
protected boolean doTriggerAINoCost(final Player ai, SpellAbility sa, boolean mandatory) {
if (sa.usesTargeting()) {
+ sa.resetTargets();
if (!moveTgtAI(ai, sa) && !mandatory) {
return false;
@@ -142,7 +143,7 @@ public class CountersMoveAi extends SpellAbilityAi {
final Card host = sa.getHostCard();
final String type = sa.getParam("CounterType");
- final CounterType cType = "Any".equals(type) ? null : CounterType.valueOf(type);
+ final CounterType cType = "Any".equals(type) ? null : CounterType.getType(type);
final List srcCards = AbilityUtils.getDefinedCards(host, sa.getParam("Source"), sa);
final List destCards = AbilityUtils.getDefinedCards(host, sa.getParam("Defined"), sa);
@@ -189,7 +190,7 @@ public class CountersMoveAi extends SpellAbilityAi {
// check for some specific AI preferences
if ("DontMoveCounterIfLethal".equals(sa.getParam("AILogic"))) {
- return cType != CounterType.P1P1 || src.getNetToughness() - src.getTempToughnessBoost() - 1 > 0;
+ return !cType.is(CounterEnumType.P1P1) || src.getNetToughness() - src.getTempToughnessBoost() - 1 > 0;
}
}
// no target
@@ -234,7 +235,7 @@ public class CountersMoveAi extends SpellAbilityAi {
final Card host = sa.getHostCard();
final Game game = ai.getGame();
final String type = sa.getParam("CounterType");
- final CounterType cType = "Any".equals(type) ? null : CounterType.valueOf(type);
+ final CounterType cType = "Any".equals(type) || "All".equals(type) ? null : CounterType.getType(type);
List tgtCards = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa);
@@ -278,7 +279,7 @@ public class CountersMoveAi extends SpellAbilityAi {
// do not steal a P1P1 from Undying if it would die
// this way
- if (CounterType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) {
+ if (CounterEnumType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) {
return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING) || card.isToken();
}
return true;
@@ -321,13 +322,13 @@ public class CountersMoveAi extends SpellAbilityAi {
}
// try to remove P1P1 from undying or evolve
- if (CounterType.P1P1.equals(cType)) {
+ if (CounterEnumType.P1P1.equals(cType)) {
if (card.hasKeyword(Keyword.UNDYING) || card.hasKeyword(Keyword.EVOLVE)
|| card.hasKeyword(Keyword.ADAPT)) {
return true;
}
}
- if (CounterType.M1M1.equals(cType) && card.hasKeyword(Keyword.PERSIST)) {
+ if (CounterEnumType.M1M1.equals(cType) && card.hasKeyword(Keyword.PERSIST)) {
return true;
}
@@ -382,10 +383,10 @@ public class CountersMoveAi extends SpellAbilityAi {
}
if (cType != null) {
- if (CounterType.P1P1.equals(cType) && card.hasKeyword(Keyword.UNDYING)) {
+ if (CounterEnumType.P1P1.equals(cType) && card.hasKeyword(Keyword.UNDYING)) {
return false;
}
- if (CounterType.M1M1.equals(cType) && card.hasKeyword(Keyword.PERSIST)) {
+ if (CounterEnumType.M1M1.equals(cType) && card.hasKeyword(Keyword.PERSIST)) {
return false;
}
@@ -393,7 +394,7 @@ public class CountersMoveAi extends SpellAbilityAi {
return false;
}
}
- return false;
+ return true;
}
});
@@ -452,7 +453,7 @@ public class CountersMoveAi extends SpellAbilityAi {
// or for source -> multiple defined
@Override
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional,
- Player targetedPlayer) {
+ Player targetedPlayer, Map params) {
if (sa.hasParam("AiLogic")) {
String logic = sa.getParam("AiLogic");
diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersMultiplyAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersMultiplyAi.java
index b20e99ace3b..1dc29e1a89b 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CountersMultiplyAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CountersMultiplyAi.java
@@ -16,6 +16,7 @@ import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -77,7 +78,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph) {
final CounterType counterType = getCounterType(sa);
- if (!CounterType.P1P1.equals(counterType) && counterType != null) {
+ if (!CounterEnumType.P1P1.equals(counterType) && counterType != null) {
if (!sa.hasParam("ActivationPhases")) {
// Don't use non P1P1/M1M1 counters before main 2 if possible
if (ph.getPhase().isBefore(PhaseType.MAIN2) && !ComputerUtil.castSpellInMain1(ai, sa)) {
@@ -147,15 +148,15 @@ public class CountersMultiplyAi extends SpellAbilityAi {
if (!aiList.isEmpty()) {
// counter type list to check
// first loyalty, then P1P!, then Charge Counter
- List typeList = Lists.newArrayList(CounterType.LOYALTY, CounterType.P1P1, CounterType.CHARGE);
- for (CounterType type : typeList) {
+ List typeList = Lists.newArrayList(CounterEnumType.LOYALTY, CounterEnumType.P1P1, CounterEnumType.CHARGE);
+ for (CounterEnumType type : typeList) {
// enough targets
if (!sa.canAddMoreTarget()) {
break;
}
- if (counterType == null || counterType == type) {
- addTargetsByCounterType(ai, sa, aiList, type);
+ if (counterType == null || counterType.is(type)) {
+ addTargetsByCounterType(ai, sa, aiList, CounterType.get(type));
}
}
}
@@ -164,7 +165,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
if (!oppList.isEmpty()) {
// not enough targets
if (sa.canAddMoreTarget()) {
- final CounterType type = CounterType.M1M1;
+ final CounterType type = CounterType.get(CounterEnumType.M1M1);
if (counterType == null || counterType == type) {
addTargetsByCounterType(ai, sa, oppList, type);
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersProliferateAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersProliferateAi.java
index 52538a0827c..7dd9618dafe 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CountersProliferateAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CountersProliferateAi.java
@@ -15,6 +15,7 @@ import forge.game.GameEntity;
import forge.game.card.Card;
import forge.game.card.CardLists;
import forge.game.card.CardUtil;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -32,7 +33,7 @@ public class CountersProliferateAi extends SpellAbilityAi {
for (final Player p : allies) {
// player has experience or energy counter
- if (p.getCounters(CounterType.EXPERIENCE) + p.getCounters(CounterType.ENERGY) >= 1) {
+ if (p.getCounters(CounterEnumType.EXPERIENCE) + p.getCounters(CounterEnumType.ENERGY) >= 1) {
allyExpOrEnergy = true;
}
cperms.addAll(CardLists.filter(p.getCardsIn(ZoneType.Battlefield), new Predicate() {
@@ -115,17 +116,19 @@ public class CountersProliferateAi extends SpellAbilityAi {
*/
@SuppressWarnings("unchecked")
@Override
- public T chooseSingleEntity(Player ai, SpellAbility sa, Collection options, boolean isOptional, Player targetedPlayer) {
+ public T chooseSingleEntity(Player ai, SpellAbility sa, Collection options, boolean isOptional, Player targetedPlayer, Map params) {
// Proliferate is always optional for all, no need to select best
+ final CounterType poison = CounterType.get(CounterEnumType.POISON);
+
// because countertype can't be chosen anymore, only look for posion counters
for (final Player p : Iterables.filter(options, Player.class)) {
if (p.isOpponentOf(ai)) {
- if (p.getCounters(CounterType.POISON) > 0 && p.canReceiveCounters(CounterType.POISON)) {
+ if (p.getCounters(poison) > 0 && p.canReceiveCounters(poison)) {
return (T)p;
}
} else {
- if (p.getCounters(CounterType.POISON) <= 5 || p.canReceiveCounters(CounterType.POISON)) {
+ if (p.getCounters(poison) <= 5 || p.canReceiveCounters(poison)) {
return (T)p;
}
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java
index 70f568a6954..c3448d4af15 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java
@@ -35,7 +35,7 @@ public class CountersPutAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see forge.ai.SpellAbilityAi#willPayCosts(forge.game.player.Player,
* forge.game.spellability.SpellAbility, forge.game.cost.Cost,
* forge.game.card.Card)
@@ -56,17 +56,17 @@ public class CountersPutAi extends SpellAbilityAi {
if (part instanceof CostRemoveCounter) {
final CostRemoveCounter remCounter = (CostRemoveCounter) part;
final CounterType counterType = remCounter.counter;
- if (counterType.name().equals(type) && !aiLogic.startsWith("MoveCounter")) {
+ if (counterType.getName().equals(type) && !aiLogic.startsWith("MoveCounter")) {
return false;
}
if (!part.payCostFromSource()) {
- if (counterType.equals(CounterType.P1P1)) {
+ if (counterType.is(CounterEnumType.P1P1)) {
return false;
}
continue;
}
// don't kill the creature
- if (counterType.equals(CounterType.P1P1) && source.getLethalDamage() <= 1) {
+ if (counterType.is(CounterEnumType.P1P1) && source.getLethalDamage() <= 1) {
return false;
}
}
@@ -77,7 +77,7 @@ public class CountersPutAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see
* forge.ai.SpellAbilityAi#checkPhaseRestrictions(forge.game.player.Player,
* forge.game.spellability.SpellAbility, forge.game.phase.PhaseHandler)
@@ -109,7 +109,7 @@ public class CountersPutAi extends SpellAbilityAi {
}
}
int maxLevel = Integer.parseInt(sa.getParam("MaxLevel"));
- return source.getCounters(CounterType.LEVEL) < maxLevel;
+ return source.getCounters(CounterEnumType.LEVEL) < maxLevel;
}
return super.checkPhaseRestrictions(ai, sa, ph);
@@ -146,7 +146,7 @@ public class CountersPutAi extends SpellAbilityAi {
if (abTgt.canTgtPlayer()) {
// try to kill opponent with Poison
PlayerCollection oppList = ai.getOpponents().filter(PlayerPredicates.isTargetableBy(sa));
- PlayerCollection poisonList = oppList.filter(PlayerPredicates.hasCounter(CounterType.POISON, 9));
+ PlayerCollection poisonList = oppList.filter(PlayerPredicates.hasCounter(CounterEnumType.POISON, 9));
if (!poisonList.isEmpty()) {
sa.getTargets().add(poisonList.max(PlayerPredicates.compareByLife()));
return true;
@@ -157,13 +157,13 @@ public class CountersPutAi extends SpellAbilityAi {
// try to kill creature with -1/-1 counters if it can
// receive counters, execpt it has undying
CardCollection oppCreat = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), sa);
- CardCollection oppCreatM1 = CardLists.filter(oppCreat, CardPredicates.hasCounter(CounterType.M1M1));
+ CardCollection oppCreatM1 = CardLists.filter(oppCreat, CardPredicates.hasCounter(CounterEnumType.M1M1));
oppCreatM1 = CardLists.getNotKeyword(oppCreatM1, Keyword.UNDYING);
oppCreatM1 = CardLists.filter(oppCreatM1, new Predicate() {
@Override
public boolean apply(Card input) {
- return input.getNetToughness() <= 1 && input.canReceiveCounters(CounterType.M1M1);
+ return input.getNetToughness() <= 1 && input.canReceiveCounters(CounterType.get(CounterEnumType.M1M1));
}
});
@@ -244,7 +244,7 @@ public class CountersPutAi extends SpellAbilityAi {
int totBlkPower = Aggregates.sum(blocked, CardPredicates.Accessors.fnGetNetPower);
int totBlkToughness = Aggregates.min(blocked, CardPredicates.Accessors.fnGetNetToughness);
- int numActivations = ai.getCounters(CounterType.ENERGY) / sa.getPayCosts().getCostEnergy().convertAmount();
+ int numActivations = ai.getCounters(CounterEnumType.ENERGY) / sa.getPayCosts().getCostEnergy().convertAmount();
if (sa.getHostCard().getNetToughness() + numActivations > totBlkPower
|| sa.getHostCard().getNetPower() + numActivations >= totBlkToughness) {
return true;
@@ -259,7 +259,7 @@ public class CountersPutAi extends SpellAbilityAi {
AiCardMemory.rememberCard(ai, source, AiCardMemory.MemorySet.ACTIVATED_THIS_TURN);
return true;
}
- } else if (ai.getCounters(CounterType.ENERGY) > ComputerUtilCard.getMaxSAEnergyCostOnBattlefield(ai) + sa.getPayCosts().getCostEnergy().convertAmount()) {
+ } else if (ai.getCounters(CounterEnumType.ENERGY) > ComputerUtilCard.getMaxSAEnergyCostOnBattlefield(ai) + sa.getPayCosts().getCostEnergy().convertAmount()) {
// outside of combat, this logic only works if the relevant AI profile option is enabled
// and if there is enough energy saved
if (!onlyInCombat) {
@@ -293,7 +293,7 @@ public class CountersPutAi extends SpellAbilityAi {
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
return false;
}
-
+
if (sourceName.equals("Feat of Resistance")) { // sub-ability should take precedence
CardCollection prot = ProtectAi.getProtectCreatures(ai, sa.getSubAbility());
if (!prot.isEmpty()) {
@@ -322,7 +322,7 @@ public class CountersPutAi extends SpellAbilityAi {
Game game = ai.getGame();
Combat combat = game.getCombat();
- if (!source.canReceiveCounters(CounterType.P1P1) || source.getCounters(CounterType.P1P1) > 0) {
+ if (!source.canReceiveCounters(CounterType.get(CounterEnumType.P1P1)) || source.getCounters(CounterEnumType.P1P1) > 0) {
return false;
} else if (combat != null && ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
return doCombatAdaptLogic(source, amount, combat);
@@ -336,7 +336,7 @@ public class CountersPutAi extends SpellAbilityAi {
}
return FightAi.canFightAi(ai, sa, nPump, nPump);
}
-
+
if (amountStr.equals("X")) {
if (source.getSVar(amountStr).equals("Count$xPaid")) {
// By default, set PayX here to maximum value (used for most SAs of this type).
@@ -345,7 +345,7 @@ public class CountersPutAi extends SpellAbilityAi {
if (isClockwork) {
// Clockwork Avian and other similar cards: do not tap all mana for X,
// instead only rewind to max allowed value when the power gets low enough.
- int curCtrs = source.getCounters(CounterType.P1P0);
+ int curCtrs = source.getCounters(CounterEnumType.P1P0);
int maxCtrs = Integer.parseInt(sa.getParam("MaxFromEffect"));
// This will "rewind" clockwork cards when they fall to 50% power or below, consider improving
@@ -396,7 +396,7 @@ public class CountersPutAi extends SpellAbilityAi {
return true;
}
}
-
+
if (!ai.getGame().getStack().isEmpty() && !SpellAbilityAi.isSorcerySpeed(sa)) {
final TargetRestrictions abTgt = sa.getTargetRestrictions();
// only evaluates case where all tokens are placed on a single target
@@ -417,8 +417,8 @@ public class CountersPutAi extends SpellAbilityAi {
// Targeting
if (sa.usesTargeting()) {
- sa.resetTargets();
-
+ sa.resetTargets();
+
final boolean sacSelf = ComputerUtilCost.isSacrificeSelfCost(abCost);
if (sa.isCurse()) {
@@ -435,7 +435,7 @@ public class CountersPutAi extends SpellAbilityAi {
if (sacSelf && c.equals(source)) {
return false;
}
- return sa.canTarget(c) && c.canReceiveCounters(CounterType.valueOf(type));
+ return sa.canTarget(c) && c.canReceiveCounters(CounterType.getType(type));
}
});
@@ -488,7 +488,7 @@ public class CountersPutAi extends SpellAbilityAi {
}
return false;
}
-
+
// target loop
while (sa.canAddMoreTarget()) {
if (list.isEmpty()) {
@@ -558,7 +558,7 @@ public class CountersPutAi extends SpellAbilityAi {
return false;
}
- final int currCounters = cards.get(0).getCounters(CounterType.valueOf(type));
+ final int currCounters = cards.get(0).getCounters(CounterType.get(type));
// each non +1/+1 counter on the card is a 10% chance of not
// activating this ability.
@@ -574,11 +574,11 @@ public class CountersPutAi extends SpellAbilityAi {
}
boolean immediately = ComputerUtil.playImmediately(ai, sa);
-
+
if (abCost != null && !ComputerUtilCost.checkSacrificeCost(ai, abCost, source, sa, immediately)) {
return false;
}
-
+
if (immediately) {
return true;
}
@@ -612,7 +612,7 @@ public class CountersPutAi extends SpellAbilityAi {
final boolean divided = sa.hasParam("DividedAsYouChoose");
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), amountStr, sa);
- final boolean isMandatoryTrigger = (sa.isTrigger() && !sa.isOptionalTrigger())
+ final boolean isMandatoryTrigger = (sa.isTrigger() && !sa.isOptionalTrigger())
|| (sa.getRootAbility().isTrigger() && !sa.getRootAbility().isOptionalTrigger());
if (sa.usesTargeting()) {
@@ -692,12 +692,12 @@ public class CountersPutAi extends SpellAbilityAi {
final boolean divided = sa.hasParam("DividedAsYouChoose");
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), amountStr, sa);
int left = amount;
-
+
if (!sa.usesTargeting()) {
// No target. So must be defined
list = new CardCollection(AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa));
-
- if (amountStr.equals("X")
+
+ if (amountStr.equals("X")
&& !source.hasSVar("PayX") /* SubAbility on something that already had set PayX, e.g. Endless One ETB counters */
&& ((sa.hasParam(amountStr) && sa.getSVar(amountStr).equals("Count$xPaid")) || source.getSVar(amountStr).equals("Count$xPaid") )) {
@@ -727,7 +727,7 @@ public class CountersPutAi extends SpellAbilityAi {
source.setSVar("PayX", Integer.toString(payX));
}
-
+
if (!mandatory) {
// TODO - If Trigger isn't mandatory, when wouldn't we want to
// put a counter?
@@ -854,7 +854,7 @@ public class CountersPutAi extends SpellAbilityAi {
List threatening = CardLists.filter(creats, new Predicate() {
@Override
public boolean apply(Card c) {
- return CombatUtil.canBlock(source, c, !isHaste)
+ return CombatUtil.canBlock(source, c, !isHaste)
&& (c.getNetToughness() > source.getNetPower() + tributeAmount || c.hasKeyword(Keyword.DEATHTOUCH));
}
});
@@ -889,24 +889,28 @@ public class CountersPutAi extends SpellAbilityAi {
}
@Override
- public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options) {
+ public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) {
// used by Tribute, select player with lowest Life
// TODO add more logic using TributeAILogic
List list = Lists.newArrayList(options);
return Collections.min(list, PlayerPredicates.compareByLife());
}
-
+
@Override
- protected Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ protected Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
// Bolster does use this
// TODO need more or less logic there?
+ final CounterType m1m1 = CounterType.get(CounterEnumType.M1M1);
+ final CounterType p1p1 = CounterType.get(CounterEnumType.P1P1);
// no logic if there is no options or no to choice
if (!isOptional && Iterables.size(options) <= 1) {
return Iterables.getFirst(options, null);
}
- final CounterType type = CounterType.valueOf(sa.getParam("CounterType"));
+ final CounterType type = params.containsKey("CounterType") ? (CounterType)params.get("CounterType")
+ : CounterType.getType(sa.getParam("CounterType"));
+
final String amountStr = sa.getParamOrDefault("CounterNum", "1");
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), amountStr, sa);
@@ -923,7 +927,7 @@ public class CountersPutAi extends SpellAbilityAi {
return false;
if (ComputerUtilCard.isUselessCreature(ai, input))
return false;
- if (CounterType.M1M1.equals(type) && amount >= input.getNetToughness())
+ if (type.is(CounterEnumType.M1M1) && amount >= input.getNetToughness())
return true;
return ComputerUtil.isNegativeCounter(type, input);
}
@@ -947,6 +951,20 @@ public class CountersPutAi extends SpellAbilityAi {
CardCollection filtered = mine;
+ // Try to filter out keywords that we already have on cards
+ if (type.isKeywordCounter()) {
+ Keyword kw = Keyword.smartValueOf(type.getName());
+ final CardCollection doNotHaveKeyword = CardLists.filter(filtered, new Predicate() {
+ @Override
+ public boolean apply(Card card) {
+ return !card.hasKeyword(kw) && card.canBeTargetedBy(sa) && sa.canTarget(card);
+ }
+ });
+
+ if (doNotHaveKeyword.size() > 0)
+ filtered = doNotHaveKeyword;
+ }
+
final CardCollection notUseless = CardLists.filter(filtered, new Predicate() {
@Override
public boolean apply(Card input) {
@@ -961,26 +979,26 @@ public class CountersPutAi extends SpellAbilityAi {
}
// some special logic to reload Persist/Undying
- if (CounterType.P1P1.equals(type)) {
+ if (p1p1.equals(type)) {
final CardCollection persist = CardLists.filter(filtered, new Predicate() {
@Override
public boolean apply(Card input) {
if (!input.hasKeyword(Keyword.PERSIST))
return false;
- return input.getCounters(CounterType.M1M1) <= amount;
+ return input.getCounters(m1m1) <= amount;
}
});
if (!persist.isEmpty()) {
filtered = persist;
}
- } else if (CounterType.M1M1.equals(type)) {
+ } else if (m1m1.equals(type)) {
final CardCollection undying = CardLists.filter(filtered, new Predicate() {
@Override
public boolean apply(Card input) {
if (!input.hasKeyword(Keyword.UNDYING))
return false;
- return input.getCounters(CounterType.P1P1) <= amount && input.getNetToughness() > amount;
+ return input.getCounters(p1p1) <= amount && input.getNetToughness() > amount;
}
});
@@ -1003,8 +1021,8 @@ public class CountersPutAi extends SpellAbilityAi {
if (e instanceof Card) {
Card c = (Card) e;
if (c.getController().isOpponentOf(ai)) {
- if (options.contains(CounterType.M1M1) && !c.hasKeyword(Keyword.UNDYING)) {
- return CounterType.M1M1;
+ if (options.contains(CounterType.get(CounterEnumType.M1M1)) && !c.hasKeyword(Keyword.UNDYING)) {
+ return CounterType.get(CounterEnumType.M1M1);
}
for (CounterType type : options) {
if (ComputerUtil.isNegativeCounter(type, c)) {
@@ -1021,12 +1039,12 @@ public class CountersPutAi extends SpellAbilityAi {
} else if (e instanceof Player) {
Player p = (Player) e;
if (p.isOpponentOf(ai)) {
- if (options.contains(CounterType.POISON)) {
- return CounterType.POISON;
+ if (options.contains(CounterType.get(CounterEnumType.POISON))) {
+ return CounterType.get(CounterEnumType.POISON);
}
} else {
- if (options.contains(CounterType.EXPERIENCE)) {
- return CounterType.EXPERIENCE;
+ if (options.contains(CounterType.get(CounterEnumType.EXPERIENCE))) {
+ return CounterType.get(CounterEnumType.EXPERIENCE);
}
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java
index 4195a7924b7..a261270dec9 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java
@@ -6,12 +6,12 @@
* 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 .
*/
@@ -36,7 +36,7 @@ import java.util.Map;
*
* AbilityFactory_PutOrRemoveCountersAi class.
*
- *
+ *
* @author Forge
* @version $Id$
*/
@@ -44,7 +44,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see forge.ai.SpellAbilityAi#checkApiLogic(forge.game.player.Player,
* forge.game.spellability.SpellAbility)
*/
@@ -75,7 +75,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
if (sa.hasParam("CounterType")) {
// currently only Jhoira's Timebug
- final CounterType type = CounterType.valueOf(sa.getParam("CounterType"));
+ final CounterType type = CounterType.getType(sa.getParam("CounterType"));
CardCollection countersList = CardLists.filter(list, CardPredicates.hasCounter(type, amount));
@@ -100,7 +100,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
if (!ai.isCardInPlay("Marit Lage") || noLegendary) {
CardCollectionView depthsList = CardLists.filter(countersList,
- CardPredicates.nameEquals("Dark Depths"), CardPredicates.hasCounter(CounterType.ICE));
+ CardPredicates.nameEquals("Dark Depths"), CardPredicates.hasCounter(CounterEnumType.ICE));
if (!depthsList.isEmpty()) {
sa.getTargets().add(depthsList.getFirst());
@@ -113,7 +113,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
CardCollection planeswalkerList = CardLists.filter(
CardLists.filterControlledBy(countersList, ai.getOpponents()),
CardPredicates.Presets.PLANESWALKERS,
- CardPredicates.hasLessCounter(CounterType.LOYALTY, amount));
+ CardPredicates.hasLessCounter(CounterEnumType.LOYALTY, amount));
if (!planeswalkerList.isEmpty()) {
sa.getTargets().add(ComputerUtilCard.getBestPlaneswalkerAI(planeswalkerList));
@@ -123,7 +123,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
// do as M1M1 part
CardCollection aiList = CardLists.filterControlledBy(countersList, ai);
- CardCollection aiM1M1List = CardLists.filter(aiList, CardPredicates.hasCounter(CounterType.M1M1));
+ CardCollection aiM1M1List = CardLists.filter(aiList, CardPredicates.hasCounter(CounterEnumType.M1M1));
CardCollection aiPersistList = CardLists.getKeyword(aiM1M1List, Keyword.PERSIST);
if (!aiPersistList.isEmpty()) {
@@ -136,7 +136,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
}
// do as P1P1 part
- CardCollection aiP1P1List = CardLists.filter(aiList, CardPredicates.hasCounter(CounterType.P1P1));
+ CardCollection aiP1P1List = CardLists.filter(aiList, CardPredicates.hasCounter(CounterEnumType.P1P1));
CardCollection aiUndyingList = CardLists.getKeyword(aiM1M1List, Keyword.UNDYING);
if (!aiUndyingList.isEmpty()) {
@@ -183,7 +183,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see forge.ai.SpellAbilityAi#chooseCounterType(java.util.List,
* forge.game.spellability.SpellAbility, java.util.Map)
*/
@@ -199,18 +199,18 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
Card tgt = (Card) params.get("Target");
// planeswalker has high priority for loyalty counters
- if (tgt.isPlaneswalker() && options.contains(CounterType.LOYALTY)) {
- return CounterType.LOYALTY;
+ if (tgt.isPlaneswalker() && options.contains(CounterType.get(CounterEnumType.LOYALTY))) {
+ return CounterType.get(CounterEnumType.LOYALTY);
}
if (tgt.getController().isOpponentOf(ai)) {
// creatures with BaseToughness below or equal zero might be
// killed if their counters are removed
if (tgt.isCreature() && tgt.getBaseToughness() <= 0) {
- if (options.contains(CounterType.P1P1)) {
- return CounterType.P1P1;
- } else if (options.contains(CounterType.M1M1)) {
- return CounterType.M1M1;
+ if (options.contains(CounterType.get(CounterEnumType.P1P1))) {
+ return CounterType.get(CounterEnumType.P1P1);
+ } else if (options.contains(CounterType.get(CounterEnumType.M1M1))) {
+ return CounterType.get(CounterEnumType.M1M1);
}
}
@@ -222,14 +222,14 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
}
} else {
// this counters are treat first to be removed
- if ("Dark Depths".equals(tgt.getName()) && options.contains(CounterType.ICE)) {
+ if ("Dark Depths".equals(tgt.getName()) && options.contains(CounterType.get(CounterEnumType.ICE))) {
if (!ai.isCardInPlay("Marit Lage") || noLegendary) {
- return CounterType.ICE;
+ return CounterType.get(CounterEnumType.ICE);
}
- } else if (tgt.hasKeyword(Keyword.UNDYING) && options.contains(CounterType.P1P1)) {
- return CounterType.P1P1;
- } else if (tgt.hasKeyword(Keyword.PERSIST) && options.contains(CounterType.M1M1)) {
- return CounterType.M1M1;
+ } else if (tgt.hasKeyword(Keyword.UNDYING) && options.contains(CounterType.get(CounterEnumType.P1P1))) {
+ return CounterType.get(CounterEnumType.P1P1);
+ } else if (tgt.hasKeyword(Keyword.PERSIST) && options.contains(CounterType.get(CounterEnumType.M1M1))) {
+ return CounterType.get(CounterEnumType.M1M1);
}
// fallback logic, select positive counter to add more
@@ -246,7 +246,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see
* forge.ai.SpellAbilityAi#chooseBinary(forge.game.player.PlayerController.
* BinaryChoiceType, forge.game.spellability.SpellAbility, java.util.Map)
@@ -262,19 +262,19 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi {
boolean noLegendary = game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLegendRule);
if (tgt.getController().isOpponentOf(ai)) {
- if (type.equals(CounterType.LOYALTY) && tgt.isPlaneswalker()) {
+ if (type.is(CounterEnumType.LOYALTY) && tgt.isPlaneswalker()) {
return false;
}
return ComputerUtil.isNegativeCounter(type, tgt);
} else {
- if (type.equals(CounterType.ICE) && "Dark Depths".equals(tgt.getName())) {
+ if (type.is(CounterEnumType.ICE) && "Dark Depths".equals(tgt.getName())) {
if (!ai.isCardInPlay("Marit Lage") || noLegendary) {
return false;
}
- } else if (type.equals(CounterType.M1M1) && tgt.hasKeyword(Keyword.PERSIST)) {
+ } else if (type.is(CounterEnumType.M1M1) && tgt.hasKeyword(Keyword.PERSIST)) {
return false;
- } else if (type.equals(CounterType.P1P1) && tgt.hasKeyword(Keyword.UNDYING)) {
+ } else if (type.is(CounterEnumType.P1P1) && tgt.hasKeyword(Keyword.UNDYING)) {
return false;
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java
index 24a0ff0fa9d..2c4ad3bbfe0 100644
--- a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java
@@ -33,7 +33,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see
* forge.ai.SpellAbilityAi#checkPhaseRestrictions(forge.game.player.Player,
* forge.game.spellability.SpellAbility, forge.game.phase.PhaseHandler)
@@ -50,7 +50,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see
* forge.ai.SpellAbilityAi#checkPhaseRestrictions(forge.game.player.Player,
* forge.game.spellability.SpellAbility, forge.game.phase.PhaseHandler,
@@ -68,7 +68,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see forge.ai.SpellAbilityAi#checkApiLogic(forge.game.player.Player,
* forge.game.spellability.SpellAbility)
*/
@@ -82,7 +82,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
}
if (!type.matches("Any") && !type.matches("All")) {
- final int currCounters = sa.getHostCard().getCounters(CounterType.valueOf(type));
+ final int currCounters = sa.getHostCard().getCounters(CounterType.getType(type));
if (currCounters < 1) {
return false;
}
@@ -119,7 +119,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
if (!ai.isCardInPlay("Marit Lage") || noLegendary) {
CardCollectionView depthsList = ai.getCardsIn(ZoneType.Battlefield, "Dark Depths");
depthsList = CardLists.filter(depthsList, CardPredicates.isTargetableBy(sa),
- CardPredicates.hasCounter(CounterType.ICE, 3));
+ CardPredicates.hasCounter(CounterEnumType.ICE, 3));
if (!depthsList.isEmpty()) {
sa.getTargets().add(depthsList.getFirst());
@@ -132,7 +132,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
list = CardLists.filter(list, CardPredicates.isTargetableBy(sa));
CardCollection planeswalkerList = CardLists.filter(list, CardPredicates.Presets.PLANESWALKERS,
- CardPredicates.hasCounter(CounterType.LOYALTY, 5));
+ CardPredicates.hasCounter(CounterEnumType.LOYALTY, 5));
if (!planeswalkerList.isEmpty()) {
sa.getTargets().add(ComputerUtilCard.getBestPlaneswalkerAI(planeswalkerList));
@@ -159,11 +159,11 @@ public class CountersRemoveAi extends SpellAbilityAi {
if (!ai.isCardInPlay("Marit Lage") || noLegendary) {
CardCollectionView depthsList = ai.getCardsIn(ZoneType.Battlefield, "Dark Depths");
depthsList = CardLists.filter(depthsList, CardPredicates.isTargetableBy(sa),
- CardPredicates.hasCounter(CounterType.ICE));
+ CardPredicates.hasCounter(CounterEnumType.ICE));
if (!depthsList.isEmpty()) {
Card depth = depthsList.getFirst();
- int ice = depth.getCounters(CounterType.ICE);
+ int ice = depth.getCounters(CounterEnumType.ICE);
if (amount >= ice) {
sa.getTargets().add(depth);
if (xPay) {
@@ -180,7 +180,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
CardCollection planeswalkerList = CardLists.filter(list,
Predicates.and(CardPredicates.Presets.PLANESWALKERS, CardPredicates.isControlledByAnyOf(ai.getOpponents())),
- CardPredicates.hasLessCounter(CounterType.LOYALTY, amount));
+ CardPredicates.hasLessCounter(CounterEnumType.LOYALTY, amount));
if (!planeswalkerList.isEmpty()) {
Card best = ComputerUtilCard.getBestPlaneswalkerAI(planeswalkerList);
@@ -196,7 +196,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
// do as M1M1 part
CardCollection aiList = CardLists.filterControlledBy(list, ai);
- CardCollection aiM1M1List = CardLists.filter(aiList, CardPredicates.hasCounter(CounterType.M1M1));
+ CardCollection aiM1M1List = CardLists.filter(aiList, CardPredicates.hasCounter(CounterEnumType.M1M1));
CardCollection aiPersistList = CardLists.getKeyword(aiM1M1List, Keyword.PERSIST);
if (!aiPersistList.isEmpty()) {
@@ -209,7 +209,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
}
// do as P1P1 part
- CardCollection aiP1P1List = CardLists.filter(aiList, CardPredicates.hasLessCounter(CounterType.P1P1, amount));
+ CardCollection aiP1P1List = CardLists.filter(aiList, CardPredicates.hasLessCounter(CounterEnumType.P1P1, amount));
CardCollection aiUndyingList = CardLists.getKeyword(aiP1P1List, Keyword.UNDYING);
if (!aiUndyingList.isEmpty()) {
@@ -220,7 +220,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
// remove P1P1 counters from opposing creatures
CardCollection oppP1P1List = CardLists.filter(list,
Predicates.and(CardPredicates.Presets.CREATURES, CardPredicates.isControlledByAnyOf(ai.getOpponents())),
- CardPredicates.hasCounter(CounterType.P1P1));
+ CardPredicates.hasCounter(CounterEnumType.P1P1));
if (!oppP1P1List.isEmpty()) {
sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(oppP1P1List));
return true;
@@ -244,7 +244,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
// no special amount for that one yet
int amount = AbilityUtils.calculateAmount(source, amountStr, sa);
CardCollection aiList = CardLists.filterControlledBy(list, ai);
- aiList = CardLists.filter(aiList, CardPredicates.hasCounter(CounterType.M1M1, amount));
+ aiList = CardLists.filter(aiList, CardPredicates.hasCounter(CounterEnumType.M1M1, amount));
CardCollection aiPersist = CardLists.getKeyword(aiList, Keyword.PERSIST);
if (!aiPersist.isEmpty()) {
@@ -263,7 +263,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
// no special amount for that one yet
int amount = AbilityUtils.calculateAmount(source, amountStr, sa);
- list = CardLists.filter(list, CardPredicates.hasCounter(CounterType.P1P1, amount));
+ list = CardLists.filter(list, CardPredicates.hasCounter(CounterEnumType.P1P1, amount));
// currently only logic for Bloodcrazed Hoplite, but add logic for
// targeting ai creatures too
@@ -309,12 +309,12 @@ public class CountersRemoveAi extends SpellAbilityAi {
amount = AbilityUtils.calculateAmount(source, amountStr, sa);
}
- CardCollection timeList = CardLists.filter(list, CardPredicates.hasLessCounter(CounterType.TIME, amount));
+ CardCollection timeList = CardLists.filter(list, CardPredicates.hasLessCounter(CounterEnumType.TIME, amount));
if (!timeList.isEmpty()) {
Card best = ComputerUtilCard.getBestAI(timeList);
- int timeCount = best.getCounters(CounterType.TIME);
+ int timeCount = best.getCounters(CounterEnumType.TIME);
sa.getTargets().add(best);
if (xPay) {
source.setSVar("PayX", Integer.toString(timeCount));
@@ -335,7 +335,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
CardCollection outlastCreats = CardLists.filter(list, CardPredicates.hasKeyword(Keyword.OUTLAST));
if (!outlastCreats.isEmpty()) {
// outlast cards often benefit from having +1/+1 counters, try not to remove last one
- CardCollection betterTargets = CardLists.filter(outlastCreats, CardPredicates.hasCounter(CounterType.P1P1, 2));
+ CardCollection betterTargets = CardLists.filter(outlastCreats, CardPredicates.hasCounter(CounterEnumType.P1P1, 2));
if (!betterTargets.isEmpty()) {
sa.getTargets().add(ComputerUtilCard.getWorstAI(betterTargets));
@@ -363,7 +363,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see forge.ai.SpellAbilityAi#chooseNumber(forge.game.player.Player,
* forge.game.spellability.SpellAbility, int, int, java.util.Map)
*/
@@ -377,8 +377,8 @@ public class CountersRemoveAi extends SpellAbilityAi {
if (targetCard.getController().isOpponentOf(player)) {
return !ComputerUtil.isNegativeCounter(type, targetCard) ? max : min;
} else {
- if (targetCard.hasKeyword(Keyword.UNDYING) && type == CounterType.P1P1
- && targetCard.getCounters(CounterType.P1P1) >= max) {
+ if (targetCard.hasKeyword(Keyword.UNDYING) && type.is(CounterEnumType.P1P1)
+ && targetCard.getCounters(CounterEnumType.P1P1) >= max) {
return max;
}
@@ -387,9 +387,9 @@ public class CountersRemoveAi extends SpellAbilityAi {
} else if (target instanceof Player) {
Player targetPlayer = (Player) target;
if (targetPlayer.isOpponentOf(player)) {
- return !type.equals(CounterType.POISON) ? max : min;
+ return !type.equals(CounterEnumType.POISON) ? max : min;
} else {
- return type.equals(CounterType.POISON) ? max : min;
+ return type.equals(CounterEnumType.POISON) ? max : min;
}
}
@@ -398,7 +398,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
/*
* (non-Javadoc)
- *
+ *
* @see forge.ai.SpellAbilityAi#chooseCounterType(java.util.List,
* forge.game.spellability.SpellAbility, java.util.Map)
*/
@@ -415,7 +415,7 @@ public class CountersRemoveAi extends SpellAbilityAi {
if (targetCard.getController().isOpponentOf(ai)) {
// if its a Planeswalker try to remove Loyality first
if (targetCard.isPlaneswalker()) {
- return CounterType.LOYALTY;
+ return CounterType.get(CounterEnumType.LOYALTY);
}
for (CounterType type : options) {
if (!ComputerUtil.isNegativeCounter(type, targetCard)) {
@@ -423,10 +423,10 @@ public class CountersRemoveAi extends SpellAbilityAi {
}
}
} else {
- if (options.contains(CounterType.M1M1) && targetCard.hasKeyword(Keyword.PERSIST)) {
- return CounterType.M1M1;
- } else if (options.contains(CounterType.P1P1) && targetCard.hasKeyword(Keyword.UNDYING)) {
- return CounterType.P1P1;
+ if (options.contains(CounterType.get(CounterEnumType.M1M1)) && targetCard.hasKeyword(Keyword.PERSIST)) {
+ return CounterType.get(CounterEnumType.M1M1);
+ } else if (options.contains(CounterType.get(CounterEnumType.P1P1)) && targetCard.hasKeyword(Keyword.UNDYING)) {
+ return CounterType.get(CounterEnumType.P1P1);
}
for (CounterType type : options) {
if (ComputerUtil.isNegativeCounter(type, targetCard)) {
@@ -438,13 +438,13 @@ public class CountersRemoveAi extends SpellAbilityAi {
Player targetPlayer = (Player) target;
if (targetPlayer.isOpponentOf(ai)) {
for (CounterType type : options) {
- if (!type.equals(CounterType.POISON)) {
+ if (!type.equals(CounterEnumType.POISON)) {
return type;
}
}
} else {
for (CounterType type : options) {
- if (type.equals(CounterType.POISON)) {
+ if (type.equals(CounterEnumType.POISON)) {
return type;
}
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java
index e36a2a236dc..79e83ac65a4 100644
--- a/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java
@@ -6,7 +6,7 @@ import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.cost.Cost;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseType;
@@ -39,7 +39,7 @@ public class DamageAllAi extends SpellAbilityAi {
if (!ai.getGame().getStack().isEmpty()) {
return false;
}
-
+
int x = -1;
final String damage = sa.getParam("NumDmg");
int dmg = AbilityUtils.calculateAmount(sa.getHostCard(), damage, sa);
@@ -50,7 +50,7 @@ public class DamageAllAi extends SpellAbilityAi {
x = ComputerUtilMana.determineLeftoverMana(sa, ai);
}
if (damage.equals("ChosenX")) {
- x = source.getCounters(CounterType.LOYALTY);
+ x = source.getCounters(CounterEnumType.LOYALTY);
}
if (x == -1) {
if (determineOppToKill(ai, sa, source, dmg) != null) {
diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java
index 1a5e908a7a4..936e2187357 100644
--- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java
@@ -46,9 +46,9 @@ public class DamageDealAi extends DamageAiBase {
if ("MadSarkhanDigDmg".equals(logic)) {
return SpecialCardAi.SarkhanTheMad.considerDig(ai, sa);
}
-
+
if (damage.equals("X") && sa.getSVar(damage).equals("Count$ChosenNumber")) {
- int energy = ai.getCounters(CounterType.ENERGY);
+ int energy = ai.getCounters(CounterEnumType.ENERGY);
for (SpellAbility s : source.getSpellAbilities()) {
if ("PayEnergy".equals(s.getParam("AILogic"))) {
energy += AbilityUtils.calculateAmount(source, s.getParam("CounterNum"), sa);
@@ -145,7 +145,7 @@ public class DamageDealAi extends DamageAiBase {
if (sourceName.equals("Crater's Claws") && ai.hasFerocious()) {
dmg += 2;
}
-
+
String logic = sa.getParamOrDefault("AILogic", "");
if ("DiscardLands".equals(logic)) {
dmg = 2;
@@ -165,7 +165,7 @@ public class DamageDealAi extends DamageAiBase {
List wolves = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), "Creature.Wolf+untapped+YouCtrl+Other", ai, source);
dmg = Aggregates.sum(wolves, CardPredicates.Accessors.fnGetNetPower);
} else if ("Triskelion".equals(logic)) {
- final int n = source.getCounters(CounterType.P1P1);
+ final int n = source.getCounters(CounterEnumType.P1P1);
if (n > 0) {
if (ComputerUtil.playImmediately(ai, sa)) {
/*
@@ -196,9 +196,9 @@ public class DamageDealAi extends DamageAiBase {
}
return false;
}
-
+
if (sourceName.equals("Sorin, Grim Nemesis")) {
- int loyalty = source.getCounters(CounterType.LOYALTY);
+ int loyalty = source.getCounters(CounterEnumType.LOYALTY);
for (; loyalty > 0; loyalty--) {
if (this.damageTargetAI(ai, sa, loyalty, false)) {
dmg = ComputerUtilCombat.getEnoughDamageToKill(sa.getTargetCard(), loyalty, source, false, false);
@@ -228,7 +228,7 @@ public class DamageDealAi extends DamageAiBase {
if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source)) {
return false;
}
-
+
if ("DiscardLands".equals(sa.getParam("AILogic")) && !ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
return false;
}
@@ -309,7 +309,7 @@ public class DamageDealAi extends DamageAiBase {
*
* dealDamageChooseTgtC.
*
- *
+ *
* @param d
* a int.
* @param noPrevention
@@ -445,7 +445,7 @@ public class DamageDealAi extends DamageAiBase {
// As of right now, ranks planeswalkers by their Current Loyalty * 10 + Big buff if close to "Ultimate"
int bestScore = 0;
for (Card pw : pws) {
- int curLoyalty = pw.getCounters(CounterType.LOYALTY);
+ int curLoyalty = pw.getCounters(CounterEnumType.LOYALTY);
int pwScore = curLoyalty * 10;
for (SpellAbility sa : pw.getSpellAbilities()) {
@@ -478,7 +478,7 @@ public class DamageDealAi extends DamageAiBase {
int bestScore = Integer.MAX_VALUE;
for (Card pw : pws) {
- int curLoyalty = pw.getCounters(CounterType.LOYALTY);
+ int curLoyalty = pw.getCounters(CounterEnumType.LOYALTY);
if (curLoyalty < bestScore) {
bestScore = curLoyalty;
@@ -515,7 +515,7 @@ public class DamageDealAi extends DamageAiBase {
*
* damageTargetAI.
*
- *
+ *
* @param saMe
* a {@link forge.game.spellability.SpellAbility} object.
* @param dmg
@@ -543,7 +543,7 @@ public class DamageDealAi extends DamageAiBase {
*
* damageChoosingTargets.
*
- *
+ *
* @param sa
* a {@link forge.game.spellability.SpellAbility} object.
* @param tgt
@@ -587,7 +587,7 @@ public class DamageDealAi extends DamageAiBase {
if (tgt.getMaxTargets(source, sa) <= 0 && !logic.equals("AssumeAtLeastOneTarget")) {
return false;
}
-
+
immediately |= ComputerUtil.playImmediately(ai, sa);
if (!(sa.getParent() != null && sa.getParent().isTargetNumberValid())) {
@@ -623,7 +623,7 @@ public class DamageDealAi extends DamageAiBase {
continue;
}
final int assignedDamage = ComputerUtilCombat.getEnoughDamageToKill(humanCreature, dmg, source, false, noPrevention);
- if (assignedDamage <= dmg
+ if (assignedDamage <= dmg
&& humanCreature.getShieldCount() == 0 && !ComputerUtil.canRegenerate(humanCreature.getController(), humanCreature)) {
tcs.add(humanCreature);
tgt.addDividedAllocation(humanCreature, assignedDamage);
@@ -756,7 +756,7 @@ public class DamageDealAi extends DamageAiBase {
break;
}
}
-
+
} else if (tgt.canTgtCreature() || tgt.canTgtPlaneswalker()) {
final Card c = this.dealDamageChooseTgtC(ai, sa, dmg, noPrevention, enemy, mandatory);
if (c != null) {
@@ -825,8 +825,8 @@ public class DamageDealAi extends DamageAiBase {
*
* damageChooseNontargeted.
*
- * @param ai
- *
+ * @param ai
+ *
* @param saMe
* a {@link forge.game.spellability.SpellAbility} object.
* @param dmg
@@ -881,7 +881,7 @@ public class DamageDealAi extends DamageAiBase {
*
* damageChooseRequiredTargets.
*
- *
+ *
* @param sa
* a {@link forge.game.spellability.SpellAbility} object.
* @param tgt
@@ -1006,7 +1006,7 @@ public class DamageDealAi extends DamageAiBase {
// If I can kill my target by paying less mana, do it
int actualPay = 0;
final boolean noPrevention = sa.hasParam("NoPrevention");
-
+
//target is a player
if (!sa.getTargets().isTargetingAnyCard()) {
actualPay = dmg;
@@ -1037,15 +1037,15 @@ public class DamageDealAi extends DamageAiBase {
Player opponent = ai.getOpponents().min(PlayerPredicates.compareByLife());
- // TODO: somehow account for the possible cost reduction?
+ // TODO: somehow account for the possible cost reduction?
int dmg = ComputerUtilMana.determineLeftoverMana(sa, ai, saTgt.getParam("XColor"));
-
+
while (!ComputerUtilMana.canPayManaCost(sa, ai, dmg) && dmg > 0) {
// TODO: ideally should never get here, currently put here as a precaution for complex mana base cases where the miscalculation might occur. Will remove later if it proves to never trigger.
dmg--;
System.out.println("Warning: AI could not pay mana cost for a XLifeDrain logic spell. Reducing X value to "+dmg);
}
-
+
// set the color map for black X for the purpose of Soul Burn
// TODO: somehow generalize this calculation to allow other potential similar cards to function in the future
if ("Soul Burn".equals(sourceName)) {
@@ -1066,7 +1066,7 @@ public class DamageDealAi extends DamageAiBase {
int toughness = c.getNetToughness();
boolean canDie = !(c.hasKeyword(Keyword.INDESTRUCTIBLE) || ComputerUtil.canRegenerate(c.getController(), c));
- // Currently will target creatures with toughness 3+ (or power 5+)
+ // Currently will target creatures with toughness 3+ (or power 5+)
// and only if the creature can actually die, do not "underdrain"
// unless the creature has high power
if (canDie && toughness <= dmg && ((toughness == dmg && toughness >= 3) || power >= 5)) {
diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java
index 392c1c52e0c..8c3855385e6 100644
--- a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java
@@ -101,7 +101,7 @@ public class DestroyAi extends SpellAbilityAi {
return SpecialCardAi.SarkhanTheMad.considerMakeDragon(ai, sa);
} else if (logic != null && logic.startsWith("MinLoyalty.")) {
int minLoyalty = Integer.parseInt(logic.substring(logic.indexOf(".") + 1));
- if (source.getCounters(CounterType.LOYALTY) < minLoyalty) {
+ if (source.getCounters(CounterEnumType.LOYALTY) < minLoyalty) {
return false;
}
} else if ("Polymorph".equals(logic)) {
@@ -161,7 +161,7 @@ public class DestroyAi extends SpellAbilityAi {
return false;
}
//Check for undying
- return (!c.hasKeyword(Keyword.UNDYING) || c.getCounters(CounterType.P1P1) > 0);
+ return (!c.hasKeyword(Keyword.UNDYING) || c.getCounters(CounterEnumType.P1P1) > 0);
}
});
}
@@ -388,7 +388,7 @@ public class DestroyAi extends SpellAbilityAi {
if (CardLists.getNotType(list, "Creature").isEmpty()) {
if (!sa.getUniqueTargets().isEmpty() && sa.getParent().getApi() == ApiType.Destroy
&& sa.getUniqueTargets().get(0) instanceof Card) {
- // basic ai for Diaochan
+ // basic ai for Diaochan
c = (Card) sa.getUniqueTargets().get(0);
} else {
c = ComputerUtilCard.getWorstCreatureAI(list);
@@ -413,7 +413,7 @@ public class DestroyAi extends SpellAbilityAi {
Player tgtPlayer = tgtLand.getController();
int oppLandsOTB = tgtPlayer.getLandsInPlay().size();
-
+
// AI profile-dependent properties
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
int amountNoTempoCheck = aic.getIntProperty(AiProps.STRIPMINE_MIN_LANDS_OTB_FOR_NO_TEMPO_CHECK);
@@ -436,7 +436,7 @@ public class DestroyAi extends SpellAbilityAi {
// Non-basic lands are currently not ranked in any way in ComputerUtilCard#getBestLandAI, so if a non-basic land is best target,
// consider killing it off unless there's too much potential tempo loss.
- // TODO: actually rank non-basics in that method and then kill off the potentially dangerous (manlands, Valakut) or lucrative
+ // TODO: actually rank non-basics in that method and then kill off the potentially dangerous (manlands, Valakut) or lucrative
// (dual/triple mana that opens access to a certain color) lands
boolean nonBasicTgt = !tgtLand.isBasicLand();
@@ -448,7 +448,7 @@ public class DestroyAi extends SpellAbilityAi {
boolean isHighPriority = highPriorityIfNoLandDrop && oppSkippedLandDrop;
boolean timingCheck = canManaLock || canColorLock || nonBasicTgt;
- boolean tempoCheck = numLandsOTB >= amountNoTempoCheck
+ boolean tempoCheck = numLandsOTB >= amountNoTempoCheck
|| ((numLandsInHand >= amountLandsInHand || isHighPriority) && ((numLandsInHand + numLandsOTB >= amountNoTimingCheck) || timingCheck));
// For Ghost Quarter, only use it if you have either more lands in play than your opponent
diff --git a/forge-ai/src/main/java/forge/ai/ability/DigAi.java b/forge-ai/src/main/java/forge/ai/ability/DigAi.java
index b8b13d18fd3..7099250d925 100644
--- a/forge-ai/src/main/java/forge/ai/ability/DigAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/DigAi.java
@@ -1,5 +1,7 @@
package forge.ai.ability;
+import java.util.Map;
+
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@@ -132,7 +134,7 @@ public class DigAi extends SpellAbilityAi {
}
@Override
- public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable valid, boolean isOptional, Player relatedPlayer) {
+ public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable valid, boolean isOptional, Player relatedPlayer, Map params) {
if ("DigForCreature".equals(sa.getParam("AILogic"))) {
Card bestChoice = ComputerUtilCard.getBestCreatureAI(valid);
if (bestChoice == null) {
@@ -163,7 +165,7 @@ public class DigAi extends SpellAbilityAi {
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayer(forge.game.player.Player, forge.card.spellability.SpellAbility, java.util.List)
*/
@Override
- public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options) {
+ public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) {
// an opponent choose a card from
return Iterables.getFirst(options, null);
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java
index 6fbe29ccdd1..4047d12ee77 100644
--- a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java
@@ -25,6 +25,7 @@ import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.cost.*;
import forge.game.phase.PhaseHandler;
@@ -348,7 +349,7 @@ public class DrawAi extends SpellAbilityAi {
}
// try to make opponent lose to poison
// currently only Caress of Phyrexia
- if (getPoison != null && oppA.canReceiveCounters(CounterType.POISON)) {
+ if (getPoison != null && oppA.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
if (oppA.getPoisonCounters() + numCards > 9) {
sa.getTargets().add(oppA);
return true;
@@ -392,7 +393,7 @@ public class DrawAi extends SpellAbilityAi {
}
}
- if (getPoison != null && ai.canReceiveCounters(CounterType.POISON)) {
+ if (getPoison != null && ai.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
if (numCards + ai.getPoisonCounters() >= 8) {
aiTarget = false;
}
@@ -451,7 +452,7 @@ public class DrawAi extends SpellAbilityAi {
}
// ally would lose because of poison
- if (getPoison != null && ally.canReceiveCounters(CounterType.POISON)) {
+ if (getPoison != null && ally.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
if (ally.getPoisonCounters() + numCards > 9) {
continue;
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java b/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java
index fcfe5c957ba..53587f59cd6 100644
--- a/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/EncodeAi.java
@@ -18,6 +18,7 @@
package forge.ai.ability;
import java.util.List;
+import java.util.Map;
import com.google.common.base.Predicate;
@@ -84,7 +85,7 @@ public final class EncodeAi extends SpellAbilityAi {
* forge.game.player.Player)
*/
@Override
- public Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ public Card chooseSingleCard(final Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
return chooseCard(ai, options, isOptional);
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/LegendaryRuleAi.java b/forge-ai/src/main/java/forge/ai/ability/LegendaryRuleAi.java
index 87e9d2d9464..4ad913b7a25 100644
--- a/forge-ai/src/main/java/forge/ai/ability/LegendaryRuleAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/LegendaryRuleAi.java
@@ -1,9 +1,11 @@
package forge.ai.ability;
+import java.util.Map;
+
import com.google.common.collect.Iterables;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -23,7 +25,7 @@ public class LegendaryRuleAi extends SpellAbilityAi {
@Override
- public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
// Choose a single legendary/planeswalker card to keep
Card firstOption = Iterables.getFirst(options, null);
boolean choosingFromPlanewalkers = firstOption.isPlaneswalker();
@@ -38,16 +40,16 @@ public class LegendaryRuleAi extends SpellAbilityAi {
if (firstOption.getName().equals("Dark Depths")) {
Card best = firstOption;
for (Card c : options) {
- if (c.getCounters(CounterType.ICE) < best.getCounters(CounterType.ICE)) {
+ if (c.getCounters(CounterEnumType.ICE) < best.getCounters(CounterEnumType.ICE)) {
best = c;
}
}
return best;
- } else if (firstOption.getCounters(CounterType.KI) > 0) {
+ } else if (firstOption.getCounters(CounterEnumType.KI) > 0) {
// Extra Rule for KI counter
Card best = firstOption;
for (Card c : options) {
- if (c.getCounters(CounterType.KI) > best.getCounters(CounterType.KI)) {
+ if (c.getCounters(CounterEnumType.KI) > best.getCounters(CounterEnumType.KI)) {
best = c;
}
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/LifeSetAi.java b/forge-ai/src/main/java/forge/ai/ability/LifeSetAi.java
index cc4d851bd9b..2afc4b47137 100644
--- a/forge-ai/src/main/java/forge/ai/ability/LifeSetAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/LifeSetAi.java
@@ -5,7 +5,7 @@ import forge.ai.ComputerUtilMana;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -130,7 +130,7 @@ public class LifeSetAi extends SpellAbilityAi {
}
if (sourceName.equals("Eternity Vessel")
- && (opponent.isCardInPlay("Vampire Hexmage") || (source.getCounters(CounterType.CHARGE) == 0))) {
+ && (opponent.isCardInPlay("Vampire Hexmage") || (source.getCounters(CounterEnumType.CHARGE) == 0))) {
return false;
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java b/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java
index 6158b777e9b..80f7b916f11 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java
@@ -120,7 +120,7 @@ public class ManaEffectAi extends SpellAbilityAi {
int manaSurplus = 0;
if ("XChoice".equals(host.getSVar("X"))
&& sa.getPayCosts().hasSpecificCostType(CostRemoveCounter.class)) {
- CounterType ctrType = CounterType.KI; // Petalmane Baku
+ CounterType ctrType = CounterType.get(CounterEnumType.KI); // Petalmane Baku
for (CostPart part : sa.getPayCosts().getCostParts()) {
if (part instanceof CostRemoveCounter) {
ctrType = ((CostRemoveCounter)part).counter;
diff --git a/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java b/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java
index 925f8ce02a1..fe921f05e72 100644
--- a/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/MustBlockAi.java
@@ -18,6 +18,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.List;
+import java.util.Map;
public class MustBlockAi extends SpellAbilityAi {
@@ -167,7 +168,7 @@ public class MustBlockAi extends SpellAbilityAi {
@Override
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional,
- Player targetedPlayer) {
+ Player targetedPlayer, Map params) {
final Card host = sa.getHostCard();
Card attacker = host;
diff --git a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java
index 3d5922a9122..7168f4c911e 100644
--- a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java
@@ -20,6 +20,7 @@ import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.List;
+import java.util.Map;
public class PlayAi extends SpellAbilityAi {
@@ -88,7 +89,7 @@ public class PlayAi extends SpellAbilityAi {
minCMC = sa.getPayCosts().getTotalMana().getCMC();
}
validOpts = CardLists.filter(validOpts, CardPredicates.greaterCMC(minCMC));
- return chooseSingleCard(ai, sa, validOpts, sa.hasParam("Optional"), null) != null;
+ return chooseSingleCard(ai, sa, validOpts, sa.hasParam("Optional"), null, null) != null;
}
if (source != null && source.hasKeyword(Keyword.HIDEAWAY) && source.hasRemembered()) {
@@ -142,8 +143,7 @@ public class PlayAi extends SpellAbilityAi {
*/
@Override
public Card chooseSingleCard(final Player ai, final SpellAbility sa, Iterable options,
- final boolean isOptional,
- Player targetedPlayer) {
+ final boolean isOptional, Player targetedPlayer, Map params) {
List tgtCards = CardLists.filter(options, new Predicate() {
@Override
public boolean apply(final Card c) {
diff --git a/forge-ai/src/main/java/forge/ai/ability/PoisonAi.java b/forge-ai/src/main/java/forge/ai/ability/PoisonAi.java
index 0eba3082f50..5761c79832c 100644
--- a/forge-ai/src/main/java/forge/ai/ability/PoisonAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/PoisonAi.java
@@ -5,6 +5,7 @@ import com.google.common.base.Predicate;
import forge.ai.ComputerUtil;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -59,7 +60,7 @@ public class PoisonAi extends SpellAbilityAi {
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
if (sa.usesTargeting()) {
return tgtPlayer(ai, sa, mandatory);
- } else if (mandatory || !ai.canReceiveCounters(CounterType.POISON)) {
+ } else if (mandatory || !ai.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
// mandatory or ai is uneffected
return true;
} else {
@@ -92,7 +93,7 @@ public class PoisonAi extends SpellAbilityAi {
public boolean apply(Player input) {
if (input.cantLose()) {
return false;
- } else if (!input.canReceiveCounters(CounterType.POISON)) {
+ } else if (!input.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
return false;
}
return true;
@@ -113,7 +114,7 @@ public class PoisonAi extends SpellAbilityAi {
if (tgts.isEmpty()) {
if (mandatory) {
// AI is uneffected
- if (ai.canBeTargetedBy(sa) && ai.canReceiveCounters(CounterType.POISON)) {
+ if (ai.canBeTargetedBy(sa) && ai.canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
sa.getTargets().add(ai);
return true;
}
@@ -127,7 +128,7 @@ public class PoisonAi extends SpellAbilityAi {
if (input.cantLose()) {
return true;
}
- return !input.canReceiveCounters(CounterType.POISON);
+ return !input.canReceiveCounters(CounterType.get(CounterEnumType.POISON));
}
});
diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java
index af93f8a1b72..ced79a57318 100644
--- a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java
@@ -150,7 +150,7 @@ public class PumpAi extends PumpAiBase {
}
final String counterType = moveSA.getParam("CounterType");
- final CounterType cType = "Any".equals(counterType) ? null : CounterType.valueOf(counterType);
+ final CounterType cType = "Any".equals(counterType) ? null : CounterType.getType(counterType);
final PhaseHandler ph = game.getPhaseHandler();
if (ph.inCombat() && ph.getPlayerTurn().isOpponentOf(ai)) {
@@ -185,7 +185,7 @@ public class PumpAi extends PumpAiBase {
// cant use substract on Copy
srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount);
- if (CounterType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) {
+ if (CounterEnumType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) {
return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING)
|| card.isToken();
}
@@ -235,7 +235,7 @@ public class PumpAi extends PumpAiBase {
// cant use substract on Copy
srcCardCpy.setCounters(cType, srcCardCpy.getCounters(cType) - amount);
- if (CounterType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) {
+ if (CounterEnumType.P1P1.equals(cType) && srcCardCpy.getNetToughness() <= 0) {
return srcCardCpy.getCounters(cType) > 0 || !card.hasKeyword(Keyword.UNDYING)
|| card.isToken();
}
@@ -402,7 +402,7 @@ public class PumpAi extends PumpAiBase {
if ("DebuffForXCounters".equals(sa.getParam("AILogic")) && sa.getTargetCard() != null) {
// e.g. Skullmane Baku
- CounterType ctrType = CounterType.KI;
+ CounterType ctrType = CounterType.get(CounterEnumType.KI);
for (CostPart part : sa.getPayCosts().getCostParts()) {
if (part instanceof CostRemoveCounter) {
ctrType = ((CostRemoveCounter)part).counter;
@@ -730,7 +730,7 @@ public class PumpAi extends PumpAiBase {
final String numAttack = sa.hasParam("NumAtt") ? sa.getParam("NumAtt") : "";
if (numDefense.equals("-X") && sa.getSVar("X").equals("Count$ChosenNumber")) {
- int energy = ai.getCounters(CounterType.ENERGY);
+ int energy = ai.getCounters(CounterEnumType.ENERGY);
for (SpellAbility s : source.getSpellAbilities()) {
if ("PayEnergy".equals(s.getParam("AILogic"))) {
energy += AbilityUtils.calculateAmount(source, s.getParam("CounterNum"), sa);
@@ -860,7 +860,7 @@ public class PumpAi extends PumpAiBase {
final boolean isInfect = source.hasKeyword(Keyword.INFECT); // Flesh-Eater Imp
int lethalDmg = isInfect ? 10 - defPlayer.getPoisonCounters() : defPlayer.getLife();
- if (isInfect && !combat.getDefenderByAttacker(source).canReceiveCounters(CounterType.POISON)) {
+ if (isInfect && !combat.getDefenderByAttacker(source).canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
lethalDmg = Integer.MAX_VALUE; // won't be able to deal poison damage to kill the opponent
}
@@ -976,7 +976,7 @@ public class PumpAi extends PumpAiBase {
final boolean isInfect = source.hasKeyword(Keyword.INFECT);
int lethalDmg = isInfect ? 10 - defPlayer.getPoisonCounters() : defPlayer.getLife();
- if (isInfect && !combat.getDefenderByAttacker(source).canReceiveCounters(CounterType.POISON)) {
+ if (isInfect && !combat.getDefenderByAttacker(source).canReceiveCounters(CounterType.get(CounterEnumType.POISON))) {
lethalDmg = Integer.MAX_VALUE; // won't be able to deal poison damage to kill the opponent
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/RepeatEachAi.java b/forge-ai/src/main/java/forge/ai/ability/RepeatEachAi.java
index 8ba1494b666..e357ff98b0f 100644
--- a/forge-ai/src/main/java/forge/ai/ability/RepeatEachAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/RepeatEachAi.java
@@ -16,6 +16,7 @@ import forge.game.zone.ZoneType;
import forge.util.TextUtil;
import java.util.List;
+import java.util.Map;
public class RepeatEachAi extends SpellAbilityAi {
@@ -118,7 +119,7 @@ public class RepeatEachAi extends SpellAbilityAi {
}
@Override
- protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer) {
+ protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) {
return ComputerUtilCard.getBestCreatureAI(options);
}
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/ScryAi.java b/forge-ai/src/main/java/forge/ai/ability/ScryAi.java
index 1733c7eaee7..2ec63fb82ac 100644
--- a/forge-ai/src/main/java/forge/ai/ability/ScryAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/ScryAi.java
@@ -99,7 +99,7 @@ public class ScryAi extends SpellAbilityAi {
} else if ("BrainJar".equals(aiLogic)) {
final Card source = sa.getHostCard();
- int counterNum = source.getCounters(CounterType.CHARGE);
+ int counterNum = source.getCounters(CounterEnumType.CHARGE);
// no need for logic
if (counterNum == 0) {
return false;
diff --git a/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java b/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java
index 7e03c1cf0f5..ca7404dee76 100644
--- a/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java
@@ -248,7 +248,7 @@ public class SetStateAi extends SpellAbilityAi {
final Card othercard = aiPlayer.getCardsIn(ZoneType.Battlefield, other.getName()).getFirst();
// for legendary KI counter creatures
- if (othercard.getCounters(CounterType.KI) >= source.getCounters(CounterType.KI)) {
+ if (othercard.getCounters(CounterEnumType.KI) >= source.getCounters(CounterEnumType.KI)) {
// if the other legendary is useless try to replace it
return ComputerUtilCard.isUselessCreature(aiPlayer, othercard);
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/TapAi.java b/forge-ai/src/main/java/forge/ai/ability/TapAi.java
index a4eb933dbe4..54da422ee87 100644
--- a/forge-ai/src/main/java/forge/ai/ability/TapAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/TapAi.java
@@ -3,6 +3,7 @@ package forge.ai.ability;
import forge.ai.*;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.cost.Cost;
import forge.game.cost.CostPart;
@@ -68,7 +69,7 @@ public class TapAi extends TapAiBase {
} else {
if ("TapForXCounters".equals(sa.getParam("AILogic"))) {
// e.g. Waxmane Baku
- CounterType ctrType = CounterType.KI;
+ CounterType ctrType = CounterType.get(CounterEnumType.KI);
for (CostPart part : sa.getPayCosts().getCostParts()) {
if (part instanceof CostRemoveCounter) {
ctrType = ((CostRemoveCounter)part).counter;
diff --git a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java
index 5af081fbdaa..f6a62f567ef 100644
--- a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java
@@ -1,5 +1,7 @@
package forge.ai.ability;
+import java.util.Map;
+
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.*;
@@ -296,7 +298,7 @@ public class TokenAi extends SpellAbilityAi {
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayer(forge.game.player.Player, forge.card.spellability.SpellAbility, Iterable options)
*/
@Override
- protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options) {
+ protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) {
Combat combat = ai.getGame().getCombat();
// TokenAttacking
if (combat != null && sa.hasParam("TokenAttacking")) {
@@ -314,7 +316,7 @@ public class TokenAi extends SpellAbilityAi {
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayerOrPlaneswalker(forge.game.player.Player, forge.card.spellability.SpellAbility, Iterable options)
*/
@Override
- protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options) {
+ protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) {
Combat combat = ai.getGame().getCombat();
// TokenAttacking
if (combat != null && sa.hasParam("TokenAttacking")) {
diff --git a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java
index 16170b99919..be7eb4f2ae9 100644
--- a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java
@@ -24,6 +24,7 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.List;
+import java.util.Map;
public class UntapAi extends SpellAbilityAi {
@Override
@@ -311,7 +312,7 @@ public class UntapAi extends SpellAbilityAi {
}
@Override
- public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable list, boolean isOptional, Player targetedPlayer) {
+ public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable list, boolean isOptional, Player targetedPlayer, Map params) {
PlayerCollection pl = new PlayerCollection();
pl.add(ai);
pl.addAll(ai.getAllies());
diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java
index 903f6e474a9..1fac17f367a 100644
--- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java
+++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java
@@ -76,7 +76,7 @@ public class GameCopier {
newPlayer.addSpellCastThisTurn();
for (int j = 0; j < origPlayer.getLandsPlayedThisTurn(); j++)
newPlayer.addLandPlayedThisTurn();
- newPlayer.setCounters(Maps.newEnumMap(origPlayer.getCounters()));
+ newPlayer.setCounters(Maps.newHashMap(origPlayer.getCounters()));
newPlayer.setLifeLostLastTurn(origPlayer.getLifeLostLastTurn());
newPlayer.setLifeLostThisTurn(origPlayer.getLifeLostThisTurn());
newPlayer.setPreventNextDamage(origPlayer.getPreventNextDamage());
@@ -328,7 +328,7 @@ public class GameCopier {
Map counters = c.getCounters();
if (!counters.isEmpty()) {
- newCard.setCounters(Maps.newEnumMap(counters));
+ newCard.setCounters(Maps.newHashMap(counters));
}
if (c.getChosenPlayer() != null) {
newCard.setChosenPlayer(playerMap.get(c.getChosenPlayer()));
diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java b/forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java
index f2d0f01bf85..e3dc9e8a64c 100644
--- a/forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java
+++ b/forge-ai/src/main/java/forge/ai/simulation/GameStateEvaluator.java
@@ -3,7 +3,7 @@ package forge.ai.simulation;
import forge.ai.CreatureEvaluator;
import forge.game.Game;
import forge.game.card.Card;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
@@ -154,7 +154,7 @@ public class GameStateEvaluator {
// e.g. a 5 CMC permanent results in 200, whereas a 5/5 creature is ~225
int value = 50 + 30 * c.getCMC();
if (c.isPlaneswalker()) {
- value += 2 * c.getCounters(CounterType.LOYALTY);
+ value += 2 * c.getCounters(CounterEnumType.LOYALTY);
}
return value;
}
diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java
index be845713549..6456b345b3d 100644
--- a/forge-game/src/main/java/forge/game/GameAction.java
+++ b/forge-game/src/main/java/forge/game/GameAction.java
@@ -36,7 +36,6 @@ import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
-import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityPredicates;
import forge.game.staticability.StaticAbility;
@@ -180,6 +179,10 @@ public class GameAction {
if (lastKnownInfo == null) {
lastKnownInfo = CardUtil.getLKICopy(c);
}
+
+ if (!lastKnownInfo.hasKeyword("Counters remain on CARDNAME as it moves to any zone other than a player's hand or library.") || zoneTo.is(ZoneType.Hand) || zoneTo.is(ZoneType.Library)) {
+ copied.clearCounters();
+ }
} else {
// if from Battlefield to Graveyard and Card does exist in LastStateBattlefield
// use that instead
@@ -228,17 +231,14 @@ public class GameAction {
for (final StaticAbility sa : copied.getStaticAbilities()) {
sa.setHostCard(copied);
}
- if (c.getName().equals("Skullbriar, the Walking Grave")) {
- copied.setCounters(c.getCounters());
- }
-
- // ensure that any leftover keyword/type changes are cleared in the state view
- copied.updateStateForView();
} else { //Token
copied = c;
}
}
+ // ensure that any leftover keyword/type changes are cleared in the state view
+ copied.updateStateForView();
+
// Clean up temporary variables such as Sunburst value or announced PayX value
if (!(zoneTo.is(ZoneType.Stack) || zoneTo.is(ZoneType.Battlefield))) {
copied.clearTemporaryVars();
@@ -421,13 +421,6 @@ public class GameAction {
return copied;
}
- // remove all counters from the card if destination is not the battlefield
- // UNLESS we're dealing with Skullbriar, the Walking Grave
- if (!c.isToken() && (zoneTo.is(ZoneType.Hand) || zoneTo.is(ZoneType.Library) ||
- (!toBattlefield && !c.getName().equals("Skullbriar, the Walking Grave")))) {
- copied.clearCounters();
- }
-
if (!c.isToken() && !toBattlefield) {
copied.clearDevoured();
copied.clearDelved();
@@ -1030,8 +1023,10 @@ public class GameAction {
checkAgain |= stateBasedAction704_5r(c); // annihilate +1/+1 counters with -1/-1 ones
- if (c.getCounters(CounterType.DREAM) > 7 && c.hasKeyword("CARDNAME can't have more than seven dream counters on it.")) {
- c.subtractCounter(CounterType.DREAM, c.getCounters(CounterType.DREAM) - 7);
+ final CounterType dreamType = CounterType.get(CounterEnumType.DREAM);
+
+ if (c.getCounters(dreamType) > 7 && c.hasKeyword("CARDNAME can't have more than seven dream counters on it.")) {
+ c.subtractCounter(dreamType, c.getCounters(dreamType) - 7);
checkAgain = true;
}
}
@@ -1123,7 +1118,7 @@ public class GameAction {
if (!c.canBeSacrificed()) {
return false;
}
- if (c.getCounters(CounterType.LORE) < c.getFinalChapterNr()) {
+ if (c.getCounters(CounterEnumType.LORE) < c.getFinalChapterNr()) {
return false;
}
if (!game.getStack().hasSimultaneousStackEntries() &&
@@ -1164,16 +1159,18 @@ public class GameAction {
private boolean stateBasedAction704_5r(Card c) {
boolean checkAgain = false;
- int plusOneCounters = c.getCounters(CounterType.P1P1);
- int minusOneCounters = c.getCounters(CounterType.M1M1);
+ final CounterType p1p1 = CounterType.get(CounterEnumType.P1P1);
+ final CounterType m1m1 = CounterType.get(CounterEnumType.M1M1);
+ int plusOneCounters = c.getCounters(p1p1);
+ int minusOneCounters = c.getCounters(m1m1);
if (plusOneCounters > 0 && minusOneCounters > 0) {
int remove = Math.min(plusOneCounters, minusOneCounters);
// If a permanent has both a +1/+1 counter and a -1/-1 counter on it,
// N +1/+1 and N -1/-1 counters are removed from it, where N is the
// smaller of the number of +1/+1 and -1/-1 counters on it.
// This should fire remove counters trigger
- c.subtractCounter(CounterType.P1P1, remove);
- c.subtractCounter(CounterType.M1M1, remove);
+ c.subtractCounter(p1p1, remove);
+ c.subtractCounter(m1m1, remove);
checkAgain = true;
}
return checkAgain;
@@ -1294,7 +1291,7 @@ public class GameAction {
//final Multimap uniqueWalkers = ArrayListMultimap.create(); // Not used as of Ixalan
for (Card c : list) {
- if (c.getCounters(CounterType.LOYALTY) <= 0) {
+ if (c.getCounters(CounterEnumType.LOYALTY) <= 0) {
sacrificeDestroy(c, null, table);
// Play the Destroy sound
game.fireEvent(new GameEventCardDestroyed());
@@ -1354,7 +1351,8 @@ public class GameAction {
recheck = true;
- Card toKeep = p.getController().chooseSingleEntityForEffect(new CardCollection(cc), new AbilitySub(ApiType.InternalLegendaryRule, null, null, null), "You have multiple legendary permanents named \""+name+"\" in play.\n\nChoose the one to stay on battlefield (the rest will be moved to graveyard)");
+ Card toKeep = p.getController().chooseSingleEntityForEffect(new CardCollection(cc), new SpellAbility.EmptySa(ApiType.InternalLegendaryRule, null, p),
+ "You have multiple legendary permanents named \""+name+"\" in play.\n\nChoose the one to stay on battlefield (the rest will be moved to graveyard)", null);
for (Card c: cc) {
if (c != toKeep) {
sacrificeDestroy(c, null, table);
diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java
index f9c54617a94..28b6a51e0f3 100644
--- a/forge-game/src/main/java/forge/game/GameActionUtil.java
+++ b/forge-game/src/main/java/forge/game/GameActionUtil.java
@@ -472,7 +472,7 @@ public final class GameActionUtil {
CardFactoryUtil.setupETBReplacementAbility(saAb);
String desc = "It enters the battlefield with ";
- desc += Lang.nounWithNumeral(v, CounterType.P1P1.getName() + " counter");
+ desc += Lang.nounWithNumeral(v, CounterEnumType.P1P1.getName() + " counter");
desc += " on it.";
String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
diff --git a/forge-game/src/main/java/forge/game/GameEntity.java b/forge-game/src/main/java/forge/game/GameEntity.java
index f042378ec64..cbd00a9144f 100644
--- a/forge-game/src/main/java/forge/game/GameEntity.java
+++ b/forge-game/src/main/java/forge/game/GameEntity.java
@@ -24,6 +24,7 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardDamageMap;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.event.GameEventCardAttachment;
import forge.game.keyword.Keyword;
@@ -38,6 +39,7 @@ import forge.util.collect.FCollection;
import java.util.Map;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -48,7 +50,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
private int preventNextDamage = 0;
protected CardCollection attachedCards;
private Map> preventionShieldsWithEffects = Maps.newTreeMap();
- protected Map counters = Maps.newEnumMap(CounterType.class);
+ protected Map counters = Maps.newTreeMap();
protected GameEntity(int id0) {
id = id0;
@@ -315,7 +317,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
}
// enchanted means attached by Aura
- return CardLists.count(attachedCards, CardPredicates.Presets.AURA) > 0;
+ return Iterables.any(attachedCards, CardPredicates.Presets.AURA);
}
public final boolean hasCardAttachment(Card c) {
@@ -453,6 +455,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
return value == null ? 0 : value;
}
+ public final int getCounters(final CounterEnumType counterType) {
+ return getCounters(CounterType.get(counterType));
+ }
+
public void setCounters(final CounterType counterType, final Integer num) {
if (num <= 0) {
counters.remove(counterType);
@@ -461,6 +467,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
}
}
+ public void setCounters(final CounterEnumType counterType, final Integer num) {
+ setCounters(CounterType.get(counterType), num);
+ }
+
abstract public void setCounters(final Map allCounters);
abstract public boolean canReceiveCounters(final CounterType type);
@@ -468,6 +478,16 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
abstract public void subtractCounter(final CounterType counterName, final int n);
abstract public void clearCounters();
+ public boolean canReceiveCounters(final CounterEnumType type) {
+ return canReceiveCounters(CounterType.get(type));
+ }
+
+ public int addCounter(final CounterEnumType counterType, final int n, final Player source, final boolean applyMultiplier, final boolean fireEvents, GameEntityCounterTable table) {
+ return addCounter(CounterType.get(counterType), n, source, applyMultiplier, fireEvents, table);
+ }
+ public void subtractCounter(final CounterEnumType counterName, final int n) {
+ subtractCounter(CounterType.get(counterName), n);
+ }
@Override
public final boolean equals(Object o) {
diff --git a/forge-game/src/main/java/forge/game/GameLogFormatter.java b/forge-game/src/main/java/forge/game/GameLogFormatter.java
index f098cb088e7..cb83ff742e6 100644
--- a/forge-game/src/main/java/forge/game/GameLogFormatter.java
+++ b/forge-game/src/main/java/forge/game/GameLogFormatter.java
@@ -95,7 +95,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base {
String action = event.sa.isSpell() ? localizer.getMessage("lblCast")
: event.sa.isTrigger() ? localizer.getMessage("lblTriggered")
: localizer.getMessage("lblActivated");
- String object = event.sa.getStackDescription().startsWith("Morph ")
+ String object = event.si.getStackDescription().startsWith("Morph ")
? localizer.getMessage("lblMorph")
: event.sa.getHostCard().toString();
diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java
index 5005ecb07b2..331a181c550 100644
--- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java
+++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java
@@ -53,8 +53,9 @@ public class AbilityUtils {
if ("ReplacedCounterType".equals(name)) {
name = (String) sa.getReplacingObject(AbilityKey.CounterType);
}
- try {
+ //try {
counterType = CounterType.getType(name);
+ /*
} catch (Exception e) {
String type = sa.getSVar(name);
if (type.equals("")) {
@@ -66,6 +67,7 @@ public class AbilityUtils {
}
counterType = CounterType.getType(type);
}
+ //*/
return counterType;
}
diff --git a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java
index 0dbd45f1a43..ae557bfd3fe 100644
--- a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java
@@ -13,6 +13,7 @@ import com.google.common.collect.Lists;
import forge.GameCommand;
import forge.card.CardType;
import forge.game.Game;
+import forge.game.GameEntity;
import forge.game.GameObject;
import forge.game.card.Card;
import forge.game.card.CardCollection;
@@ -34,7 +35,7 @@ import forge.util.collect.FCollection;
*
* AbilityFactory_AlterLife class.
*
- *
+ *
* @author Forge
* @version $Id: AbilityFactoryAlterLife.java 17656 2012-10-22 19:32:56Z Max mtg $
*/
@@ -93,7 +94,7 @@ public abstract class SpellAbilityEffect {
final String baseDesc = this.getStackDescription(sa);
if (conditionDesc != null) {
sb.append(conditionDesc).append(" ");
- }
+ }
sb.append(baseDesc);
}
@@ -125,7 +126,7 @@ public abstract class SpellAbilityEffect {
/**
* Append the description of a {@link SpellAbility} to a
* {@link StringBuilder}.
- *
+ *
* @param sa
* a {@link SpellAbility}.
* @param sb
@@ -173,7 +174,7 @@ public abstract class SpellAbilityEffect {
private static CardCollection getCards(final boolean definedFirst, final String definedParam, final SpellAbility sa) {
final boolean useTargets = sa.usesTargeting() && (!definedFirst || !sa.hasParam(definedParam));
- return useTargets ? new CardCollection(sa.getTargets().getTargetCards())
+ return useTargets ? new CardCollection(sa.getTargets().getTargetCards())
: AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam(definedParam), sa);
}
@@ -196,10 +197,22 @@ public abstract class SpellAbilityEffect {
private static List getSpells(final boolean definedFirst, final String definedParam, final SpellAbility sa) {
final boolean useTargets = sa.usesTargeting() && (!definedFirst || !sa.hasParam(definedParam));
- return useTargets ? Lists.newArrayList(sa.getTargets().getTargetSpells())
+ return useTargets ? Lists.newArrayList(sa.getTargets().getTargetSpells())
: AbilityUtils.getDefinedSpellAbilities(sa.getHostCard(), sa.getParam(definedParam), sa);
}
+
+ // Targets of card or player type
+ protected final static List getTargetEntities(final SpellAbility sa) { return getEntities(false, "Defined", sa); }
+ protected final static List getTargetEntities(final SpellAbility sa, final String definedParam) { return getEntities(false, definedParam, sa); }
+ protected final static List getDefinedEntitiesOrTargeted(SpellAbility sa, final String definedParam) { return getEntities(true, definedParam, sa); }
+
+ private static List getEntities(final boolean definedFirst, final String definedParam, final SpellAbility sa) {
+ final boolean useTargets = sa.usesTargeting() && (!definedFirst || !sa.hasParam(definedParam));
+ return useTargets ? Lists.newArrayList(sa.getTargets().getTargetEntities())
+ : AbilityUtils.getDefinedEntities(sa.getHostCard(), sa.getParam(definedParam), sa);
+ }
+
// Targets of unspecified type
protected final static List getTargets(final SpellAbility sa) { return getTargetables(false, "Defined", sa); }
protected final static List getTargets(final SpellAbility sa, final String definedParam) { return getTargetables(false, definedParam, sa); }
@@ -207,10 +220,10 @@ public abstract class SpellAbilityEffect {
private static List getTargetables(final boolean definedFirst, final String definedParam, final SpellAbility sa) {
final boolean useTargets = sa.usesTargeting() && (!definedFirst || !sa.hasParam(definedParam));
- return useTargets ? Lists.newArrayList(sa.getTargets().getTargets())
+ return useTargets ? Lists.newArrayList(sa.getTargets().getTargets())
: AbilityUtils.getDefinedObjects(sa.getHostCard(), sa.getParam(definedParam), sa);
}
-
+
protected static void registerDelayedTrigger(final SpellAbility sa, String location, final List crds) {
boolean intrinsic = sa.isIntrinsic();
@@ -218,14 +231,14 @@ public abstract class SpellAbilityEffect {
boolean combat = location.endsWith("Combat");
String desc = sa.hasParam("AtEOTDesc") ? sa.getParam("AtEOTDesc") : "";
-
+
if (your) {
location = location.substring("Your".length());
}
if (combat) {
location = location.substring(0, location.length() - "Combat".length());
}
-
+
if (desc.isEmpty()) {
StringBuilder sb = new StringBuilder();
if (location.equals("Hand")) {
@@ -253,12 +266,12 @@ public abstract class SpellAbilityEffect {
StringBuilder delTrig = new StringBuilder();
delTrig.append("Mode$ Phase | Phase$ ");
delTrig.append(combat ? "EndCombat " : "End Of Turn ");
-
+
if (your) {
delTrig.append("| ValidPlayer$ You ");
}
delTrig.append("| TriggerDescription$ ").append(desc);
-
+
final Trigger trig = TriggerHandler.parseTrigger(delTrig.toString(), sa.getHostCard(), intrinsic);
for (final Card c : crds) {
trig.addRemembered(c);
@@ -289,7 +302,7 @@ public abstract class SpellAbilityEffect {
trig.setOverridingAbility(newSa);
sa.getActivatingPlayer().getGame().getTriggerHandler().registerDelayedTrigger(trig);
}
-
+
protected static void addSelfTrigger(final SpellAbility sa, String location, final Card card) {
String trigStr = "Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield " +
@@ -311,17 +324,17 @@ public abstract class SpellAbilityEffect {
card.setSVar("EndOfTurnLeavePlay", "AtEOT");
}
}
-
+
protected static void addForgetOnMovedTrigger(final Card card, final String zone) {
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ " + zone + " | Destination$ Any | TriggerZones$ Command | Static$ True";
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
-
+
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, card);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, card);
saForget.setSubAbility(saExile);
-
+
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, card, true);
parsedTrigger.setOverridingAbility(saForget);
final Trigger addedTrigger = card.addTrigger(parsedTrigger);
@@ -336,22 +349,22 @@ public abstract class SpellAbilityEffect {
final Trigger addedTrigger = card.addTrigger(parsedTrigger);
addedTrigger.setIntrinsic(true);
}
-
+
protected static void addForgetCounterTrigger(final Card card, final String counterType) {
String trig = "Mode$ CounterRemoved | TriggerZones$ Command | ValidCard$ Card.IsRemembered | CounterType$ " + counterType + " | NewCounterAmount$ 0 | Static$ True";
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
-
+
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, card);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, card);
saForget.setSubAbility(saExile);
-
+
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, card, true);
parsedTrigger.setOverridingAbility(saForget);
final Trigger addedTrigger = card.addTrigger(parsedTrigger);
- addedTrigger.setIntrinsic(true);
+ addedTrigger.setIntrinsic(true);
}
protected static void addLeaveBattlefieldReplacement(final Card card, final SpellAbility sa, final String zone) {
@@ -378,10 +391,10 @@ public abstract class SpellAbilityEffect {
game.getAction().moveTo(ZoneType.Command, eff, sa);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
}
-
+
protected static void addLeaveBattlefieldReplacement(final Card eff, final String zone) {
final String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered "
- + "| Origin$ Battlefield | ExcludeDestination$ " + zone
+ + "| Origin$ Battlefield | ExcludeDestination$ " + zone
+ "| Description$ If Creature would leave the battlefield, "
+ " exile it instead of putting it anywhere else.";
String effect = "DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ " + zone;
@@ -392,7 +405,7 @@ public abstract class SpellAbilityEffect {
re.setOverridingAbility(AbilityFactory.getAbility(effect, eff));
eff.addReplacementEffect(re);
}
-
+
// create a basic template for Effect to be used somewhere else
protected static Card createEffect(final SpellAbility sa, final Player controller, final String name,
final String image) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java
index 45c8797362d..1612c2ae3da 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java
@@ -1,7 +1,11 @@
package forge.game.ability.effects;
+import java.util.Map;
+
import org.apache.commons.lang3.mutable.MutableBoolean;
+import com.google.common.collect.Maps;
+
import forge.game.Game;
import forge.game.GameEntityCounterTable;
import forge.game.ability.AbilityUtils;
@@ -10,6 +14,7 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardZoneTable;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.token.TokenInfo;
import forge.game.event.GameEventCombatChanged;
@@ -79,13 +84,16 @@ public class AmassEffect extends TokenEffectBase {
game.updateCombatForView();
game.fireEvent(new GameEventCombatChanged());
}
+ Map params = Maps.newHashMap();
+ params.put("CounterType", CounterType.get(CounterEnumType.P1P1));
+ params.put("Amount", 1);
CardCollectionView tgtCards = CardLists.getType(activator.getCardsIn(ZoneType.Battlefield), "Army");
- tgtCards = pc.chooseCardsForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblChooseAnArmy"), 1, 1, false);
+ tgtCards = pc.chooseCardsForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblChooseAnArmy"), 1, 1, false, params);
GameEntityCounterTable table = new GameEntityCounterTable();
for(final Card tgtCard : tgtCards) {
- tgtCard.addCounter(CounterType.P1P1, amount, activator, true, table);
+ tgtCard.addCounter(CounterEnumType.P1P1, amount, activator, true, table);
game.updateLastStateForCard(tgtCard);
if (remember) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java
index ff0c74c1020..cd8325cdba9 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java
@@ -35,7 +35,8 @@ public class AttachEffect extends SpellAbilityEffect {
sa.setHostCard(c);
}
- Card source = sa.getHostCard();
+ final Card source = sa.getHostCard();
+ final Game game = source.getGame();
CardCollection attachments;
final List targets = getDefinedOrTargeted(sa, "Defined");
@@ -57,15 +58,22 @@ public class AttachEffect extends SpellAbilityEffect {
final Player p = sa.getActivatingPlayer();
- if (sa.hasParam("Object")) {
- attachments = AbilityUtils.getDefinedCards(source, sa.getParam("Object"), sa);
- if (sa.hasParam("ChooseAnObject")) {
- Card c = p.getController().chooseSingleEntityForEffect(attachments, sa, sa.getParam("ChooseAnObject"));
- attachments.clear();
- if (c != null) {
- attachments.add(c);
- }
+ if (sa.hasParam("Choices")) {
+ ZoneType choiceZone = ZoneType.Battlefield;
+ if (sa.hasParam("ChoiceZone")) {
+ choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
}
+ String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChoose") + " ";
+
+ CardCollection choices = CardLists.getValidCards(game.getCardsIn(choiceZone), sa.getParam("Choices"), p, source, sa);
+
+ Card c = p.getController().chooseSingleEntityForEffect(choices, sa, title, null);
+ if (c == null) {
+ return;
+ }
+ attachments = new CardCollection(c);
+ } else if (sa.hasParam("Object")) {
+ attachments = AbilityUtils.getDefinedCards(source, sa.getParam("Object"), sa);
} else {
attachments = new CardCollection(source);
}
@@ -185,7 +193,8 @@ public class AttachEffect extends SpellAbilityEffect {
players.add(player);
}
}
- final Player pa = p.getController().chooseSingleEntityForEffect(players, aura, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", CardTranslation.getTranslatedName(source.getName())));
+ final Player pa = p.getController().chooseSingleEntityForEffect(players, aura,
+ Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", CardTranslation.getTranslatedName(source.getName())), null);
if (pa != null) {
handleAura(source, pa);
return true;
@@ -198,7 +207,8 @@ public class AttachEffect extends SpellAbilityEffect {
return false;
}
- final Card o = p.getController().chooseSingleEntityForEffect(list, aura, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(source.getName())));
+ final Card o = p.getController().chooseSingleEntityForEffect(list, aura,
+ Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(source.getName())), null);
if (o != null) {
handleAura(source, o);
//source.enchantEntity((Card) o);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/BondEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BondEffect.java
index b41e6a265c5..4d9789bac9f 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/BondEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/BondEffect.java
@@ -31,7 +31,7 @@ public class BondEffect extends SpellAbilityEffect {
Card partner = cards.getFirst();
// skip choice if only one card on list
if (cards.size() > 1) {
- partner = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(cards, sa, Localizer.getInstance().getMessage("lblSelectACardPair"));
+ partner = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(cards, sa, Localizer.getInstance().getMessage("lblSelectACardPair"), null);
}
// pair choices together
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java
index 5d9d68b9a53..0b807bdd2bc 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeCombatantsEffect.java
@@ -18,7 +18,10 @@ import forge.util.CardTranslation;
import org.apache.commons.lang3.StringUtils;
+import com.google.common.collect.Maps;
+
import java.util.List;
+import java.util.Map;
public class ChangeCombatantsEffect extends SpellAbilityEffect {
@@ -45,8 +48,12 @@ public class ChangeCombatantsEffect extends SpellAbilityEffect {
final Combat combat = game.getCombat();
final GameEntity originalDefender = combat.getDefenderByAttacker(c);
final FCollectionView defs = combat.getDefenders();
- final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(defs, sa,
- Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), false);
+
+ String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName()));
+ Map params = Maps.newHashMap();
+ params.put("Attacker", c);
+
+ final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(defs, sa, title, false, params);
if (originalDefender != null && !originalDefender.equals(defender)) {
AttackingBand ab = combat.getBandOfAttacker(c);
if (ab != null) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java
index c68a48b9836..8711a63ad8e 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java
@@ -507,7 +507,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("AttachedTo"), tgtC.getController(), tgtC);
}
if (!list.isEmpty()) {
- Card attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", tgtC.toString()));
+ Map params = Maps.newHashMap();
+ params.put("Attach", tgtC);
+ Card attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", tgtC.toString()), params);
tgtC.attachToEntity(attachedTo);
} else { // When it should enter the battlefield attached to an illegal permanent it fails
continue;
@@ -517,7 +519,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("AttachedToPlayer")) {
FCollectionView list = AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("AttachedToPlayer"), sa);
if (!list.isEmpty()) {
- Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", tgtC.toString()));
+ Map params = Maps.newHashMap();
+ params.put("Attach", tgtC);
+ Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectAPlayerAttachSourceTo", tgtC.toString()), params);
tgtC.attachToEntity(attachedTo);
}
else { // When it should enter the battlefield attached to an illegal player it fails
@@ -578,7 +582,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
} else {
- defender = player.getController().chooseSingleEntityForEffect(e, sa, Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(movedCard.getName())));
+ String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(movedCard.getName()));
+ Map params = Maps.newHashMap();
+ params.put("Attacker", movedCard);
+ defender = player.getController().chooseSingleEntityForEffect(e, sa, title, params);
}
if (defender != null) {
combat.addAttacker(movedCard, defender);
@@ -1039,7 +1046,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (!list.isEmpty()) {
Card attachedTo = null;
if (list.size() > 1) {
- attachedTo = decider.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(c.getName())));
+ String title = Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(c.getName()));
+ Map params = Maps.newHashMap();
+ params.put("Attach", c);
+ attachedTo = decider.getController().chooseSingleEntityForEffect(list, sa, title, params);
}
else {
attachedTo = list.get(0);
@@ -1057,7 +1067,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("AttachedToPlayer")) {
FCollectionView list = AbilityUtils.getDefinedPlayers(source, sa.getParam("AttachedToPlayer"), sa);
if (!list.isEmpty()) {
- Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(c.getName())));
+ String title = Localizer.getInstance().getMessage("lblSelectACardAttachSourceTo", CardTranslation.getTranslatedName(c.getName()));
+ Map params = Maps.newHashMap();
+ params.put("Attach", c);
+ Player attachedTo = player.getController().chooseSingleEntityForEffect(list, sa, title, params);
c.attachToEntity(attachedTo);
}
else { // When it should enter the battlefield attached to an illegal permanent it fails
@@ -1080,7 +1093,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
} else {
- defender = player.getController().chooseSingleEntityForEffect(e, sa, Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())));
+ String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName()));
+ Map params = Maps.newHashMap();
+ params.put("Attacker", c);
+ defender = player.getController().chooseSingleEntityForEffect(e, sa, title, params);
}
if (defender != null) {
combat.addAttacker(c, defender);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java
index ee1cca795e7..faed7543bcc 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java
@@ -189,7 +189,7 @@ public class CharmEffect extends SpellAbilityEffect {
//String choosers = sa.getParam("Chooser");
FCollection opponents = activator.getOpponents(); // all cards have Choser$ Opponent, so it's hardcoded here
- chooser = activator.getController().chooseSingleEntityForEffect(opponents, sa, "Choose an opponent");
+ chooser = activator.getController().chooseSingleEntityForEffect(opponents, sa, "Choose an opponent", null);
source.setChosenPlayer(chooser);
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java
index 1a601c45a2a..3d55ced65bc 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java
@@ -84,7 +84,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
final CardCollectionView cl = CardLists.getType(land, type);
if (!cl.isEmpty()) {
final String prompt = Localizer.getInstance().getMessage("lblChoose") + " " + Lang.nounWithAmount(1, type);
- Card c = p.getController().chooseSingleEntityForEffect(cl, sa, prompt, false);
+ Card c = p.getController().chooseSingleEntityForEffect(cl, sa, prompt, false, null);
if (c != null) {
chosen.add(c);
}
@@ -100,7 +100,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
while (!creature.isEmpty()) {
Card c = p.getController().chooseSingleEntityForEffect(creature, sa,
Localizer.getInstance().getMessage("lblSelectCreatureWithTotalPowerLessOrEqualTo", (totP - chosenP - negativeNum))
- + "\r\n(" + Localizer.getInstance().getMessage("lblSelected") + ":" + chosenPool + ")\r\n(" + Localizer.getInstance().getMessage("lblTotalPowerNum", chosenP) + ")", chosenP <= totP);
+ + "\r\n(" + Localizer.getInstance().getMessage("lblSelected") + ":" + chosenPool + ")\r\n(" + Localizer.getInstance().getMessage("lblTotalPowerNum", chosenP) + ")", chosenP <= totP, null);
if (c == null) {
if (p.getController().confirmAction(sa, PlayerActionConfirmMode.OptionalChoose, Localizer.getInstance().getMessage("lblCancelChooseConfirm"))) {
break;
@@ -120,7 +120,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
Aggregates.random(choices, validAmount, chosen);
} else {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";
- chosen.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount, !sa.hasParam("Mandatory")));
+ chosen.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount, !sa.hasParam("Mandatory"), null));
}
}
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java
index a1d21c94c0f..f5f59dfb4e5 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java
@@ -8,8 +8,7 @@ import forge.game.card.Card;
import forge.game.event.GameEventCardModeChosen;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
-import forge.util.MyRandom;
-import forge.util.Localizer;
+import forge.util.Aggregates;
import java.util.List;
@@ -33,6 +32,7 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
final List abilities = Lists.newArrayList(sa.getAdditionalAbilityList("Choices"));
final SpellAbility fallback = sa.getAdditionalAbility("FallbackAbility");
+ final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("ChoiceAmount", "1"), sa);
final List tgtPlayers = getDefinedPlayersOrTargeted(sa);
@@ -43,8 +43,7 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
for (SpellAbility saChoice : abilities) {
if (!saChoice.getRestrictions().checkOtherRestrictions(host, saChoice, sa.getActivatingPlayer()) ) {
saToRemove.add(saChoice);
- } else if (saChoice.hasParam("UnlessCost") &&
- "Player.IsRemembered".equals(saChoice.getParam("Defined"))) {
+ } else if (saChoice.hasParam("UnlessCost")) {
String unlessCost = saChoice.getParam("UnlessCost");
// Sac a permanent in presence of Sigarda, Host of Herons
// TODO: generalize this by testing if the unless cost can be paid
@@ -65,27 +64,26 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
continue;
}
- SpellAbility chosenSA = null;
+ List chosenSAs = Lists.newArrayList();
if (sa.hasParam("AtRandom")) {
- if (!abilities.isEmpty()) {
- chosenSA = abilities.get(MyRandom.getRandom().nextInt(abilities.size()));
- }
+ Aggregates.random(abilities, amount, chosenSAs);
} else {
- chosenSA = p.getController().chooseSingleSpellForEffect(abilities, sa, Localizer.getInstance().getMessage("lblChooseOne"),
- ImmutableMap.of());
+ chosenSAs = p.getController().chooseSpellAbilitiesForEffect(abilities, sa, "Choose", amount, ImmutableMap.of());
}
-
- if (chosenSA != null) {
- String chosenValue = chosenSA.getDescription();
- if (sa.hasParam("ShowChoice")) {
- boolean dontNotifySelf = sa.getParam("ShowChoice").equals("ExceptSelf");
- p.getGame().getAction().nofityOfValue(sa, p, chosenValue, dontNotifySelf ? sa.getActivatingPlayer() : null);
+
+ if (!chosenSAs.isEmpty()) {
+ for (SpellAbility chosenSA : chosenSAs) {
+ String chosenValue = chosenSA.getDescription();
+ if (sa.hasParam("ShowChoice")) {
+ boolean dontNotifySelf = sa.getParam("ShowChoice").equals("ExceptSelf");
+ p.getGame().getAction().nofityOfValue(sa, p, chosenValue, dontNotifySelf ? sa.getActivatingPlayer() : null);
+ }
+ if (sa.hasParam("SetChosenMode")) {
+ sa.getHostCard().setChosenMode(chosenValue);
+ }
+ p.getGame().fireEvent(new GameEventCardModeChosen(p, host.getName(), chosenValue, sa.hasParam("ShowChoice")));
+ AbilityUtils.resolve(chosenSA);
}
- if (sa.hasParam("SetChosenMode")) {
- sa.getHostCard().setChosenMode(chosenValue);
- }
- p.getGame().fireEvent(new GameEventCardModeChosen(p, host.getName(), chosenValue, sa.hasParam("ShowChoice")));
- AbilityUtils.resolve(chosenSA);
} else {
// no choices are valid, e.g. maybe all Unless costs are unpayable
if (fallback != null) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChoosePlayerEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChoosePlayerEffect.java
index 0d57e4a4c2c..6f25e23d7b4 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ChoosePlayerEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ChoosePlayerEffect.java
@@ -51,7 +51,7 @@ public class ChoosePlayerEffect extends SpellAbilityEffect {
if (random) {
chosen = choices.isEmpty() ? null : Aggregates.random(choices);
} else {
- chosen = choices.isEmpty() ? null : p.getController().chooseSingleEntityForEffect(choices, sa, choiceDesc);
+ chosen = choices.isEmpty() ? null : p.getController().chooseSingleEntityForEffect(choices, sa, choiceDesc, null);
}
if( null != chosen ) {
card.setChosenPlayer(chosen);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseSourceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseSourceEffect.java
index b35e17c0a25..34004b1a310 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ChooseSourceEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseSourceEffect.java
@@ -138,7 +138,7 @@ public class ChooseSourceEffect extends SpellAbilityEffect {
final String choiceTitle = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseSource") + " ";
Card o = null;
do {
- o = p.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, sa, choiceTitle);
+ o = p.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, sa, choiceTitle, null);
} while (o == null);
chosen.add(o);
sourcesToChooseFrom.remove(o);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ClashEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ClashEffect.java
index 191b1db43e9..a775ddd281d 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ClashEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ClashEffect.java
@@ -75,7 +75,7 @@ public class ClashEffect extends SpellAbilityEffect {
*/
final Card source = sa.getHostCard();
final Player player = source.getController();
- final Player opponent = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(player.getOpponents(), sa, Localizer.getInstance().getMessage("lblChooseOpponent")) ;
+ final Player opponent = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(player.getOpponents(), sa, Localizer.getInstance().getMessage("lblChooseOpponent"), null);
final ZoneType lib = ZoneType.Library;
if (sa.hasParam("RememberClasher")) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java
index 9cf8118d66b..0b27812a57e 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java
@@ -81,7 +81,7 @@ public class CloneEffect extends SpellAbilityEffect {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host);
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";
- cardToCopy = activator.getController().chooseSingleEntityForEffect(choices, sa, title, false);
+ cardToCopy = activator.getController().chooseSingleEntityForEffect(choices, sa, title, false, null);
} else if (sa.hasParam("Defined")) {
List cloneSources = AbilityUtils.getDefinedCards(host, sa.getParam("Defined"), sa);
if (!cloneSources.isEmpty()) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ControlExchangeVariantEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ControlExchangeVariantEffect.java
index f39c38616d8..92db1453cb4 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ControlExchangeVariantEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ControlExchangeVariantEffect.java
@@ -36,9 +36,9 @@ public class ControlExchangeVariantEffect extends SpellAbilityEffect {
CardCollectionView list2 = AbilityUtils.filterListByType(player2.getCardsIn(zone), type, sa);
int max = Math.min(list1.size(), list2.size());
// choose the same number of cards
- CardCollectionView chosen1 = activator.getController().chooseCardsForEffect(list1, sa, Localizer.getInstance().getMessage("lblChooseCards") + ":" + player1, 0, max, true);
+ CardCollectionView chosen1 = activator.getController().chooseCardsForEffect(list1, sa, Localizer.getInstance().getMessage("lblChooseCards") + ":" + player1, 0, max, true, null);
int num = chosen1.size();
- CardCollectionView chosen2 = activator.getController().chooseCardsForEffect(list2, sa, Localizer.getInstance().getMessage("lblChooseCards") + ":" + player2, num, num, true);
+ CardCollectionView chosen2 = activator.getController().chooseCardsForEffect(list2, sa, Localizer.getInstance().getMessage("lblChooseCards") + ":" + player2, num, num, true, null);
// check all cards can be controlled by the other player
for (final Card c : chosen1) {
if (!c.canBeControlledBy(player2)) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java
index a69a02623f3..e0e2f7ca921 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java
@@ -2,8 +2,10 @@ package forge.game.ability.effects;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import forge.GameCommand;
import forge.game.Game;
@@ -211,9 +213,10 @@ public class ControlGainEffect extends SpellAbilityEffect {
final Combat combat = game.getCombat();
if ( null != combat ) {
final FCollectionView e = combat.getDefenders();
-
- final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(e, sa,
- Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(tgtC.getName())));
+ String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(tgtC.getName()));
+ Map params = Maps.newHashMap();
+ params.put("Attacker", tgtC);
+ final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(e, sa, title, params);
if (defender != null) {
combat.addAttacker(tgtC, defender);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java
index cf1c6e9630c..c83bca2d61d 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java
@@ -143,7 +143,7 @@ public class CopyPermanentEffect extends TokenEffectBase {
if (!choices.isEmpty()) {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") +" ";
- Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false);
+ Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false, null);
if (choosen != null) {
tgtCards.add(choosen);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CopySpellAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CopySpellAbilityEffect.java
index 9f050cb5b0d..43e13b56480 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CopySpellAbilityEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CopySpellAbilityEffect.java
@@ -146,7 +146,7 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
valid.remove(originalTarget);
mayChooseNewTargets = false;
if (sa.hasParam("ChooseOnlyOne")) {
- Card choice = controller.getController().chooseSingleEntityForEffect(valid, sa, Localizer.getInstance().getMessage("lblChooseOne"));
+ Card choice = controller.getController().chooseSingleEntityForEffect(valid, sa, Localizer.getInstance().getMessage("lblChooseOne"), null);
SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true);
resetFirstTargetOnCopy(copy, choice, targetedSA);
copies.add(copy);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersMoveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersMoveEffect.java
index 30245cc137b..9bef78eab96 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CountersMoveEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CountersMoveEffect.java
@@ -7,6 +7,7 @@ import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
+import forge.game.card.CardPredicates;
import forge.game.card.CounterType;
import forge.game.player.Player;
import forge.game.player.PlayerController;
@@ -26,17 +27,30 @@ public class CountersMoveEffect extends SpellAbilityEffect {
@Override
protected String getStackDescription(SpellAbility sa) {
+ final Card host = sa.getHostCard();
final StringBuilder sb = new StringBuilder();
- Card source = null;
- List srcCards = getDefinedCardsOrTargeted(sa, "Source");
-
- if (srcCards.size() > 0) {
- source = srcCards.get(0);
- }
final List tgtCards = getDefinedCardsOrTargeted(sa);
+
+ Card source = null;
+ if (sa.usesTargeting() && sa.getTargetRestrictions().getMinTargets(host, sa) == 2) {
+ if (tgtCards.size() < 2) {
+ return "";
+ }
+ source = tgtCards.remove(0);
+ } else {
+ List srcCards = getDefinedCardsOrTargeted(sa, "Source");
+
+ if (srcCards.size() > 0) {
+ source = srcCards.get(0);
+ }
+ }
final String countername = sa.getParam("CounterType");
- final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("CounterNum"), sa);
+ final String counterAmount = sa.getParam("CounterNum");
+ int amount = 0;
+ if (!"Any".equals(counterAmount) && !"All".equals(counterAmount)) {
+ amount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("CounterNum"), sa);
+ }
sb.append("Move ");
if ("Any".matches(countername)) {
@@ -45,16 +59,18 @@ public class CountersMoveEffect extends SpellAbilityEffect {
} else {
sb.append(amount).append(" ").append(" counter");
}
- } else {
+ } else if ("All".equals(countername)) {
+ sb.append("all counter");
+ } else {
sb.append(amount).append(" ").append(countername).append(" counter");
}
if (amount != 1) {
sb.append("s");
}
sb.append(" from ").append(source).append(" to ");
- try{
+ try {
sb.append(tgtCards.get(0));
- } catch(final IndexOutOfBoundsException exception) {
+ } catch (final IndexOutOfBoundsException exception) {
System.out.println(TextUtil.concatWithSpace("Somehow this is missing targets?", source.toString()));
}
@@ -70,12 +86,12 @@ public class CountersMoveEffect extends SpellAbilityEffect {
final Player player = sa.getActivatingPlayer();
final PlayerController pc = player.getController();
final Game game = host.getGame();
-
+
CounterType cType = null;
- try {
- cType = AbilityUtils.getCounterType(counterName, sa);
- } catch (Exception e) {
- if (!counterName.matches("Any")) {
+ if (!counterName.matches("Any") && !counterName.matches("All")) {
+ try {
+ cType = AbilityUtils.getCounterType(counterName, sa);
+ } catch (Exception e) {
System.out.println("Counter type doesn't match, nor does an SVar exist with the type name.");
return;
}
@@ -89,17 +105,12 @@ public class CountersMoveEffect extends SpellAbilityEffect {
CardCollectionView srcCards = game.getCardsIn(ZoneType.Battlefield);
srcCards = CardLists.getValidCards(srcCards, sa.getParam("ValidSource"), player, host, sa);
List tgtCards = getDefinedCardsOrTargeted(sa);
-
+
if (tgtCards.isEmpty()) {
return;
}
Card dest = tgtCards.get(0);
- // target cant receive this counter type
- if (!dest.canReceiveCounters(cType)) {
- return;
- }
-
Card cur = game.getCardState(dest, null);
if (cur == null || !cur.equalsWithTimestamp(dest)) {
// Test to see if the card we're trying to add is in the expected state
@@ -107,48 +118,57 @@ public class CountersMoveEffect extends SpellAbilityEffect {
}
dest = cur;
- int csum = 0;
+ Map params = Maps.newHashMap();
+ params.put("Target", dest);
- // only select cards if the counterNum is any
- if (counterNum.equals("Any")) {
- srcCards = player.getController().chooseCardsForEffect(srcCards, sa, Localizer.getInstance().getMessage("lblChooseTakeCountersCard", cType.getName()), 0, srcCards.size(), true);
+ if ("All".equals(counterName)) {
+ // only select cards if the counterNum is any
+ if (counterNum.equals("Any")) {
+ srcCards = CardLists.filter(srcCards, CardPredicates.hasCounters());
+ srcCards = player.getController().chooseCardsForEffect(srcCards, sa,
+ Localizer.getInstance().getMessage("lblChooseTakeCountersCard", "any"), 0,
+ srcCards.size(), true, params);
+ }
+ } else {
+ // target cant receive this counter type
+ if (!dest.canReceiveCounters(cType)) {
+ return;
+ }
+ srcCards = CardLists.filter(srcCards, CardPredicates.hasCounter(cType));
+
+ // only select cards if the counterNum is any
+ if (counterNum.equals("Any")) {
+ params.put("CounterType", cType);
+ srcCards = player.getController().chooseCardsForEffect(srcCards, sa,
+ Localizer.getInstance().getMessage("lblChooseTakeCountersCard", cType.getName()), 0,
+ srcCards.size(), true, params);
+ }
}
+ Map countersToAdd = Maps.newHashMap();
+
for (Card src : srcCards) {
- // rule 121.5: If the first and second objects are the same object, nothing happens
+ // rule 121.5: If the first and second objects are the same object, nothing
+ // happens
if (src.equals(dest)) {
continue;
}
- int cmax = src.getCounters(cType);
- if (cmax <= 0) {
- continue;
- }
-
- int cnum = 0;
- if (counterNum.equals("All")) {
- cnum = cmax;
- } else if (counterNum.equals("Any")) {
- Map params = Maps.newHashMap();
- params.put("CounterType", cType);
- params.put("Source", src);
- params.put("Target", dest);
- cnum = player.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblTakeHowManyTargetCounterFromCard", cType.getName(), CardTranslation.getTranslatedName(src.getName())), 0, cmax, params);
+ if ("All".equals(counterName)) {
+ final Map tgtCounters = Maps.newHashMap(src.getCounters());
+ for (Map.Entry e : tgtCounters.entrySet()) {
+ removeCounter(sa, src, dest, e.getKey(), counterNum, countersToAdd);
+ }
} else {
- cnum = AbilityUtils.calculateAmount(host, counterNum, sa);
- }
- if(cnum > 0) {
- src.subtractCounter(cType, cnum);
- game.updateLastStateForCard(src);
- csum += cnum;
+ removeCounter(sa, src, dest, cType, counterNum, countersToAdd);
}
}
+ for (Map.Entry e : countersToAdd.entrySet()) {
+ dest.addCounter(e.getKey(), e.getValue(), player, true, table);
+ }
- if (csum > 0) {
- dest.addCounter(cType, csum, player, true, table);
- game.updateLastStateForCard(dest);
- table.triggerCountersPutAll(game);
- }
+ game.updateLastStateForCard(dest);
+ table.triggerCountersPutAll(game);
return;
} else if (sa.hasParam("ValidDefined")) {
// one Source to many Targets
@@ -163,18 +183,25 @@ public class CountersMoveEffect extends SpellAbilityEffect {
if (source.getCounters(cType) <= 0) {
return;
}
+ Map params = Maps.newHashMap();
+ params.put("CounterType", cType);
+ params.put("Source", source);
+
CardCollectionView tgtCards = game.getCardsIn(ZoneType.Battlefield);
tgtCards = CardLists.getValidCards(tgtCards, sa.getParam("ValidDefined"), player, host, sa);
if (counterNum.equals("Any")) {
- tgtCards = player.getController().chooseCardsForEffect(tgtCards, sa,
- Localizer.getInstance().getMessage("lblChooseCardToGetCountersFrom", cType.getName(), CardTranslation.getTranslatedName(source.getName())), 0, tgtCards.size(), true);
+ tgtCards = player.getController().chooseCardsForEffect(
+ tgtCards, sa, Localizer.getInstance().getMessage("lblChooseCardToGetCountersFrom",
+ cType.getName(), CardTranslation.getTranslatedName(source.getName())),
+ 0, tgtCards.size(), true, params);
}
boolean updateSource = false;
for (final Card dest : tgtCards) {
- // rule 121.5: If the first and second objects are the same object, nothing happens
+ // rule 121.5: If the first and second objects are the same object, nothing
+ // happens
if (source.equals(dest)) {
continue;
}
@@ -188,11 +215,14 @@ public class CountersMoveEffect extends SpellAbilityEffect {
continue;
}
- Map params = Maps.newHashMap();
+ params = Maps.newHashMap();
params.put("CounterType", cType);
params.put("Source", source);
params.put("Target", cur);
- int cnum = player.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblPutHowManyTargetCounterOnCard", cType.getName(), CardTranslation.getTranslatedName(cur.getName())), 0, source.getCounters(cType), params);
+ int cnum = player.getController().chooseNumber(sa,
+ Localizer.getInstance().getMessage("lblPutHowManyTargetCounterOnCard", cType.getName(),
+ CardTranslation.getTranslatedName(cur.getName())),
+ 0, source.getCounters(cType), params);
if (cnum > 0) {
source.subtractCounter(cType, cnum);
@@ -207,96 +237,133 @@ public class CountersMoveEffect extends SpellAbilityEffect {
table.triggerCountersPutAll(game);
}
return;
- }
-
- Card source = null;
- int cntToMove = 0;
- List srcCards = getDefinedCardsOrTargeted(sa, "Source");
- if (srcCards.size() > 0) {
- source = srcCards.get(0);
- }
-
- // source doesn't has any counters to move
- if (!source.hasCounters()) {
- return;
- }
-
- if (!counterNum.equals("All") && !counterNum.equals("Any")) {
- cntToMove = AbilityUtils.calculateAmount(host, counterNum, sa);
} else {
- cntToMove = source.getCounters(cType);
- }
- List tgtCards = getDefinedCardsOrTargeted(sa);
-
- for (final Card dest : tgtCards) {
- if (null != source && null != dest) {
- // rule 121.5: If the first and second objects are the same object, nothing happens
- if (source.equals(dest)) {
- continue;
+ Card source = null;
+ List tgtCards = getDefinedCardsOrTargeted(sa);
+ // special logic for moving from Target to Target
+ if (sa.usesTargeting() && sa.getTargetRestrictions().getMinTargets(host, sa) == 2) {
+ if (tgtCards.size() < 2) {
+ return;
}
- Card cur = game.getCardState(dest, null);
- if (cur == null || !cur.equalsWithTimestamp(dest)) {
- // Test to see if the card we're trying to add is in the expected state
- continue;
+ source = tgtCards.remove(0);
+ } else {
+ List srcCards = getDefinedCardsOrTargeted(sa, "Source");
+ if (srcCards.size() > 0) {
+ source = srcCards.get(0);
}
+ }
+ if (source == null) {
+ return;
+ }
- if (!"Any".matches(counterName)) {
- if (!cur.canReceiveCounters(cType)) {
+ // source doesn't has any counters to move
+ if (!source.hasCounters()) {
+ return;
+ }
+
+ for (final Card dest : tgtCards) {
+ if (null != source && null != dest) {
+ // rule 121.5: If the first and second objects are the same object, nothing
+ // happens
+ if (source.equals(dest)) {
+ continue;
+ }
+ Card cur = game.getCardState(dest, null);
+ if (cur == null || !cur.equalsWithTimestamp(dest)) {
+ // Test to see if the card we're trying to add is in the expected state
continue;
}
- if (counterNum.equals("Any")) {
- Map params = Maps.newHashMap();
- params.put("CounterType", cType);
- params.put("Source", source);
- params.put("Target", cur);
- cntToMove = pc.chooseNumber(sa, Localizer.getInstance().getMessage("lblTakeHowManyTargetCounterFromCard", cType.getName(), CardTranslation.getTranslatedName(source.getName())), 0, cntToMove, params);
- }
-
- if (source.getCounters(cType) >= cntToMove) {
- source.subtractCounter(cType, cntToMove);
- cur.addCounter(cType, cntToMove, player, true, table);
- game.updateLastStateForCard(cur);
- }
- } else {
- // any counterType currently only Leech Bonder
- final Map tgtCounters = source.getCounters();
-
- final List typeChoices = Lists.newArrayList();
- // get types of counters
- for (CounterType ct : tgtCounters.keySet()) {
- if (dest.canReceiveCounters(ct)) {
- typeChoices.add(ct);
+ Map countersToAdd = Maps.newHashMap();
+ if ("All".equals(counterName)) {
+ final Map tgtCounters = Maps.newHashMap(source.getCounters());
+ for (Map.Entry e : tgtCounters.entrySet()) {
+ removeCounter(sa, source, cur, e.getKey(), counterNum, countersToAdd);
}
- }
- if (typeChoices.isEmpty()) {
- return;
+
+ } else if ("Any".equals(counterName)) {
+ // any counterType currently only Leech Bonder
+ final Map tgtCounters = source.getCounters();
+
+ final List typeChoices = Lists.newArrayList();
+ // get types of counters
+ for (CounterType ct : tgtCounters.keySet()) {
+ if (dest.canReceiveCounters(ct)) {
+ typeChoices.add(ct);
+ }
+ }
+ if (typeChoices.isEmpty()) {
+ return;
+ }
+
+ Map params = Maps.newHashMap();
+ params.put("Source", source);
+ params.put("Target", dest);
+ String title = Localizer.getInstance().getMessage("lblSelectRemoveCounterType");
+ CounterType chosenType = pc.chooseCounterType(typeChoices, sa, title, params);
+
+ removeCounter(sa, source, cur, chosenType, counterNum, countersToAdd);
+ } else {
+ if (!cur.canReceiveCounters(cType)) {
+ continue;
+ }
+
+ removeCounter(sa, source, cur, cType, counterNum, countersToAdd);
}
- Map params = Maps.newHashMap();
- params.put("Source", source);
- params.put("Target", dest);
- String title = Localizer.getInstance().getMessage("lblSelectRemoveCounterType");
- CounterType chosenType = pc.chooseCounterType(typeChoices, sa, title, params);
-
- params = Maps.newHashMap();
- params.put("CounterType", chosenType);
- params.put("Source", source);
- params.put("Target", dest);
- int chosenAmount = pc.chooseNumber(sa, Localizer.getInstance().getMessage("lblTakeHowManyTargetCounters", chosenType.getName()),
- 0, Math.min(tgtCounters.get(chosenType), cntToMove), params);
-
- if (chosenAmount > 0) {
- dest.addCounter(chosenType, chosenAmount, player, true, table);
- source.subtractCounter(chosenType, chosenAmount);
- game.updateLastStateForCard(dest);
- cntToMove -= chosenAmount;
+ for (Map.Entry e : countersToAdd.entrySet()) {
+ cur.addCounter(e.getKey(), e.getValue(), player, true, table);
}
+ game.updateLastStateForCard(cur);
}
}
+ // update source
+ game.updateLastStateForCard(source);
}
- // update source
- game.updateLastStateForCard(source);
table.triggerCountersPutAll(game);
} // moveCounterResolve
+
+ protected void removeCounter(SpellAbility sa, final Card src, final Card dest, CounterType cType, String counterNum, Map countersToAdd) {
+ final Card host = sa.getHostCard();
+ //final String counterNum = sa.getParam("CounterNum");
+ final Player player = sa.getActivatingPlayer();
+ final PlayerController pc = player.getController();
+ final Game game = host.getGame();
+
+ // rule 121.5: If the first and second objects are the same object, nothing
+ // happens
+ if (src.equals(dest)) {
+ return;
+ }
+
+ if (!dest.canReceiveCounters(cType)) {
+ return;
+ }
+
+ int cmax = src.getCounters(cType);
+ if (cmax <= 0) {
+ return;
+ }
+
+ int cnum = 0;
+ if (counterNum.equals("All")) {
+ cnum = cmax;
+ } else if (counterNum.equals("Any")) {
+ Map params = Maps.newHashMap();
+ params.put("CounterType", cType);
+ params.put("Source", src);
+ params.put("Target", dest);
+ cnum = pc.chooseNumber(
+ sa, Localizer.getInstance().getMessage("lblTakeHowManyTargetCounterFromCard",
+ cType.getName(), CardTranslation.getTranslatedName(src.getName())),
+ 0, cmax, params);
+ } else {
+ cnum = Math.min(cmax, AbilityUtils.calculateAmount(host, counterNum, sa));
+ }
+ if (cnum > 0) {
+ src.subtractCounter(cType, cnum);
+ game.updateLastStateForCard(src);
+ countersToAdd.put(cType, (countersToAdd.containsKey(cType) ? countersToAdd.get(cType) : 0) + cnum);
+ }
+ }
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersProliferateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersProliferateEffect.java
index 587cc53995c..fd81398e5e9 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CountersProliferateEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CountersProliferateEffect.java
@@ -43,7 +43,7 @@ public class CountersProliferateEffect extends SpellAbilityEffect {
list.addAll(CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.hasCounters()));
List result = pc.chooseEntitiesForEffect(list, 0, list.size(), null, sa,
- Localizer.getInstance().getMessage("lblChooseProliferateTarget"), p);
+ Localizer.getInstance().getMessage("lblChooseProliferateTarget"), p, null);
GameEntityCounterTable table = new GameEntityCounterTable();
for (final GameEntity ge : result) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersPutAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersPutAllEffect.java
index d611df3baf0..4d69ba3d4e1 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CountersPutAllEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CountersPutAllEffect.java
@@ -18,7 +18,7 @@ public class CountersPutAllEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
- final CounterType cType = CounterType.valueOf(sa.getParam("CounterType"));
+ final CounterType cType = CounterType.getType(sa.getParam("CounterType"));
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("CounterNum"), sa);
final String zone = sa.hasParam("ValidZone") ? sa.getParam("ValidZone") : "Battlefield";
@@ -67,7 +67,7 @@ public class CountersPutAllEffect extends SpellAbilityEffect {
GameEntityCounterTable table = new GameEntityCounterTable();
for (final Card tgtCard : cards) {
boolean inBattlefield = game.getZoneOf(tgtCard).is(ZoneType.Battlefield);
- tgtCard.addCounter(CounterType.valueOf(type), counterAmount, placer, inBattlefield, table);
+ tgtCard.addCounter(CounterType.getType(type), counterAmount, placer, inBattlefield, table);
game.updateLastStateForCard(tgtCard);
}
table.triggerCountersPutAll(game);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersPutEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersPutEffect.java
index 19e58dce90e..61d58891566 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CountersPutEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CountersPutEffect.java
@@ -1,5 +1,6 @@
package forge.game.ability.effects;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -8,20 +9,25 @@ import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameEntityCounterTable;
import forge.game.GameObject;
+import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
+import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.player.PlayerController;
import forge.game.spellability.SpellAbility;
+import forge.game.trigger.Trigger;
+import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
@@ -31,6 +37,7 @@ import forge.util.CardTranslation;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -63,7 +70,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
} else if (type.equals("EachFromSource")) {
stringBuilder.append("each counter");
} else {
- stringBuilder.append(CounterType.valueOf(type).getName()).append(" counter");
+ stringBuilder.append(CounterType.getType(type).getName()).append(" counter");
}
if (amount != 1) {
@@ -112,48 +119,27 @@ public class CountersPutEffect extends SpellAbilityEffect {
return stringBuilder.toString();
}
- @Override
- public void resolve(SpellAbility sa) {
+ protected void resolvePerType(SpellAbility sa, final Player placer, CounterType counterType, int counterAmount, GameEntityCounterTable table) {
final Card card = sa.getHostCard();
final Game game = card.getGame();
final Player activator = sa.getActivatingPlayer();
final PlayerController pc = activator.getController();
-
- String strTyp = sa.getParam("CounterType");
- CounterType counterType = null;
- boolean existingCounter = strTyp.equals("ExistingCounter");
- boolean eachExistingCounter = sa.hasParam("EachExistingCounter");
- boolean eachFromSource = strTyp.equals("EachFromSource");
- String amount = sa.getParamOrDefault("CounterNum", "1");
-
- if (!existingCounter && !eachFromSource) {
- try {
- counterType = AbilityUtils.getCounterType(strTyp, sa);
- } catch (Exception e) {
- System.out.println("Counter type doesn't match, nor does an SVar exist with the type name.");
- return;
- }
- }
-
- Player placer = activator;
- if (sa.hasParam("Placer")) {
- final String pstr = sa.getParam("Placer");
- placer = AbilityUtils.getDefinedPlayers(sa.getHostCard(), pstr, sa).get(0);
- }
-
final boolean etbcounter = sa.hasParam("ETB");
- final boolean remember = sa.hasParam("RememberCounters");
final boolean rememberCards = sa.hasParam("RememberCards");
- int counterAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amount, sa);
final int max = sa.hasParam("MaxFromEffect") ? Integer.parseInt(sa.getParam("MaxFromEffect")) : -1;
- CardCollection tgtCards = new CardCollection();
+ boolean existingCounter = sa.hasParam("CounterType") && sa.getParam("CounterType").equals("ExistingCounter");
+ boolean eachExistingCounter = sa.hasParam("EachExistingCounter");
+
List tgtObjects = Lists.newArrayList();
if (sa.hasParam("Bolster")) {
CardCollection creatsYouCtrl = CardLists.filter(activator.getCardsIn(ZoneType.Battlefield), Presets.CREATURES);
CardCollection leastToughness = new CardCollection(Aggregates.listWithMin(creatsYouCtrl, CardPredicates.Accessors.fnGetDefense));
- tgtCards.addAll(activator.getController().chooseCardsForEffect(leastToughness, sa, Localizer.getInstance().getMessage("lblChooseACreatureWithLeastToughness"), 1, 1, false));
- tgtObjects.addAll(tgtCards);
+
+ Map params = Maps.newHashMap();
+ params.put("CounterType", counterType);
+
+ Iterables.addAll(tgtObjects, activator.getController().chooseCardsForEffect(leastToughness, sa, Localizer.getInstance().getMessage("lblChooseACreatureWithLeastToughness"), 1, 1, false, params));
} else if (sa.hasParam("Choices")) {
ZoneType choiceZone = ZoneType.Battlefield;
if (sa.hasParam("ChoiceZone")) {
@@ -174,14 +160,22 @@ public class CountersPutEffect extends SpellAbilityEffect {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, card, sa);
- String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";
- tgtObjects.addAll(new CardCollection(chooser.getController().chooseCardsForEffect(choices, sa, title, n, n, sa.hasParam("ChoiceOptional"))));
+ String title = Localizer.getInstance().getMessage("lblChooseaCard") + " ";
+ if (sa.hasParam("ChoiceTitle")) {
+ title = sa.getParam("ChoiceTitle");
+ // TODO might use better message
+ if (counterType != null) {
+ title += " " + counterType.getName();
+ }
+ }
+
+ Map params = Maps.newHashMap();
+ params.put("CounterType", counterType);
+ Iterables.addAll(tgtObjects, chooser.getController().chooseCardsForEffect(choices, sa, title, n, n, sa.hasParam("ChoiceOptional"), params));
} else {
tgtObjects.addAll(getDefinedOrTargeted(sa, "Defined"));
}
- GameEntityCounterTable table = new GameEntityCounterTable();
-
for (final GameObject obj : tgtObjects) {
// check if the object is still in game or if it was moved
Card gameCard = null;
@@ -234,9 +228,8 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
}
- if (eachFromSource) {
- final CardCollection definedCard = AbilityUtils.getDefinedCards(card, sa.getParam("EachFromSource"), sa);
- for (Card c : definedCard) {
+ if (sa.hasParam("EachFromSource")) {
+ for (Card c : AbilityUtils.getDefinedCards(card, sa.getParam("EachFromSource"), sa)) {
for (Entry cti : c.getCounters().entrySet()) {
if (gameCard != null && gameCard.canReceiveCounters(cti.getKey())) {
gameCard.addCounter(cti.getKey(), cti.getValue(), placer, true, table);
@@ -262,7 +255,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
// Adapt need extra logic
if (sa.hasParam("Adapt")) {
- if (!(gameCard.getCounters(CounterType.P1P1) == 0
+ if (!(gameCard.getCounters(CounterEnumType.P1P1) == 0
|| gameCard.hasKeyword("CARDNAME adapts as though it had no +1/+1 counters"))) {
continue;
}
@@ -293,8 +286,13 @@ public class CountersPutEffect extends SpellAbilityEffect {
continue;
}
+ Map params = Maps.newHashMap();
+ params.put("CounterType", counterType);
+ params.put("Amount", counterAmount);
+ params.put("Target", gameCard);
+
String message = Localizer.getInstance().getMessage("lblDoYouWantPutTargetP1P1CountersOnCard", String.valueOf(counterAmount), CardTranslation.getTranslatedName(gameCard.getName()));
- Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa, Localizer.getInstance().getMessage("lblChooseAnOpponent"));
+ Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa, Localizer.getInstance().getMessage("lblChooseAnOpponent"), params);
if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.Tribute, message)) {
gameCard.setTributed(true);
@@ -307,13 +305,14 @@ public class CountersPutEffect extends SpellAbilityEffect {
if (etbcounter) {
gameCard.addEtbCounter(counterType, counterAmount, placer);
} else {
- if (gameCard.addCounter(counterType, counterAmount, placer, true, table) > 0) {
+ int addedAmount = gameCard.addCounter(counterType, counterAmount, placer, true, table);
+ if (addedAmount > 0) {
counterAdded = true;
}
- }
- if (remember) {
- final int value = gameCard.getTotalCountersToAdd();
- gameCard.addCountersAddedBy(card, counterType, value);
+
+ if (sa.hasParam("RemovePhase")) {
+ addRemovePhaseTrigger(card, sa, sa.getParam("RemovePhase"), gameCard, counterType, addedAmount);
+ }
}
if (sa.hasParam("Evolve")) {
@@ -356,7 +355,85 @@ public class CountersPutEffect extends SpellAbilityEffect {
pl.addCounter(counterType, counterAmount, placer, true, table);
}
}
+ }
+
+ @Override
+ public void resolve(SpellAbility sa) {
+ final Card card = sa.getHostCard();
+ final Game game = card.getGame();
+ final Player activator = sa.getActivatingPlayer();
+
+ CounterType counterType = null;
+ String amount = sa.getParamOrDefault("CounterNum", "1");
+ boolean rememberAmount = sa.hasParam("RememberAmount");
+
+ if (!sa.hasParam("EachExistingCounter") && !sa.hasParam("EachFromSource") && !sa.hasParam("SharedKeywords")) {
+ try {
+ counterType = AbilityUtils.getCounterType(sa.getParam("CounterType"), sa);
+ } catch (Exception e) {
+ System.out.println("Counter type doesn't match, nor does an SVar exist with the type name.");
+ return;
+ }
+ }
+
+ Player placer = activator;
+ if (sa.hasParam("Placer")) {
+ final String pstr = sa.getParam("Placer");
+ placer = AbilityUtils.getDefinedPlayers(sa.getHostCard(), pstr, sa).get(0);
+ }
+
+ int counterAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amount, sa);
+
+ GameEntityCounterTable table = new GameEntityCounterTable();
+
+ if (sa.hasParam("SharedKeywords")) {
+ List keywords = Arrays.asList(sa.getParam("SharedKeywords").split(" & "));
+ List zones = ZoneType.listValueOf(sa.getParam("SharedKeywordsZone"));
+ String[] restrictions = sa.hasParam("SharedRestrictions") ? sa.getParam("SharedRestrictions").split(",") : new String[]{"Card"};
+ keywords = CardFactoryUtil.sharedKeywords(keywords, restrictions, zones, sa.getHostCard());
+ for (String k : keywords) {
+ resolvePerType(sa, placer, CounterType.getType(k), counterAmount, table);
+ }
+ } else {
+ resolvePerType(sa, placer, counterType, counterAmount, table);
+ }
+
+ int totalAdded = 0;
+ for (Integer i : table.values()) {
+ totalAdded += i;
+ }
+
+ if (totalAdded > 0 && rememberAmount) {
+ // TODO use SpellAbility Remember later
+ card.addRemembered(Integer.valueOf(totalAdded));
+ }
+
table.triggerCountersPutAll(game);
}
+ protected void addRemovePhaseTrigger(final Card host, final SpellAbility sa, String phase, Card tgt, CounterType ct, int added) {
+ boolean intrinsic = sa.isIntrinsic();
+
+ StringBuilder delTrig = new StringBuilder("Mode$ Phase | Phase$ ");
+ delTrig.append(phase);
+ delTrig.append(" | TriggerDescription$ For each ").append(ct.getName()).append(" counter you put on a creature this way, remove a ").append(ct.getName()).append(" counter from that creature at the beginning of the next");
+ if ("Cleanup".equals(phase)) {
+ delTrig.append("cleanup step");
+ } else if ("End of Turn".equals(phase)) {
+ delTrig.append("next end step");
+ }
+
+ String trigSA = new StringBuilder("DB$ RemoveCounter | Defined$ DelayTriggerRemembered | CounterNum$ 1 | CounterType$ ").append(ct).toString();
+
+ // these trigger are one per counter
+ for (int i = 0; i < added; i++) {
+ final Trigger trig = TriggerHandler.parseTrigger(delTrig.toString(), sa.getHostCard(), intrinsic);
+ trig.addRemembered(tgt);
+
+ final SpellAbility newSa = AbilityFactory.getAbility(trigSA, sa.getHostCard());
+ newSa.setIntrinsic(intrinsic);
+ trig.setOverridingAbility(newSa);
+ sa.getActivatingPlayer().getGame().getTriggerHandler().registerDelayedTrigger(trig);
+ }
+ }
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java
index 61e89d134ec..14298c46617 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CountersPutOrRemoveEffect.java
@@ -32,7 +32,7 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect {
sb.append(sa.getActivatingPlayer().getName());
if (sa.hasParam("CounterType")) {
- CounterType ctype = CounterType.valueOf(sa.getParam("CounterType"));
+ CounterType ctype = CounterType.getType(sa.getParam("CounterType"));
sb.append(" removes a ").append(ctype.getName());
sb.append(" counter from or put another ").append(ctype.getName()).append(" counter on ");
} else {
@@ -56,7 +56,7 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect {
CounterType ctype = null;
if (sa.hasParam("CounterType")) {
- ctype = CounterType.valueOf(sa.getParam("CounterType"));
+ ctype = CounterType.getType(sa.getParam("CounterType"));
}
GameEntityCounterTable table = new GameEntityCounterTable();
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveAllEffect.java
index f53a1b58264..74110e12e3e 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveAllEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveAllEffect.java
@@ -18,7 +18,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
- final CounterType cType = CounterType.valueOf(sa.getParam("CounterType"));
+ final CounterType cType = CounterType.getType(sa.getParam("CounterType"));
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("CounterNum"), sa);
final String zone = sa.hasParam("ValidZone") ? sa.getParam("ValidZone") : "Battlefield";
String amountString = Integer.toString(amount);
@@ -69,11 +69,11 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect {
continue;
}
if (sa.hasParam("AllCounters")) {
- counterAmount = tgtCard.getCounters(CounterType.valueOf(type));
+ counterAmount = tgtCard.getCounters(CounterType.getType(type));
}
if (counterAmount > 0) {
- tgtCard.subtractCounter(CounterType.valueOf(type), counterAmount);
+ tgtCard.subtractCounter(CounterType.getType(type), counterAmount);
game.updateLastStateForCard(tgtCard);
}
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java
index 5698fb50bb0..286cf8589a7 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CountersRemoveEffect.java
@@ -31,7 +31,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
final String num = sa.getParam("CounterNum");
int amount = 0;
- if (!num.equals("All") && !num.equals("Remembered")) {
+ if (!num.equals("All") && !num.equals("Any")) {
amount = AbilityUtils.calculateAmount(sa.getHostCard(), num, sa);
}
@@ -48,7 +48,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
sb.append(amount).append(" ").append(" counter");
}
} else {
- sb.append(amount).append(" ").append(CounterType.valueOf(counterName).getName()).append(" counter");
+ sb.append(amount).append(" ").append(CounterType.getType(counterName).getName()).append(" counter");
}
if (amount != 1) {
sb.append("s");
@@ -80,7 +80,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
final String num = sa.getParam("CounterNum");
int cntToRemove = 0;
- if (!num.equals("All") && !num.equals("Any") && !num.equals("Remembered")) {
+ if (!num.equals("All") && !num.equals("Any")) {
cntToRemove = AbilityUtils.calculateAmount(sa.getHostCard(), num, sa);
}
@@ -130,7 +130,10 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
srcCards = game.getCardsIn(ZoneType.Battlefield);
srcCards = CardLists.getValidCards(srcCards, sa.getParam("ValidSource"), player, card, sa);
if (num.equals("Any")) {
- srcCards = player.getController().chooseCardsForEffect(srcCards, sa, Localizer.getInstance().getMessage("lblChooseCardsToTakeTargetCounters", counterType.getName()), 0, srcCards.size(), true);
+ String title = Localizer.getInstance().getMessage("lblChooseCardsToTakeTargetCounters", counterType.getName());
+ Map params = Maps.newHashMap();
+ params.put("CounterType", counterType);
+ srcCards = player.getController().chooseCardsForEffect(srcCards, sa, title, 0, srcCards.size(), true, params);
}
} else {
srcCards = getTargetCards(sa);
@@ -156,8 +159,6 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
continue;
} else if (num.equals("All") || num.equals("Any")) {
cntToRemove = gameCard.getCounters(counterType);
- } else if (num.equals("Remembered")) {
- cntToRemove = gameCard.getCountersAddedBy(card, counterType);
}
if (type.equals("Any")) {
@@ -169,7 +170,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
if (sa.hasParam("UpTo") || num.equals("Any")) {
Map params = Maps.newHashMap();
params.put("Target", gameCard);
- params.put("CounterType", type);
+ params.put("CounterType", counterType);
String title = Localizer.getInstance().getMessage("lblSelectRemoveCountersNumberOfTarget", type);
cntToRemove = pc.chooseNumber(sa, title, 0, cntToRemove, params);
}
@@ -179,6 +180,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
gameCard.subtractCounter(counterType, cntToRemove);
if (rememberRemoved) {
for (int i = 0; i < cntToRemove; i++) {
+ // TODO might need to be more specific
card.addRemembered(Pair.of(counterType, i));
}
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java
index bc4329777a0..343bb983c8d 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java
@@ -166,7 +166,7 @@ public class DigEffect extends SpellAbilityEffect {
if (sa.hasParam("Choser")) {
final FCollectionView choosers = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Choser"), sa);
if (!choosers.isEmpty()) {
- chooser = player.getController().chooseSingleEntityForEffect(choosers, sa, Localizer.getInstance().getMessage("lblChooser") + ":");
+ chooser = player.getController().chooseSingleEntityForEffect(choosers, null, sa, Localizer.getInstance().getMessage("lblChooser") + ":", false, p, null);
}
if (sa.hasParam("SetChosenPlayer")) {
host.setChosenPlayer(chooser);
@@ -221,7 +221,7 @@ public class DigEffect extends SpellAbilityEffect {
}
for (final byte pair : MagicColor.COLORPAIR) {
Card chosen = chooser.getController().chooseSingleEntityForEffect(CardLists.filter(valid, CardPredicates.isExactlyColor(pair)),
- delayedReveal, sa, Localizer.getInstance().getMessage("lblChooseOne"), false, p);
+ delayedReveal, sa, Localizer.getInstance().getMessage("lblChooseOne"), false, p, null);
if (chosen != null) {
movedCards.add(chosen);
}
@@ -241,7 +241,7 @@ public class DigEffect extends SpellAbilityEffect {
prompt = Localizer.getInstance().getMessage("lblChooseACardLeaveTarget", p.getName(), destZone2.getTranslatedName());
}
- Card chosen = chooser.getController().chooseSingleEntityForEffect(valid, delayedReveal, sa, prompt, false, p);
+ Card chosen = chooser.getController().chooseSingleEntityForEffect(valid, delayedReveal, sa, prompt, false, p, null);
movedCards.remove(chosen);
if (sa.hasParam("RandomOrder")) {
CardLists.shuffle(movedCards);
@@ -274,7 +274,7 @@ public class DigEffect extends SpellAbilityEffect {
int max = anyNumber ? valid.size() : Math.min(valid.size(),destZone1ChangeNum);
int min = (anyNumber || optional) ? 0 : max;
if ( max > 0 ) { // if max is 0 don't make a choice
- chosen = chooser.getController().chooseEntitiesForEffect(valid, min, max, delayedReveal, sa, prompt, p);
+ chosen = chooser.getController().chooseEntitiesForEffect(valid, min, max, delayedReveal, sa, prompt, p, null);
}
chooser.getController().endTempShowCards();
@@ -316,7 +316,7 @@ public class DigEffect extends SpellAbilityEffect {
final FCollectionView e = combat.getDefenders();
final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(e, sa,
- Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())));
+ Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), null);
if (defender != null) {
combat.addAttacker(c, defender);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigMultipleEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigMultipleEffect.java
index f4eb10f558c..9fc679605fd 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/DigMultipleEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/DigMultipleEffect.java
@@ -90,7 +90,7 @@ public class DigMultipleEffect extends SpellAbilityEffect {
int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("ChooseAmount", "1"), sa);
final ZoneType chosenZone = sa.hasParam("ChosenZone") ? ZoneType.smartValueOf(sa.getParam("ChosenZone")) : ZoneType.Battlefield;
- CardCollectionView extraChosen = chooser.getController().chooseCardsForEffect(chosen, sa, Localizer.getInstance().getMessage("lblChooseCards"), amount, amount, false);
+ CardCollectionView extraChosen = chooser.getController().chooseCardsForEffect(chosen, sa, Localizer.getInstance().getMessage("lblChooseCards"), amount, amount, false, null);
if (!extraChosen.isEmpty()) {
game.getAction().reveal(extraChosen, chooser, true, Localizer.getInstance().getMessage("lblPlayerPickedCardFrom", chooser.getName()));
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java
index cb20a91cad8..eff16192f72 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java
@@ -20,6 +20,8 @@ import forge.util.collect.FCollectionView;
import java.util.*;
+import com.google.common.collect.Maps;
+
public class DigUntilEffect extends SpellAbilityEffect {
/* (non-Javadoc)
@@ -153,7 +155,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
if (revealed.size() > 0) {
game.getAction().reveal(revealed, p, false);
}
-
+
if (foundDest != null) {
// Allow ordering of found cards
@@ -178,11 +180,14 @@ public class DigUntilEffect extends SpellAbilityEffect {
}
if (sa.hasParam("Attacking")) {
final Combat combat = game.getCombat();
- if ( null != combat ) {
+ if (null != combat) {
final FCollectionView e = combat.getDefenders();
+ Map params = Maps.newHashMap();
+ params.put("Attacker", c);
+
final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(e, sa,
- Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())));
+ Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), params);
if (defender != null) {
combat.addAttacker(c, defender);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java
index 7e59dde1f78..326d56bf27d 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java
@@ -86,7 +86,7 @@ public class EffectEffect extends SpellAbilityEffect {
}
if (sa.hasParam("ForgetCounter")) {
- CounterType cType = CounterType.valueOf(sa.getParam("ForgetCounter"));
+ CounterType cType = CounterType.getType(sa.getParam("ForgetCounter"));
rememberList = new FCollection(CardLists.filter(Iterables.filter(rememberList, Card.class), CardPredicates.hasCounter(cType)));
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/EncodeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/EncodeEffect.java
index b2f88def518..fce3d683d35 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/EncodeEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/EncodeEffect.java
@@ -54,7 +54,7 @@ public class EncodeEffect extends SpellAbilityEffect {
Card movedCard = game.getAction().moveTo(ZoneType.Exile, host, sa);
// choose a creature
- Card choice = player.getController().chooseSingleEntityForEffect(choices, sa, Localizer.getInstance().getMessage("lblChooseACreatureYouControlToEncode") + " ", true);
+ Card choice = player.getController().chooseSingleEntityForEffect(choices, sa, Localizer.getInstance().getMessage("lblChooseACreatureYouControlToEncode") + " ", true, null);
if (choice == null) {
return;
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ExploreEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ExploreEffect.java
index c31e4db297a..212e6ad83fc 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ExploreEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ExploreEffect.java
@@ -7,7 +7,7 @@ import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.player.Player;
import forge.game.player.PlayerController;
import forge.game.spellability.SpellAbility;
@@ -78,7 +78,7 @@ public class ExploreEffect extends SpellAbilityEffect {
// if the card is not more in the game anymore
// this might still return true but its no problem
if (game.getZoneOf(gamec).is(ZoneType.Battlefield) && gamec.equalsWithTimestamp(c)) {
- c.addCounter(CounterType.P1P1, 1, pl, true, table);
+ c.addCounter(CounterEnumType.P1P1, 1, pl, true, table);
}
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java
index fed406415c2..e4c0b312ee0 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ManifestEffect.java
@@ -40,7 +40,8 @@ public class ManifestEffect extends SpellAbilityEffect {
}
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseCardToManifest") + " ";
- tgtCards = new CardCollection(activator.getController().chooseEntitiesForEffect(choices, amount, amount, null, sa, title, p));
+
+ tgtCards = new CardCollection(activator.getController().chooseCardsForEffect(choices, sa, title, amount, amount, false, null));
} else if ("TopOfLibrary".equals(defined)) {
tgtCards = p.getTopXCardsFromLibrary(amount);
} else {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/MeldEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MeldEffect.java
index b89a17b08e0..50443ae04b1 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/MeldEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/MeldEffect.java
@@ -36,7 +36,7 @@ public class MeldEffect extends SpellAbilityEffect {
return;
}
- Card secondary = controller.getController().chooseSingleEntityForEffect(field, sa, Localizer.getInstance().getMessage("lblChooseCardToMeld"));
+ Card secondary = controller.getController().chooseSingleEntityForEffect(field, sa, Localizer.getInstance().getMessage("lblChooseCardToMeld"), null);
secondary = game.getAction().exile(secondary, sa);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/MultiplePilesEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MultiplePilesEffect.java
index ec3de6b43eb..57b74d34c9b 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/MultiplePilesEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/MultiplePilesEffect.java
@@ -86,7 +86,7 @@ public class MultiplePilesEffect extends SpellAbilityEffect {
for (int i = 1; i < piles; i++) {
int size = pool.size();
- CardCollectionView pile = p.getController().chooseCardsForEffect(pool, sa, Localizer.getInstance().getMessage("lblChooseCardsInTargetPile", String.valueOf(i)), 0, size, false);
+ CardCollectionView pile = p.getController().chooseCardsForEffect(pool, sa, Localizer.getInstance().getMessage("lblChooseCardsInTargetPile", String.valueOf(i)), 0, size, false, null);
pileList.add(pile);
pool.removeAll(pile);
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/MustBlockEffect.java b/forge-game/src/main/java/forge/game/ability/effects/MustBlockEffect.java
index f83f720d8ad..1a950048965 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/MustBlockEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/MustBlockEffect.java
@@ -12,8 +12,10 @@ import forge.game.zone.ZoneType;
import forge.util.Localizer;
import java.util.List;
+import java.util.Map;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
public class MustBlockEffect extends SpellAbilityEffect {
@@ -23,6 +25,13 @@ public class MustBlockEffect extends SpellAbilityEffect {
final Player activator = sa.getActivatingPlayer();
final Game game = activator.getGame();
+ List cards;
+ if (sa.hasParam("DefinedAttacker")) {
+ cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DefinedAttacker"), sa);
+ } else {
+ cards = Lists.newArrayList(host);
+ }
+
List tgtCards = Lists.newArrayList();
if (sa.hasParam("Choices")) {
Player chooser = activator;
@@ -35,8 +44,9 @@ public class MustBlockEffect extends SpellAbilityEffect {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host);
if (!choices.isEmpty()) {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") +" ";
-
- Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false);
+ Map params = Maps.newHashMap();
+ params.put("Attackers", cards);
+ Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false, params);
if (choosen != null) {
tgtCards.add(choosen);
@@ -48,13 +58,6 @@ public class MustBlockEffect extends SpellAbilityEffect {
final boolean mustBlockAll = sa.hasParam("BlockAllDefined");
- List cards;
- if (sa.hasParam("DefinedAttacker")) {
- cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DefinedAttacker"), sa);
- } else {
- cards = Lists.newArrayList(host);
- }
-
for (final Card c : tgtCards) {
if ((!sa.usesTargeting()) || c.canBeTargetedBy(sa)) {
if (mustBlockAll) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java
index c5b07d427b6..17a633afa6a 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java
@@ -118,7 +118,7 @@ public class PlayEffect extends SpellAbilityEffect {
final int choicenum = AbilityUtils.calculateAmount(source, sa.getParam("ChoiceNum"), sa);
tgtCards = new CardCollection(
activator.getController().chooseCardsForEffect(choice, sa,
- source + " - " + Localizer.getInstance().getMessage("lblChooseUpTo") + " " + Lang.nounWithNumeral(choicenum, "card"), 0, choicenum, true
+ source + " - " + Localizer.getInstance().getMessage("lblChooseUpTo") + " " + Lang.nounWithNumeral(choicenum, "card"), 0, choicenum, true, null
)
);
}
@@ -145,7 +145,7 @@ public class PlayEffect extends SpellAbilityEffect {
final CardCollection saidNoTo = new CardCollection();
while (tgtCards.size() > saidNoTo.size() && saidNoTo.size() < amount && amount > 0) {
activator.getController().tempShowCards(showCards);
- Card tgtCard = controller.getController().chooseSingleEntityForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblSelectCardToPlay"));
+ Card tgtCard = controller.getController().chooseSingleEntityForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblSelectCardToPlay"), null);
activator.getController().endTempShowCards();
if (tgtCard == null) {
return;
diff --git a/forge-game/src/main/java/forge/game/ability/effects/PoisonEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PoisonEffect.java
index 21d6f14715a..a5baf906e78 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/PoisonEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/PoisonEffect.java
@@ -5,7 +5,7 @@ import forge.game.GameEntityCounterTable;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.util.Lang;
@@ -59,7 +59,7 @@ import java.util.List;
sb.append("s");
}
- String type = CounterType.POISON.getName() + " counter";
+ String type = CounterEnumType.POISON.getName() + " counter";
sb.append(" ").append(Lang.nounWithAmount(amount, type)).append(".");
diff --git a/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java
index 54e32d8e6d6..78a9aa8ae51 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java
@@ -164,20 +164,6 @@ public class RepeatEachEffect extends SpellAbilityEffect {
}
}
}
-
- if (sa.hasParam("RepeatCounters")) {
- Card target = sa.getTargetCard();
- if (target == null) {
- target = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa).get(0);
- }
- for (CounterType type : target.getCounters().keySet()) {
- StringBuilder sb = new StringBuilder();
- sb.append("Number$").append(target.getCounters(type));
- source.setSVar("RepeatSVarCounter", type.getName().toUpperCase());
- source.setSVar("RepeatCounterAmount", sb.toString());
- AbilityUtils.resolve(repeat);
- }
- }
if (recordChoice) {
boolean random = sa.hasParam("Random");
Map> recordMap = Maps.newHashMap();
@@ -187,7 +173,7 @@ public class RepeatEachEffect extends SpellAbilityEffect {
if (random) {
p = Aggregates.random(game.getPlayers());
} else {
- p = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(game.getPlayers(), sa, Localizer.getInstance().getMessage("lblChoosePlayer"));
+ p = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(game.getPlayers(), sa, Localizer.getInstance().getMessage("lblChoosePlayer"), null);
}
if (recordMap.containsKey(p)) {
recordMap.get(p).add(0, card);
@@ -208,7 +194,7 @@ public class RepeatEachEffect extends SpellAbilityEffect {
valid = CardLists.filterControlledBy(valid,
game.getNextPlayerAfter(p, source.getChosenDirection()));
}
- Card card = p.getController().chooseSingleEntityForEffect(valid, sa, Localizer.getInstance().getMessage("lblChooseaCard"));
+ Card card = p.getController().chooseSingleEntityForEffect(valid, sa, Localizer.getInstance().getMessage("lblChooseaCard"), null);
if (recordMap.containsKey(p)) {
recordMap.get(p).add(0, card);
} else {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java
index f4a84e42a43..7e05cec8c9f 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java
@@ -45,13 +45,13 @@ public class SacrificeEffect extends SpellAbilityEffect {
}
} else if (sa.hasParam("CumulativeUpkeep")) {
GameEntityCounterTable table = new GameEntityCounterTable();
- card.addCounter(CounterType.AGE, 1, activator, true, table);
+ card.addCounter(CounterEnumType.AGE, 1, activator, true, table);
table.triggerCountersPutAll(game);
Cost cumCost = new Cost(sa.getParam("CumulativeUpkeep"), true);
Cost payCost = new Cost(ManaCost.ZERO, true);
- int n = card.getCounters(CounterType.AGE);
+ int n = card.getCounters(CounterEnumType.AGE);
// multiply cost
for (int i = 0; i < n; ++i) {
diff --git a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java
index e25e9cc2ef3..56d064457b8 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java
@@ -8,7 +8,7 @@ import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardUtil;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
@@ -125,7 +125,7 @@ public class SetStateEffect extends SpellAbilityEffect {
}
game.fireEvent(new GameEventCardStatsChanged(tgt));
if (sa.hasParam("Mega")) {
- tgt.addCounter(CounterType.P1P1, 1, p, true, table);
+ tgt.addCounter(CounterEnumType.P1P1, 1, p, true, table);
}
if (remChanged) {
host.addRemembered(tgt);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java
index f4ad424f1a9..6768eb14849 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java
@@ -2,11 +2,13 @@ package forge.game.ability.effects;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import forge.GameCommand;
@@ -127,7 +129,10 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
// into battlefield attacking only should work if you are the attacking player
if (combat.getAttackingPlayer().equals(controller)) {
final FCollectionView defs = combat.getDefenders();
- defender = controller.getController().chooseSingleEntityForEffect(defs, sa, Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), false);
+ Map params = Maps.newHashMap();
+ params.put("Attacker", c);
+ defender = controller.getController().chooseSingleEntityForEffect(defs, sa,
+ Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), false, params);
}
} else {
defender = Iterables.getFirst(AbilityUtils.getDefinedEntities(host, attacking, sa), null);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/TwoPilesEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TwoPilesEffect.java
index 9c4d2d881a3..d5b03eb83eb 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/TwoPilesEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/TwoPilesEffect.java
@@ -95,7 +95,7 @@ public class TwoPilesEffect extends SpellAbilityEffect {
card.clearRemembered();
// first, separate the cards into piles
- final CardCollectionView pile1 = separator.getController().chooseCardsForEffect(pool, sa, title, 0, size, false);
+ final CardCollectionView pile1 = separator.getController().chooseCardsForEffect(pool, sa, title, 0, size, false, null);
final CardCollection pile2 = new CardCollection(pool);
pile2.removeAll(pile1);
diff --git a/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java b/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java
index 584a1739ffb..d2c1a94dbd5 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java
@@ -81,7 +81,7 @@ public class UntapEffect extends SpellAbilityEffect {
valid, sa.getActivatingPlayer(), sa.getHostCard());
list = CardLists.filter(list, Presets.TAPPED);
- final CardCollectionView selected = p.getController().chooseCardsForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectCardToUntap"), mandatory ? num : 0, num, !mandatory);
+ final CardCollectionView selected = p.getController().chooseCardsForEffect(list, sa, Localizer.getInstance().getMessage("lblSelectCardToUntap"), mandatory ? num : 0, num, !mandatory, null);
if (selected != null) {
for (final Card c : selected) {
c.untap();
diff --git a/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java
index 1353090efd6..b2a41fed62d 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/ZoneExchangeEffect.java
@@ -70,7 +70,7 @@ public class ZoneExchangeEffect extends SpellAbilityEffect {
return;
}
- Card object2 = p.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblChooseaCard"), !sa.hasParam("Mandatory"));
+ Card object2 = p.getController().chooseSingleEntityForEffect(list, sa, Localizer.getInstance().getMessage("lblChooseaCard"), !sa.hasParam("Mandatory"), null);
if (object2 == null || !object2.isInZone(zone2) || (type != null && !object2.getType().hasStringType(type))) {
return;
}
diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java
index b8c474a2d53..658a9bb20d7 100644
--- a/forge-game/src/main/java/forge/game/card/Card.java
+++ b/forge-game/src/main/java/forge/game/card/Card.java
@@ -93,7 +93,6 @@ public class Card extends GameEntity implements Comparable {
private SpellAbility castSA = null;
private final CardDamageHistory damageHistory = new CardDamageHistory();
- private Map> countersAddedBy = Maps.newTreeMap();
// Hidden keywords won't be displayed on the card
private final KeywordCollection hiddenExtrinsicKeyword = new KeywordCollection();
@@ -126,7 +125,7 @@ public class Card extends GameEntity implements Comparable {
private final Multimap cantHaveKeywords = MultimapBuilder.hashKeys().enumSetValues(Keyword.class).build();
- private final Map counterTypeTimestamps = Maps.newEnumMap(CounterType.class);
+ private final Map counterTypeTimestamps = Maps.newHashMap();
private final Map canBlockAdditional = Maps.newTreeMap();
private final Set canBlockAny = Sets.newHashSet();
@@ -264,8 +263,6 @@ public class Card extends GameEntity implements Comparable {
// breaking when the LKI object is changed to a different card state.
private int lkiCMC = -1;
- private int countersAdded = 0;
-
private CardRules cardRules;
private final CardView view;
@@ -1171,7 +1168,6 @@ public class Card extends GameEntity implements Comparable {
@Override
public final boolean canReceiveCounters(final CounterType type) {
-
// CantPutCounter static abilities
for (final Card ca : getGame().getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
@@ -1180,34 +1176,27 @@ public class Card extends GameEntity implements Comparable {
}
}
}
-
- if (type == CounterType.DREAM) {
- // need to be done extra because it is also a state based action
- return !hasKeyword("CARDNAME can't have more than seven dream counters on it.") || getCounters(CounterType.DREAM) <= 6;
- }
return true;
}
- public final int getTotalCountersToAdd() {
- return countersAdded;
- }
-
- public final void setTotalCountersToAdd(int value) {
- countersAdded = value;
- }
-
public final int addCounter(final CounterType counterType, final int n, final Player source, final boolean applyMultiplier, GameEntityCounterTable table) {
return addCounter(counterType, n, source, applyMultiplier, true, table);
}
public final int addCounterFireNoEvents(final CounterType counterType, final int n, final Player source, final boolean applyMultiplier, GameEntityCounterTable table) {
return addCounter(counterType, n, source, applyMultiplier, false, table);
}
+ public final int addCounter(final CounterEnumType counterType, final int n, final Player source, final boolean applyMultiplier, GameEntityCounterTable table) {
+ return addCounter(counterType, n, source, applyMultiplier, true, table);
+ }
+ public final int addCounterFireNoEvents(final CounterEnumType counterType, final int n, final Player source, final boolean applyMultiplier, GameEntityCounterTable table) {
+ return addCounter(counterType, n, source, applyMultiplier, false, table);
+ }
@Override
public int addCounter(final CounterType counterType, final int n, final Player source, final boolean applyMultiplier, final boolean fireEvents, GameEntityCounterTable table) {
int addAmount = n;
- if(addAmount <= 0) {
- addAmount = 0; // As per rule 107.1b
+ if(addAmount <= 0 || !canReceiveCounters(counterType)) {
+ // As per rule 107.1b
return 0;
}
final Map repParams = AbilityKey.mapFromAffected(this);
@@ -1227,19 +1216,9 @@ public class Card extends GameEntity implements Comparable {
return 0;
}
- if (canReceiveCounters(counterType)) {
- if (counterType == CounterType.DREAM && hasKeyword("CARDNAME can't have more than seven dream counters on it.")) {
- addAmount = Math.min(7 - getCounters(CounterType.DREAM), addAmount);
- }
- }
- else {
- addAmount = 0;
- }
-
if (addAmount <= 0) {
return 0;
}
- setTotalCountersToAdd(addAmount);
final Integer oldValue = getCounters(counterType);
final Integer newValue = addAmount + (oldValue == null ? 0 : oldValue);
@@ -1304,7 +1283,7 @@ public class Card extends GameEntity implements Comparable {
long timestamp = game.getNextTimestamp();
counterTypeTimestamps.put(counterType, timestamp);
- addChangedCardKeywords(ImmutableList.of(counterType.getKeyword().toString()), null, false, false, timestamp, updateView);
+ addChangedCardKeywords(ImmutableList.of(counterType.toString()), null, false, false, timestamp, updateView);
return true;
}
@@ -1320,38 +1299,6 @@ public class Card extends GameEntity implements Comparable {
return old != null;
}
- /**
- *
- * addCountersAddedBy.
- *
- * @param source - the card adding the counters to this card
- * @param counterType - the counter type added
- * @param counterAmount - the amount of counters added
- */
- public final void addCountersAddedBy(final Card source, final CounterType counterType, final int counterAmount) {
- final Map counterMap = Maps.newTreeMap();
- counterMap.put(counterType, counterAmount);
- countersAddedBy.put(source, counterMap);
- }
-
- /**
- *
- * getCountersAddedBy.
- *
- * @param source - the card the counters were added by
- * @param counterType - the counter type added
- * @return the amount of counters added.
- */
- public final int getCountersAddedBy(final Card source, final CounterType counterType) {
- int counterAmount = 0;
- if (countersAddedBy.containsKey(source)) {
- final Map counterMap = countersAddedBy.get(source);
- counterAmount = counterMap.containsKey(counterType) ? counterMap.get(counterType) : 0;
- countersAddedBy.remove(source);
- }
- return counterAmount;
- }
-
@Override
public final void subtractCounter(final CounterType counterName, final int n) {
int oldValue = getCounters(counterName);
@@ -1419,7 +1366,7 @@ public class Card extends GameEntity implements Comparable {
view.updateCounters(this);
boolean changed = false;
- for (CounterType ct : counterTypeTimestamps.keySet()) {
+ for (CounterType ct : Lists.newArrayList(counterTypeTimestamps.keySet())) {
if (removeCounterTimestamp(ct, false)) {
changed = true;
}
@@ -1691,7 +1638,7 @@ public class Card extends GameEntity implements Comparable {
} else {
s.append(getName());
s.append(" enters the battlefield with ");
- s.append(Lang.nounWithNumeral(p[2], CounterType.valueOf(p[1]).getName() + " counter"));
+ s.append(Lang.nounWithNumeral(p[2], CounterType.getType(p[1]).getName() + " counter"));
s.append(" on it.");
}
sbLong.append(s).append("\r\n");
@@ -2742,11 +2689,17 @@ public class Card extends GameEntity implements Comparable {
public final void addFacedownCommand(final GameCommand c) {
facedownCommandList.add(c);
}
-
+ public final void runUntapCommands() {
+ for (final GameCommand c : untapCommandList) {
+ c.run();
+ }
+ untapCommandList.clear();
+ }
public final void runUnattachCommands() {
for (final GameCommand c : unattachCommandList) {
c.run();
}
+ unattachCommandList.clear();
}
public final void runFaceupCommands() {
@@ -2931,7 +2884,7 @@ public class Card extends GameEntity implements Comparable {
return false;
}
- return CardLists.count(attachedCards, CardPredicates.Presets.EQUIPMENT) > 0;
+ return Iterables.any(attachedCards, CardPredicates.Presets.EQUIPMENT);
}
public final boolean isEquippedBy(Card c) {
return this.hasCardAttachment(c);
@@ -2953,7 +2906,7 @@ public class Card extends GameEntity implements Comparable {
return false;
}
- return CardLists.count(attachedCards, CardPredicates.Presets.FORTIFICATION) > 0;
+ return Iterables.any(attachedCards, CardPredicates.Presets.FORTIFICATION);
}
public final boolean isFortifiedBy(Card c) {
// 301.5e + 301.6
@@ -3258,7 +3211,7 @@ public class Card extends GameEntity implements Comparable {
}
public final int getCurrentLoyalty() {
- return getCounters(CounterType.LOYALTY);
+ return getCounters(CounterEnumType.LOYALTY);
}
// values that are printed on card
@@ -3509,9 +3462,9 @@ public class Card extends GameEntity implements Comparable {
}
public final int getPowerBonusFromCounters() {
- return getCounters(CounterType.P1P1) + getCounters(CounterType.P1P2) + getCounters(CounterType.P1P0)
- - getCounters(CounterType.M1M1) + 2 * getCounters(CounterType.P2P2) - 2 * getCounters(CounterType.M2M1)
- - 2 * getCounters(CounterType.M2M2) - getCounters(CounterType.M1M0) + 2 * getCounters(CounterType.P2P0);
+ return getCounters(CounterEnumType.P1P1) + getCounters(CounterEnumType.P1P2) + getCounters(CounterEnumType.P1P0)
+ - getCounters(CounterEnumType.M1M1) + 2 * getCounters(CounterEnumType.P2P2) - 2 * getCounters(CounterEnumType.M2M1)
+ - 2 * getCounters(CounterEnumType.M2M2) - getCounters(CounterEnumType.M1M0) + 2 * getCounters(CounterEnumType.P2P0);
}
public final StatBreakdown getNetPowerBreakdown() {
@@ -3567,10 +3520,10 @@ public class Card extends GameEntity implements Comparable {
}
public final int getToughnessBonusFromCounters() {
- return getCounters(CounterType.P1P1) + 2 * getCounters(CounterType.P1P2) - getCounters(CounterType.M1M1)
- + getCounters(CounterType.P0P1) - 2 * getCounters(CounterType.M0M2) + 2 * getCounters(CounterType.P2P2)
- - getCounters(CounterType.M0M1) - getCounters(CounterType.M2M1) - 2 * getCounters(CounterType.M2M2)
- + 2 * getCounters(CounterType.P0P2);
+ return getCounters(CounterEnumType.P1P1) + 2 * getCounters(CounterEnumType.P1P2) - getCounters(CounterEnumType.M1M1)
+ + getCounters(CounterEnumType.P0P1) - 2 * getCounters(CounterEnumType.M0M2) + 2 * getCounters(CounterEnumType.P2P2)
+ - getCounters(CounterEnumType.M0M1) - getCounters(CounterEnumType.M2M1) - 2 * getCounters(CounterEnumType.M2M2)
+ + 2 * getCounters(CounterEnumType.P0P2);
}
public final StatBreakdown getNetToughnessBreakdown() {
@@ -3696,9 +3649,7 @@ public class Card extends GameEntity implements Comparable {
// Run triggers
getGame().getTriggerHandler().runTrigger(TriggerType.Untaps, AbilityKey.mapFromCard(this), false);
- for (final GameCommand var : untapCommandList) {
- var.run();
- }
+ runUntapCommands();
setTapped(false);
getGame().fireEvent(new GameEventCardTapped(this, false));
}
@@ -4266,7 +4217,7 @@ public class Card extends GameEntity implements Comparable {
public final boolean hasSuspend() {
return hasKeyword(Keyword.SUSPEND) && getLastKnownZone().is(ZoneType.Exile)
- && getCounters(CounterType.TIME) >= 1;
+ && getCounters(CounterEnumType.TIME) >= 1;
}
public final boolean isPhasedOut() {
@@ -5143,7 +5094,7 @@ public class Card extends GameEntity implements Comparable {
GameEventCardDamaged.DamageType damageType = DamageType.Normal;
if (isPlaneswalker()) {
- subtractCounter(CounterType.LOYALTY, damageIn);
+ subtractCounter(CounterType.get(CounterEnumType.LOYALTY), damageIn);
}
if (isCreature()) {
final Game game = source.getGame();
@@ -5153,7 +5104,7 @@ public class Card extends GameEntity implements Comparable {
if (isInPlay()) {
if (wither) {
- addCounter(CounterType.M1M1, damageIn, source.getController(), true, counterTable);
+ addCounter(CounterType.get(CounterEnumType.M1M1), damageIn, source.getController(), true, counterTable);
damageType = DamageType.M1M1Counters;
}
else {
diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
index e4f9d12fc83..a583250c15d 100644
--- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
+++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
@@ -836,26 +836,11 @@ public class CardFactoryUtil {
// Count$CountersAddedToPermYouCtrl
if (l[0].startsWith("CountersAddedToPermYouCtrl")) {
final String[] components = l[0].split(" ", 2);
- final CounterType counterType = CounterType.valueOf(components[1]);
+ final CounterType counterType = CounterType.getType(components[1]);
int n = cc.getCounterToPermThisTurn(counterType);
return doXMath(n, m, c);
}
- // Count$CountersAdded
- if (l[0].startsWith("CountersAdded")) {
- final String[] components = l[0].split(" ", 3);
- final CounterType counterType = CounterType.valueOf(components[1]);
- String restrictions = components[2];
- final String[] rest = restrictions.split(",");
- CardCollection candidates = CardLists.getValidCards(game.getCardsInGame(), rest, cc, c, null);
-
- int added = 0;
- for (final Card counterSource : candidates) {
- added += c.getCountersAddedBy(counterSource, counterType);
- }
- return doXMath(added, m, c);
- }
-
if (l[0].startsWith("CommanderCastFromCommandZone")) {
// only used by Opal Palace, and it does add the trigger to the card
return doXMath(cc.getCommanderCast(c), m, c);
@@ -2150,7 +2135,7 @@ public class CardFactoryUtil {
String[] splitkw = parse.split(":");
String desc = "CARDNAME enters the battlefield with ";
- desc += Lang.nounWithNumeral(splitkw[2], CounterType.valueOf(splitkw[1]).getName() + " counter");
+ desc += Lang.nounWithNumeral(splitkw[2], CounterType.getType(splitkw[1]).getName() + " counter");
desc += " on it.";
String extraparams = "";
@@ -3591,7 +3576,7 @@ public class CardFactoryUtil {
} else if (keyword.equals("Sunburst")) {
// Rule 702.43a If this object is entering the battlefield as a creature,
// ignoring any type-changing effects that would affect it
- CounterType t = card.isCreature() ? CounterType.P1P1 : CounterType.CHARGE;
+ CounterType t = CounterType.get(card.isCreature() ? CounterEnumType.P1P1 : CounterEnumType.CHARGE);
StringBuilder sb = new StringBuilder("etbCounter:");
sb.append(t).append(":Sunburst:no Condition:");
@@ -4302,7 +4287,7 @@ public class CardFactoryUtil {
int counters = AbilityUtils.calculateAmount(c, k[1], this);
GameEntityCounterTable table = new GameEntityCounterTable();
- c.addCounter(CounterType.TIME, counters, getActivatingPlayer(), true, table);
+ c.addCounter(CounterEnumType.TIME, counters, getActivatingPlayer(), true, table);
table.triggerCountersPutAll(game);
String sb = TextUtil.concatWithSpace(getActivatingPlayer().toString(),"has suspended", c.getName(), "with", String.valueOf(counters),"time counters on it.");
diff --git a/forge-game/src/main/java/forge/game/card/CardPredicates.java b/forge-game/src/main/java/forge/game/card/CardPredicates.java
index 3994c04e3e7..6104f053fd2 100644
--- a/forge-game/src/main/java/forge/game/card/CardPredicates.java
+++ b/forge-game/src/main/java/forge/game/card/CardPredicates.java
@@ -329,6 +329,9 @@ public final class CardPredicates {
public static final Predicate hasCounter(final CounterType type) {
return hasCounter(type, 1);
}
+ public static final Predicate hasCounter(final CounterEnumType type) {
+ return hasCounter(type, 1);
+ }
public static final Predicate hasCounter(final CounterType type, final int n) {
return new Predicate() {
@@ -338,6 +341,9 @@ public final class CardPredicates {
}
};
}
+ public static final Predicate hasCounter(final CounterEnumType type, final int n) {
+ return hasCounter(CounterType.get(type), n);
+ }
public static final Predicate hasLessCounter(final CounterType type, final int n) {
return new Predicate() {
@@ -348,6 +354,9 @@ public final class CardPredicates {
}
};
}
+ public static final Predicate hasLessCounter(final CounterEnumType type, final int n) {
+ return hasLessCounter(CounterType.get(type), n);
+ }
public static Predicate canReceiveCounters(final CounterType counter) {
return new Predicate() {
@@ -357,6 +366,9 @@ public final class CardPredicates {
}
};
}
+ public static Predicate canReceiveCounters(final CounterEnumType counter) {
+ return canReceiveCounters(CounterType.get(counter));
+ }
public static final Predicate hasGreaterPowerThan(final int minPower) {
return new Predicate() {
@@ -376,6 +388,9 @@ public final class CardPredicates {
}
};
}
+ public static final Comparator compareByCounterType(final CounterEnumType type) {
+ return compareByCounterType(CounterType.get(type));
+ }
public static final Predicate hasSVar(final String name) {
return new Predicate() {
diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java
index a0af629a150..a88fb4ed226 100644
--- a/forge-game/src/main/java/forge/game/card/CardUtil.java
+++ b/forge-game/src/main/java/forge/game/card/CardUtil.java
@@ -244,7 +244,7 @@ public final class CardUtil {
newCopy.setBasePower(in.getCurrentPower() + in.getTempPowerBoost());
newCopy.setBaseToughness(in.getCurrentToughness() + in.getTempToughnessBoost());
- newCopy.setCounters(Maps.newEnumMap(in.getCounters()));
+ newCopy.setCounters(Maps.newHashMap(in.getCounters()));
newCopy.setColor(in.determineColor().getColor());
newCopy.setReceivedDamageFromThisTurn(in.getReceivedDamageFromThisTurn());
diff --git a/forge-game/src/main/java/forge/game/card/CounterEnumType.java b/forge-game/src/main/java/forge/game/card/CounterEnumType.java
new file mode 100644
index 00000000000..23190fdafbb
--- /dev/null
+++ b/forge-game/src/main/java/forge/game/card/CounterEnumType.java
@@ -0,0 +1,390 @@
+/*
+ * 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.card;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * The class Counters.
+ *
+ * @author Clemens Koza
+ * @version V0.0 17.02.2010
+ */
+public enum CounterEnumType {
+
+ M1M1("-1/-1", "-1/-1", 255, 110, 106),
+ P1P1("+1/+1", "+1/+1", 96, 226, 23),
+
+ LOYALTY("LOYAL", 198, 198, 198),
+
+ AGE("AGE", 255, 137, 57),
+
+ AIM("AIM", 255, 180, 0),
+
+ ARROW("ARROW", 237, 195, 0),
+
+ ARROWHEAD("ARWHD", 230, 191, 167),
+
+ AWAKENING("AWAKE", 0, 231, 79),
+
+ BLAZE("BLAZE", 255, 124, 82),
+
+ BLOOD("BLOOD", 255, 108, 111),
+
+ BOUNTY("BOUNT", 255, 158, 0),
+
+ BRIBERY("BRIBE", 172, 201, 235),
+
+ BRICK("BRICK", 226, 192, 164),
+
+ CAGE("CAGE", 155, 155, 155),
+
+ CARRION("CRRON", 255, 163, 222),
+
+ CHARGE("CHARG", 246, 192, 0),
+
+ COIN("COIN",255,215,0),
+
+ CORPSE("CRPSE", 230, 186, 209),
+
+ CREDIT("CRDIT", 188, 197, 234),
+
+ CRYSTAL("CRYST", 255, 85, 206),
+
+ CUBE("CUBE", 148, 219, 0),
+
+ CURRENCY("CURR", 223, 200, 0),
+
+ DEATH("DEATH", 255, 108, 110),
+
+ DELAY("DELAY", 102, 206, 255),
+
+ DEPLETION("DPLT", 185, 201, 208),
+
+ DESPAIR("DESPR", 238, 186, 187),
+
+ DEVOTION("DEVOT", 255, 111, 255),
+
+ DIVINITY("DVNTY", 0, 233, 255),
+
+ DOOM("DOOM", 255, 104, 118),
+
+ DREAM("DREAM", 190, 189, 255),
+
+ ECHO("ECHO", 225, 180, 255),
+
+ EGG("EGG", 255, 245, 195),
+
+ ELIXIR("ELIXR", 81, 221, 175),
+
+ EON("EON", 23, 194, 255),
+
+ EYEBALL("EYE", 184, 202, 201),
+
+ FADE("FADE", 159, 209, 192),
+
+ FATE("FATE", 255, 164, 226),
+
+ FEATHER("FTHR", 195, 202, 165),
+
+ FILIBUSTER("FLBTR", 255, 179, 119),
+
+ FLAME("FLAME", 255, 143, 43),
+
+ FLOOD("FLOOD", 0, 203, 255),
+
+ FORESHADOW("FRSHD",144,99, 207),
+
+ FUNGUS("FNGUS", 121, 219, 151),
+
+ FURY("FURY", 255, 120, 89),
+
+ FUSE("FUSE", 255, 122, 85),
+
+ GEM("GEM", 255, 99, 251),
+
+ GLYPH("GLYPH", 184, 202, 199),
+
+ GOLD("GOLD", 248, 191, 0),
+
+ GROWTH("GRWTH", 87, 226, 32),
+
+ HATCHLING("HATCH", 201, 199, 186),
+
+ HEALING("HEAL", 255, 166, 236),
+
+ HIT("HIT", 255, 245, 195),
+
+ HOOFPRINT("HOOF", 233, 189, 170),
+
+ HOUR("HOUR", 198, 197, 210),
+
+ HOURGLASS("HRGLS", 0, 215, 255),
+
+ HUNGER("HUNGR", 255, 91, 149),
+
+ ICE("ICE", 0, 239, 255),
+
+ INFECTION("INFCT", 0, 230, 66),
+
+ INTERVENTION("INTRV", 205, 203, 105),
+
+ ISOLATION("ISOLT", 250, 190, 0),
+
+ JAVELIN("JAVLN", 180, 206, 172),
+
+ KI("KI", 190, 189, 255),
+
+ KNOWLEDGE("KNOWLEDGE", 0, 115, 255),
+
+ LANDMARK("LNMRK", 186, 28, 28),
+
+ LEVEL("LEVEL", 60, 222, 185),
+
+ LORE("LORE", 209, 198, 161),
+
+ LUCK("LUCK", 185, 174, 255),
+
+ M0M1("-0/-1", "-0/-1", 255, 110, 106),
+
+ M0M2("-0/-2", "-0/-2", 255, 110, 106),
+
+ M1M0("-1/-0", "-1/-0", 255, 110, 106),
+
+ M2M1("-2/-1", "-2/-1", 255, 110, 106),
+
+ M2M2("-2/-2", "-2/-2", 255, 110, 106),
+
+ MAGNET("MAGNT", 198, 197, 210),
+
+ MANA("MANA", 0, 237, 152),
+
+ MANIFESTATION("MNFST", 104, 225, 8),
+
+ MANNEQUIN("MANQN", 206, 199, 162),
+
+ MATRIX("MATRX", 183, 174, 255),
+
+ MINE("MINE", 255, 100, 127),
+
+ MINING("MINNG", 184, 201, 207),
+
+ MIRE("MIRE", 153, 209, 199),
+
+ MUSIC("MUSIC", 255, 138, 255),
+
+ MUSTER("MUSTR", 235, 196, 0),
+
+ NET("NET", 0, 221, 251),
+
+ OMEN("OMEN", 255, 178, 120),
+
+ ORE("ORE", 200, 201, 163),
+
+ PAGE("PAGE", 218, 195, 162),
+
+ PAIN("PAIN", 255, 108, 111),
+
+ PARALYZATION("PRLYZ", 220, 201, 0),
+
+ PETAL("PETAL", 255, 162, 216),
+
+ PETRIFICATION("PETRI", 185, 201, 208),
+
+ PIN("PIN", 194, 196, 233),
+
+ PLAGUE("PLGUE", 94, 226, 25),
+
+ PLOT("PLOT", 255, 172, 133),
+
+ PRESSURE("PRESS", 255, 164, 159),
+
+ PHYLACTERY("PHYLA", 117, 219, 153),
+
+ POLYP("POLYP", 236, 185, 198),
+
+ PREY("PREY", 240, 0, 0),
+
+ PUPA("PUPA", 0, 223, 203),
+
+ P0P1("+0/+1", "+0/+1", 96, 226, 23),
+
+ P0P2("+0/+2", "+0/+2", 96, 226, 23),
+
+ P1P0("+1/+0", "+1/+0", 96, 226, 23),
+
+ P1P2("+1/+2", "+1/+2", 96, 226, 23),
+
+ P2P0("+2/+0", "+2/+0", 96, 226, 23),
+
+ P2P2("+2/+2", "+2/+2", 96, 226, 23),
+
+ QUEST("QUEST", 251, 189, 0),
+
+ RUST("RUST", 255, 181, 116),
+
+ SCREAM("SCREM", 0, 220, 255),
+
+ SCROLL("SCRLL", 206, 199, 162),
+
+ SHELL("SHELL", 190, 207, 111),
+
+ SHIELD("SHLD", 202, 198, 186),
+
+ SHRED("SHRED", 255, 165, 152),
+
+ SILVER("SILVER", 192, 192, 192),
+
+ SLEEP("SLEEP", 178, 192, 255),
+
+ SLUMBER("SLMBR", 178, 205, 255),
+
+ SLEIGHT("SLGHT", 185, 174, 255),
+
+ SLIME("SLIME", 101, 220, 163),
+
+ SOUL("SOUL", 243, 190, 247),
+
+ SOOT("SOOT", 211, 194, 198),
+
+ SPITE("SPITE", 0, 218, 255),
+
+ SPORE("SPORE", 122, 218, 150),
+
+ STORAGE("STORG", 255, 177, 121),
+
+ STRIFE("STRFE", 255, 89, 223),
+
+ STUDY("STUDY", 226, 192, 165),
+
+ TASK("TASK", 191, 63, 49),
+
+ THEFT("THEFT", 255, 176, 125),
+
+ TIDE("TIDE", 0, 212, 187),
+
+ TIME("TIME", 255, 121, 255),
+
+ TOWER("tower", "TOWER", 0, 239, 255),
+
+ TRAINING("TRAIN", 220, 201, 0),
+
+ TRAP("TRAP", 255, 121, 86),
+
+ TREASURE("TRSUR", 255, 184, 0),
+
+ UNITY("UNITY", 242, 156, 255),
+
+ VELOCITY("VELO", 255, 95, 138),
+
+ VERSE("VERSE", 0, 237, 155),
+
+ VITALITY("VITAL", 255, 94, 142),
+
+ VORTEX("VORTX", 142, 200, 255),
+
+ WAGE("WAGE", 242, 190, 106),
+
+ WINCH("WINCH", 208, 195, 203),
+
+ WIND("WIND", 0, 236, 255),
+
+ WISH("WISH", 255, 85, 206),
+
+ // Player Counters
+
+ ENERGY("ENRGY"),
+
+ EXPERIENCE("EXP"),
+
+ POISON("POISN"),
+
+ // Keyword Counters
+/*
+ FLYING("Flying"),
+ FIRSTSTRIKE("First Strike"),
+ DOUBLESTRIKE("Double Strike"),
+ DEATHTOUCH("Deathtouch"),
+ HEXPROOF("Hexproof"),
+ INDESTRUCTIBLE("Indestructible"),
+ LIFELINK("Lifelink"),
+ MENACE("Menace"),
+ REACH("Reach"),
+ TRAMPLE("Trample"),
+ VIGILANCE("Vigilance")
+//*/
+ ;
+
+ private String name, counterOnCardDisplayName;
+ private int red, green, blue;
+
+ CounterEnumType() {
+ this.name = this.name().substring(0, 1).toUpperCase() + this.name().substring(1).toLowerCase();
+ if (red == 0 && green == 0 && blue == 0) {
+ red = 255;
+ green = 255;
+ blue = 255;
+ }
+ }
+
+ CounterEnumType(final String counterOnCardDisplayName) {
+ this();
+ this.counterOnCardDisplayName = counterOnCardDisplayName;
+ }
+
+ CounterEnumType(final String counterOnCardDisplayName, final int red, final int green, final int blue) {
+ this(counterOnCardDisplayName);
+ this.red = red;
+ this.green = green;
+ this.blue = blue;
+ }
+
+ CounterEnumType(final String name, final String counterOnCardDisplayName, final int red, final int green, final int blue) {
+ this(counterOnCardDisplayName, red, green, blue);
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public int getRed() {
+ return red;
+ }
+
+ public int getGreen() {
+ return green;
+ }
+
+ public int getBlue() {
+ return blue;
+ }
+
+ public String getCounterOnCardDisplayName() {
+ return counterOnCardDisplayName;
+ }
+
+ public static CounterEnumType getType(final String name) {
+ final String replacedName = name.replace("/", "").replaceAll("\\+", "p").replaceAll("\\-", "m").toUpperCase();
+ return Enum.valueOf(CounterEnumType.class, replacedName);
+ }
+
+ public static final ImmutableList values = ImmutableList.copyOf(values());
+
+}
diff --git a/forge-game/src/main/java/forge/game/card/CounterType.java b/forge-game/src/main/java/forge/game/card/CounterType.java
index b754e28d976..22dfca9ebda 100644
--- a/forge-game/src/main/java/forge/game/card/CounterType.java
+++ b/forge-game/src/main/java/forge/game/card/CounterType.java
@@ -1,425 +1,130 @@
-/*
- * 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.card;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+
+import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
-
-import forge.game.keyword.Keyword;
-
-/**
- * The class Counters.
- *
- * @author Clemens Koza
- * @version V0.0 17.02.2010
- */
-public enum CounterType {
-
- M1M1("-1/-1", "-1/-1", 255, 110, 106),
- P1P1("+1/+1", "+1/+1", 96, 226, 23),
-
- LOYALTY("LOYAL", 198, 198, 198),
-
- AGE("AGE", 255, 137, 57),
-
- AIM("AIM", 255, 180, 0),
-
- ARROW("ARROW", 237, 195, 0),
-
- ARROWHEAD("ARWHD", 230, 191, 167),
-
- AWAKENING("AWAKE", 0, 231, 79),
-
- BLAZE("BLAZE", 255, 124, 82),
-
- BLOOD("BLOOD", 255, 108, 111),
-
- BOUNTY("BOUNT", 255, 158, 0),
-
- BRIBERY("BRIBE", 172, 201, 235),
-
- BRICK("BRICK", 226, 192, 164),
-
- CAGE("CAGE", 155, 155, 155),
-
- CARRION("CRRON", 255, 163, 222),
-
- CHARGE("CHARG", 246, 192, 0),
-
- COIN("COIN",255,215,0),
-
- CORPSE("CRPSE", 230, 186, 209),
-
- CREDIT("CRDIT", 188, 197, 234),
-
- CRYSTAL("CRYST", 255, 85, 206),
-
- CUBE("CUBE", 148, 219, 0),
-
- CURRENCY("CURR", 223, 200, 0),
-
- DEATH("DEATH", 255, 108, 110),
-
- DELAY("DELAY", 102, 206, 255),
-
- DEPLETION("DPLT", 185, 201, 208),
-
- DESPAIR("DESPR", 238, 186, 187),
-
- DEVOTION("DEVOT", 255, 111, 255),
-
- DIVINITY("DVNTY", 0, 233, 255),
-
- DOOM("DOOM", 255, 104, 118),
-
- DREAM("DREAM", 190, 189, 255),
-
- ECHO("ECHO", 225, 180, 255),
-
- EGG("EGG", 255, 245, 195),
-
- ELIXIR("ELIXR", 81, 221, 175),
-
- EON("EON", 23, 194, 255),
-
- EYEBALL("EYE", 184, 202, 201),
-
- FADE("FADE", 159, 209, 192),
-
- FATE("FATE", 255, 164, 226),
-
- FEATHER("FTHR", 195, 202, 165),
-
- FILIBUSTER("FLBTR", 255, 179, 119),
-
- FLAME("FLAME", 255, 143, 43),
-
- FLOOD("FLOOD", 0, 203, 255),
-
- FORESHADOW("FRSHD",144,99, 207),
-
- FUNGUS("FNGUS", 121, 219, 151),
-
- FURY("FURY", 255, 120, 89),
-
- FUSE("FUSE", 255, 122, 85),
-
- GEM("GEM", 255, 99, 251),
-
- GLYPH("GLYPH", 184, 202, 199),
-
- GOLD("GOLD", 248, 191, 0),
-
- GROWTH("GRWTH", 87, 226, 32),
-
- HATCHLING("HATCH", 201, 199, 186),
-
- HEALING("HEAL", 255, 166, 236),
-
- HIT("HIT", 255, 245, 195),
-
- HOOFPRINT("HOOF", 233, 189, 170),
-
- HOUR("HOUR", 198, 197, 210),
-
- HOURGLASS("HRGLS", 0, 215, 255),
-
- HUNGER("HUNGR", 255, 91, 149),
-
- ICE("ICE", 0, 239, 255),
-
- INFECTION("INFCT", 0, 230, 66),
-
- INTERVENTION("INTRV", 205, 203, 105),
-
- ISOLATION("ISOLT", 250, 190, 0),
-
- JAVELIN("JAVLN", 180, 206, 172),
-
- KI("KI", 190, 189, 255),
-
- KNOWLEDGE("KNOWLEDGE", 0, 115, 255),
-
- LANDMARK("LNMRK", 186, 28, 28),
-
- LEVEL("LEVEL", 60, 222, 185),
-
- LORE("LORE", 209, 198, 161),
-
- LUCK("LUCK", 185, 174, 255),
-
- M0M1("-0/-1", "-0/-1", 255, 110, 106),
-
- M0M2("-0/-2", "-0/-2", 255, 110, 106),
-
- M1M0("-1/-0", "-1/-0", 255, 110, 106),
-
- M2M1("-2/-1", "-2/-1", 255, 110, 106),
-
- M2M2("-2/-2", "-2/-2", 255, 110, 106),
-
- MAGNET("MAGNT", 198, 197, 210),
-
- MANA("MANA", 0, 237, 152),
-
- MANIFESTATION("MNFST", 104, 225, 8),
-
- MANNEQUIN("MANQN", 206, 199, 162),
-
- MATRIX("MATRX", 183, 174, 255),
-
- MINE("MINE", 255, 100, 127),
-
- MINING("MINNG", 184, 201, 207),
-
- MIRE("MIRE", 153, 209, 199),
-
- MUSIC("MUSIC", 255, 138, 255),
-
- MUSTER("MUSTR", 235, 196, 0),
-
- NET("NET", 0, 221, 251),
-
- OMEN("OMEN", 255, 178, 120),
-
- ORE("ORE", 200, 201, 163),
-
- PAGE("PAGE", 218, 195, 162),
-
- PAIN("PAIN", 255, 108, 111),
-
- PARALYZATION("PRLYZ", 220, 201, 0),
-
- PETAL("PETAL", 255, 162, 216),
-
- PETRIFICATION("PETRI", 185, 201, 208),
-
- PIN("PIN", 194, 196, 233),
-
- PLAGUE("PLGUE", 94, 226, 25),
-
- PLOT("PLOT", 255, 172, 133),
-
- PRESSURE("PRESS", 255, 164, 159),
-
- PHYLACTERY("PHYLA", 117, 219, 153),
-
- POLYP("POLYP", 236, 185, 198),
-
- PREY("PREY", 240, 0, 0),
-
- PUPA("PUPA", 0, 223, 203),
-
- P0P1("+0/+1", "+0/+1", 96, 226, 23),
-
- P0P2("+0/+2", "+0/+2", 96, 226, 23),
-
- P1P0("+1/+0", "+1/+0", 96, 226, 23),
-
- P1P2("+1/+2", "+1/+2", 96, 226, 23),
-
- P2P0("+2/+0", "+2/+0", 96, 226, 23),
-
- P2P2("+2/+2", "+2/+2", 96, 226, 23),
-
- QUEST("QUEST", 251, 189, 0),
-
- RUST("RUST", 255, 181, 116),
-
- SCREAM("SCREM", 0, 220, 255),
-
- SCROLL("SCRLL", 206, 199, 162),
-
- SHELL("SHELL", 190, 207, 111),
-
- SHIELD("SHLD", 202, 198, 186),
-
- SHRED("SHRED", 255, 165, 152),
-
- SILVER("SILVER", 192, 192, 192),
-
- SLEEP("SLEEP", 178, 192, 255),
-
- SLUMBER("SLMBR", 178, 205, 255),
-
- SLEIGHT("SLGHT", 185, 174, 255),
-
- SLIME("SLIME", 101, 220, 163),
-
- SOUL("SOUL", 243, 190, 247),
-
- SOOT("SOOT", 211, 194, 198),
-
- SPITE("SPITE", 0, 218, 255),
-
- SPORE("SPORE", 122, 218, 150),
-
- STORAGE("STORG", 255, 177, 121),
-
- STRIFE("STRFE", 255, 89, 223),
-
- STUDY("STUDY", 226, 192, 165),
-
- TASK("TASK", 191, 63, 49),
-
- THEFT("THEFT", 255, 176, 125),
-
- TIDE("TIDE", 0, 212, 187),
-
- TIME("TIME", 255, 121, 255),
-
- TOWER("tower", "TOWER", 0, 239, 255),
-
- TRAINING("TRAIN", 220, 201, 0),
-
- TRAP("TRAP", 255, 121, 86),
-
- TREASURE("TRSUR", 255, 184, 0),
-
- UNITY("UNITY", 242, 156, 255),
-
- VELOCITY("VELO", 255, 95, 138),
-
- VERSE("VERSE", 0, 237, 155),
-
- VITALITY("VITAL", 255, 94, 142),
-
- VORTEX("VORTX", 142, 200, 255),
-
- WAGE("WAGE", 242, 190, 106),
-
- WINCH("WINCH", 208, 195, 203),
-
- WIND("WIND", 0, 236, 255),
-
- WISH("WISH", 255, 85, 206),
-
- // Player Counters
-
- ENERGY("ENRGY"),
-
- EXPERIENCE("EXP"),
-
- POISON("POISN"),
-
- // Keyword Counters
-
- FLYING("Flying"),
- FIRSTSTRIKE("First Strike"),
- DOUBLESTRIKE("Double Strike"),
- DEATHTOUCH("Deathtouch"),
- HEXPROOF("Hexproof"),
- INDESTRUCTIBLE("Indestructible"),
- LIFELINK("Lifelink"),
- MENACE("Menace"),
- REACH("Reach"),
- TRAMPLE("Trample"),
- VIGILANCE("Vigilance")
-
- ;
-
- private String name, counterOnCardDisplayName;
- private int red, green, blue;
-
- CounterType() {
- this.name = this.name().substring(0, 1).toUpperCase() + this.name().substring(1).toLowerCase();
- if (red == 0 && green == 0 && blue == 0) {
- red = 255;
- green = 255;
- blue = 255;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Ordering;
+
+public class CounterType implements Comparable {
+ private CounterEnumType eVal = null;
+ private String sVal = null;
+
+ // Rule 122.1b
+ static ImmutableList keywordCounter = ImmutableList.of(
+ "Flying", "First Strike", "Double Strike", "Deathtouch", "Haste", "Hexproof",
+ "Indestructible", "Lifelink", "Menace", "Reach", "Trample", "Vigilance");
+
+ private static Map eMap = Maps.newEnumMap(CounterEnumType.class);
+ private static Map sMap = Maps.newHashMap();
+
+ private CounterType(CounterEnumType e, String s) {
+ this.eVal = e;
+ this.sVal = s;
+ }
+
+ public static CounterType get(CounterEnumType e) {
+ if (!eMap.containsKey(e)) {
+ eMap.put(e, new CounterType(e, null));
+ }
+ return eMap.get(e);
+ }
+
+ public static CounterType get(String s) {
+ if (!sMap.containsKey(s)) {
+ sMap.put(s, new CounterType(null, s));
+ }
+ return sMap.get(s);
+ }
+
+ public static CounterType getType(String name) {
+ try {
+ return get(CounterEnumType.getType(name));
+ } catch (final IllegalArgumentException ex) {
+ return get(name);
}
}
- CounterType(final String counterOnCardDisplayName) {
- this();
- this.counterOnCardDisplayName = counterOnCardDisplayName;
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(eVal, sVal);
}
- CounterType(final String counterOnCardDisplayName, final int red, final int green, final int blue) {
- this(counterOnCardDisplayName);
- this.red = red;
- this.green = green;
- this.blue = blue;
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }
+ CounterType rhs = (CounterType) obj;
+ return new EqualsBuilder()
+ .append(eVal, rhs.eVal)
+ .append(sVal, rhs.sVal)
+ .isEquals();
}
- CounterType(final String name, final String counterOnCardDisplayName, final int red, final int green, final int blue) {
- this(counterOnCardDisplayName, red, green, blue);
- this.name = name;
+ @Override
+ public String toString() {
+ return eVal != null ? eVal.toString() : sVal;
}
public String getName() {
- return this.name;
- }
-
- public int getRed() {
- return red;
- }
-
- public int getGreen() {
- return green;
- }
-
- public int getBlue() {
- return blue;
+ return eVal != null ? eVal.getName() : getKeywordDescription();
}
public String getCounterOnCardDisplayName() {
- return counterOnCardDisplayName;
+ return eVal != null ? eVal.getCounterOnCardDisplayName() : getKeywordDescription();
}
- public static CounterType getType(final String name) {
- final String replacedName = name.replace("/", "").replaceAll("\\+", "p").replaceAll("\\-", "m").toUpperCase();
- return Enum.valueOf(CounterType.class, replacedName);
+ private String getKeywordDescription() {
+ if (sVal.startsWith("Hexproof:")) {
+ final String[] k = sVal.split(":");
+ return "Hexproof from " + k[2];
+ }
+ return sVal;
+ }
+
+ @Override
+ public int compareTo(CounterType o) {
+ return ComparisonChain.start()
+ .compare(eVal, o.eVal, Ordering.natural().nullsLast())
+ .compare(sVal, o.sVal, Ordering.natural().nullsLast())
+ .result();
+ }
+
+ public boolean is(CounterEnumType eType) {
+ return eVal == eType;
}
public boolean isKeywordCounter() {
- return this.getKeyword() != null;
- }
-
- public Keyword getKeyword() {
- switch (this) {
- case FLYING:
- return Keyword.FLYING;
- case FIRSTSTRIKE:
- return Keyword.FIRST_STRIKE;
- case DOUBLESTRIKE:
- return Keyword.DOUBLE_STRIKE;
- case DEATHTOUCH:
- return Keyword.DEATHTOUCH;
- case HEXPROOF:
- return Keyword.HEXPROOF;
- case INDESTRUCTIBLE:
- return Keyword.INDESTRUCTIBLE;
- case LIFELINK:
- return Keyword.LIFELINK;
- case MENACE:
- return Keyword.MENACE;
- case REACH:
- return Keyword.REACH;
- case TRAMPLE:
- return Keyword.TRAMPLE;
- case VIGILANCE:
- return Keyword.VIGILANCE;
- default:
- return null;
+ if (eVal != null) {
+ return false;
}
+ if (sVal.startsWith("Hexproof:")) {
+ return true;
+ }
+ return keywordCounter.contains(sVal);
}
- public static final ImmutableList values = ImmutableList.copyOf(values());
+ public int getRed() {
+ return eVal != null ? eVal.getRed() : 255;
+ }
+ public int getGreen() {
+ return eVal != null ? eVal.getGreen() : 255;
+ }
+
+ public int getBlue() {
+ return eVal != null ? eVal.getBlue() : 255;
+ }
}
diff --git a/forge-game/src/main/java/forge/game/combat/AttackConstraints.java b/forge-game/src/main/java/forge/game/combat/AttackConstraints.java
index 181c27e769e..cee20c3d256 100644
--- a/forge-game/src/main/java/forge/game/combat/AttackConstraints.java
+++ b/forge-game/src/main/java/forge/game/combat/AttackConstraints.java
@@ -37,7 +37,7 @@ public class AttackConstraints {
// Number of "must attack" constraints on each creature with a magnet counter (equal to the number of permanents requiring that constraint).
int nMagnetRequirements = 0;
- final CardCollectionView magnetAttackers = CardLists.filter(possibleAttackers, CardPredicates.hasCounter(CounterType.MAGNET));
+ final CardCollectionView magnetAttackers = CardLists.filter(possibleAttackers, CardPredicates.hasCounter(CounterEnumType.MAGNET));
// Only require if a creature with a magnet counter on it attacks.
if (!magnetAttackers.isEmpty()) {
nMagnetRequirements = CardLists.getAmountOfKeyword(
@@ -68,7 +68,7 @@ public class AttackConstraints {
}
}
- if (possibleAttacker.getCounters(CounterType.MAGNET) > 0) {
+ if (possibleAttacker.getCounters(CounterEnumType.MAGNET) > 0) {
for (final Card c : magnetAttackers) {
if (c != possibleAttacker) {
causesToAttack.add(c, nMagnetRequirements);
diff --git a/forge-game/src/main/java/forge/game/cost/Cost.java b/forge-game/src/main/java/forge/game/cost/Cost.java
index e8e92ce1aff..46c2ab66987 100644
--- a/forge-game/src/main/java/forge/game/cost/Cost.java
+++ b/forge-game/src/main/java/forge/game/cost/Cost.java
@@ -311,7 +311,7 @@ public class Cost implements Serializable {
final String description = splitStr.length > 3 ? splitStr[3] : null;
final ZoneType zone = splitStr.length > 4 ? ZoneType.smartValueOf(splitStr[4]) : ZoneType.Battlefield;
- return new CostRemoveCounter(splitStr[0], CounterType.valueOf(splitStr[1]), type, description, zone);
+ return new CostRemoveCounter(splitStr[0], CounterType.getType(splitStr[1]), type, description, zone);
}
if (parse.startsWith("AddCounter<")) {
@@ -319,7 +319,7 @@ public class Cost implements Serializable {
final String[] splitStr = abCostParse(parse, 4);
final String target = splitStr.length > 2 ? splitStr[2] : "CARDNAME";
final String description = splitStr.length > 3 ? splitStr[3] : null;
- return new CostPutCounter(splitStr[0], CounterType.valueOf(splitStr[1]), target, description);
+ return new CostPutCounter(splitStr[0], CounterType.getType(splitStr[1]), target, description);
}
// While no card has "PayLife<2> PayLife<3> there might be a card that
diff --git a/forge-game/src/main/java/forge/game/cost/CostPayEnergy.java b/forge-game/src/main/java/forge/game/cost/CostPayEnergy.java
index 768a7876c15..5402e5e6749 100644
--- a/forge-game/src/main/java/forge/game/cost/CostPayEnergy.java
+++ b/forge-game/src/main/java/forge/game/cost/CostPayEnergy.java
@@ -21,7 +21,7 @@ import com.google.common.base.Strings;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
-import forge.game.card.CounterType;
+import forge.game.card.CounterEnumType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -89,7 +89,7 @@ public class CostPayEnergy extends CostPart {
}
}
- return payer.getCounters(CounterType.ENERGY) >= amount;
+ return payer.getCounters(CounterEnumType.ENERGY) >= amount;
}
@Override
diff --git a/forge-game/src/main/java/forge/game/cost/CostPutCounter.java b/forge-game/src/main/java/forge/game/cost/CostPutCounter.java
index 5ce5d63305d..d48ab6b73ed 100644
--- a/forge-game/src/main/java/forge/game/cost/CostPutCounter.java
+++ b/forge-game/src/main/java/forge/game/cost/CostPutCounter.java
@@ -21,6 +21,7 @@ import forge.game.GameEntityCounterTable;
import forge.game.card.Card;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -78,7 +79,7 @@ public class CostPutCounter extends CostPartWithList {
@Override
public boolean isReusable() {
- return counter != CounterType.M1M1;
+ return !counter.is(CounterEnumType.M1M1);
}
/*
@@ -89,7 +90,7 @@ public class CostPutCounter extends CostPartWithList {
@Override
public final String toString() {
final StringBuilder sb = new StringBuilder();
- if (this.counter == CounterType.LOYALTY) {
+ if (this.counter.is(CounterEnumType.LOYALTY)) {
if (this.getAmount().equals("0")) {
sb.append("0");
}
diff --git a/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java b/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java
index 7434d7add6f..d03d99cd45b 100644
--- a/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java
+++ b/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java
@@ -21,6 +21,7 @@ import com.google.common.collect.Lists;
import forge.game.card.Card;
import forge.game.card.CardLists;
+import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -82,7 +83,7 @@ public class CostRemoveCounter extends CostPartWithList {
@Override
public final String toString() {
final StringBuilder sb = new StringBuilder();
- if (this.counter == CounterType.LOYALTY) {
+ if (this.counter.is(CounterEnumType.LOYALTY)) {
sb.append("-").append(this.getAmount());
} else {
sb.append("Remove ");
diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
index 1e2ca2085d5..f74e2061a93 100644
--- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
+++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java
@@ -28,9 +28,9 @@ import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
-import forge.game.card.CounterType;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardZoneTable;
+import forge.game.card.CounterEnumType;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
@@ -268,7 +268,7 @@ public class PhaseHandler implements java.io.Serializable {
// all Saga get Lore counter at the begin of pre combat
for (Card c : playerTurn.getCardsIn(ZoneType.Battlefield)) {
if (c.getType().hasSubtype("Saga")) {
- c.addCounter(CounterType.LORE, 1, null, false, table);
+ c.addCounter(CounterEnumType.LORE, 1, null, false, table);
}
}
table.triggerCountersPutAll(game);
@@ -861,7 +861,7 @@ public class PhaseHandler implements java.io.Serializable {
boolean untapTimeVault = nextPlayer.getController().chooseBinary(fakeSA, "Skip a turn to untap a Time Vault?", BinaryChoiceType.UntapTimeVault, false);
if (untapTimeVault) {
if (vaults.size() > 1) {
- Card c = nextPlayer.getController().chooseSingleEntityForEffect(vaults, fakeSA, "Which Time Vault do you want to Untap?");
+ Card c = nextPlayer.getController().chooseSingleEntityForEffect(vaults, fakeSA, "Which Time Vault do you want to Untap?", null);
if (c != null)
crd = c;
}
diff --git a/forge-game/src/main/java/forge/game/phase/Untap.java b/forge-game/src/main/java/forge/game/phase/Untap.java
index 6b317fa3dff..6fe6668b151 100644
--- a/forge-game/src/main/java/forge/game/phase/Untap.java
+++ b/forge-game/src/main/java/forge/game/phase/Untap.java
@@ -185,7 +185,7 @@ public class Untap extends Phase {
}
}
Card chosen = player.getController().chooseSingleEntityForEffect(cardList, new SpellAbility.EmptySa(ApiType.Untap, null, player),
- "Select a card to untap\r\n(Selected:" + restrictUntapped + ")\r\n" + "Remaining cards that can untap: " + remaining);
+ "Select a card to untap\r\n(Selected:" + restrictUntapped + ")\r\n" + "Remaining cards that can untap: " + remaining, null);
if (chosen != null) {
for (Entry rest : restrictUntap.entrySet()) {
if (chosen.isValid(rest.getKey(), player, null, null)) {
diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java
index 5082c6e7b63..5c78d34c4b7 100644
--- a/forge-game/src/main/java/forge/game/player/Player.java
+++ b/forge-game/src/main/java/forge/game/player/Player.java
@@ -114,7 +114,7 @@ public class Player extends GameEntity implements Comparable {
private CardCollection sacrificedThisTurn = new CardCollection();
- private Map countersAddedtoPermThisTurn = Maps.newEnumMap(CounterType.class);
+ private Map countersAddedtoPermThisTurn = Maps.newHashMap();
/** A list of tokens not in play, but on their way.
* This list is kept in order to not break ETB-replacement
@@ -544,17 +544,17 @@ public class Player extends GameEntity implements Comparable {
}
public final boolean canPayEnergy(final int energyPayment) {
- int cnt = getCounters(CounterType.ENERGY);
+ int cnt = getCounters(CounterEnumType.ENERGY);
return cnt >= energyPayment;
}
public final int loseEnergy(int lostEnergy) {
- int cnt = getCounters(CounterType.ENERGY);
+ int cnt = getCounters(CounterEnumType.ENERGY);
if (lostEnergy > cnt) {
return -1;
}
cnt -= lostEnergy;
- this.setCounters(CounterType.ENERGY, cnt, true);
+ this.setCounters(CounterEnumType.ENERGY, cnt, true);
return cnt;
}
@@ -909,12 +909,8 @@ public class Player extends GameEntity implements Comparable {
@Override
public int addCounter(CounterType counterType, int n, final Player source, boolean applyMultiplier, boolean fireEvents, GameEntityCounterTable table) {
- if (!canReceiveCounters(counterType)) {
- return 0;
- }
-
int addAmount = n;
- if (addAmount <= 0) {
+ if (addAmount <= 0 || !canReceiveCounters(counterType)) {
// Can't add negative or 0 counters, bail out now
return 0;
}
@@ -935,6 +931,10 @@ public class Player extends GameEntity implements Comparable