diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index 2e7127f7aa0..d22916eda72 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -414,7 +414,6 @@ public class ComputerUtilMana { // then apply this one if (!replaceType.isEmpty()) { for (SpellAbility saMana : replaceAmount) { - Card card = saMana.getHostCard(); if (saMana.hasParam("ReplaceType")) { // replace color and colorless String color = saMana.getParam("ReplaceType"); @@ -436,8 +435,8 @@ public class ComputerUtilMana { // replace color String color = saMana.getParam("ReplaceColor"); if ("Chosen".equals(color)) { - if (card.hasChosenColor()) { - color = MagicColor.toShortString(card.getChosenColor()); + if (saMana.hasChosenColor()) { + color = MagicColor.toShortString(saMana.getChosenColor()); } } if (saMana.hasParam("ReplaceOnly")) { @@ -489,7 +488,7 @@ public class ComputerUtilMana { int pAmount = AbilityUtils.calculateAmount(trSA.getHostCard(), trSA.getParamOrDefault("Amount", "1"), trSA); String produced = trSA.getParam("Produced"); if (produced.equals("Chosen")) { - produced = MagicColor.toShortString(trSA.getHostCard().getChosenColor()); + produced = MagicColor.toShortString(trSA.getHostCard().getChosenColor(trSA)); } manaProduced += " " + StringUtils.repeat(produced, pAmount); } else if (ApiType.ManaReflected.equals(trSA.getApi())) { diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java index 819855c1c6c..4720199ce15 100644 --- a/forge-ai/src/main/java/forge/ai/GameState.java +++ b/forge-ai/src/main/java/forge/ai/GameState.java @@ -341,8 +341,9 @@ public abstract class GameState { newText.append("|Damage:").append(c.getDamage()); } - if (!c.getChosenColor().isEmpty()) { - newText.append("|ChosenColor:").append(TextUtil.join(c.getChosenColors(), ",")); + SpellAbility first = c.getFirstSpellAbility(); + if (first != null) { + newText.append("|ChosenColor:").append(TextUtil.join(first.getChosenColors(), ",")); } if (!c.getChosenType().isEmpty()) { newText.append("|ChosenType:").append(c.getChosenType()); @@ -734,7 +735,7 @@ public abstract class GameState { if (persistent) { produced.put("PersistentMana", "True"); } - final AbilityManaPart abMana = new AbilityManaPart(dummy, produced); + final AbilityManaPart abMana = new AbilityManaPart(dummy, null, produced); game.getAction().invoke(new Runnable() { @Override public void run() { @@ -1088,7 +1089,7 @@ public abstract class GameState { Card c = entry.getKey(); List colors = entry.getValue(); - c.setChosenColors(colors); + c.setChosenColors(colors, c.getFirstSpellAbility()); } // Chosen type diff --git a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java index 34d33387a54..f512fc031e1 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java @@ -432,7 +432,7 @@ public class AnimateAi extends SpellAbilityAi { if (sa.hasParam("Colors")) { final String colors = sa.getParam("Colors"); if (colors.equals("ChosenColor")) { - tmpDesc = CardUtil.getShortColorsString(source.getChosenColors()); + tmpDesc = CardUtil.getShortColorsString(sa.getChosenColors()); } else { tmpDesc = CardUtil.getShortColorsString(Lists.newArrayList(Arrays.asList(colors.split(",")))); } 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 9078eab7c4f..95bb658540b 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java @@ -8,6 +8,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; + import forge.ai.ComputerUtilAbility; import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCost; @@ -31,6 +32,7 @@ import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; +import forge.game.staticability.StaticAbilityCantBeCast; import forge.game.zone.ZoneType; import forge.util.Aggregates; import forge.util.collect.FCollection; @@ -228,11 +230,10 @@ public class ChooseGenericEffectAi extends SpellAbilityAi { return allow; } - //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; - } + SpellAbility firstSpell = imprinted.getFirstSpellAbility(); + // check if something would prevent it from casting + if (firstSpell == null || StaticAbilityCantBeCast.cantBeCastAbility(firstSpell, imprinted, owner)) { + return allow; } if (dmg == 0) { 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 eccdeb48f16..c34f28b7542 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java @@ -55,15 +55,15 @@ public class GameCopier { public GameCopier(Game origGame) { this.origGame = origGame; } - + public Game getOriginalGame() { return origGame; } - + public Game getCopiedGame() { return gameObjectMap.getGame(); } - + public Game makeCopy() { return makeCopy(null); } @@ -101,7 +101,7 @@ public class GameCopier { for (Player p : newGame.getPlayers()) { ((PlayerZoneBattlefield) p.getZone(ZoneType.Battlefield)).setTriggers(false); } - + copyGameState(newGame); for (Player p : newGame.getPlayers()) { @@ -124,7 +124,6 @@ public class GameCopier { System.err.println(c + " Remembered: " + o + "/" + o.getClass()); c.addRemembered(o); } - } } for (SpellAbility sa : c.getSpellAbilities()) { @@ -153,7 +152,7 @@ public class GameCopier { if (advanceToPhase != null) { newGame.getPhaseHandler().devAdvanceToPhase(advanceToPhase); } - + return newGame; } @@ -180,7 +179,7 @@ public class GameCopier { } newGame.getStack().add(newSa); } - } + } } private RegisteredPlayer clonePlayer(RegisteredPlayer p) { @@ -227,7 +226,7 @@ public class GameCopier { // TODO: Verify that the above relationships are preserved bi-directionally or not. } } - + private static final boolean USE_FROM_PAPER_CARD = true; private Card createCardCopy(Game newGame, Player newOwner, Card c) { if (c.isToken() && !c.isEmblem()) { @@ -277,7 +276,7 @@ public class GameCopier { // TODO: Controllers' list with timestamps should be copied. zoneOwner = playerMap.get(c.getController()); newCard.setController(zoneOwner, 0); - + int setPower = c.getSetPower(); int setToughness = c.getSetToughness(); if (setPower != Integer.MAX_VALUE || setToughness != Integer.MAX_VALUE) { @@ -286,7 +285,7 @@ public class GameCopier { } newCard.setPTBoost(c.getPTBoostTable()); newCard.setDamage(c.getDamage()); - + newCard.setChangedCardTypes(c.getChangedCardTypesMap()); newCard.setChangedCardKeywords(c.getChangedCardKeywords()); newCard.setChangedCardNames(c.getChangedCardNames()); @@ -341,9 +340,13 @@ public class GameCopier { if (!c.getChosenType2().isEmpty()) { newCard.setChosenType2(c.getChosenType2()); } - if (c.getChosenColors() != null) { - newCard.setChosenColors(Lists.newArrayList(c.getChosenColors())); + + SpellAbility first = c.getFirstSpellAbility(); + + if (first != null && first.hasChosenColor()) { + newCard.setChosenColors(Lists.newArrayList(first.getChosenColors()), newCard.getFirstSpellAbility()); } + if (!c.getNamedCard().isEmpty()) { newCard.setNamedCard(c.getNamedCard()); } @@ -359,7 +362,7 @@ public class GameCopier { zoneOwner.getZone(zone).add(newCard); } } - + private static SpellAbility findSAInCard(SpellAbility sa, Card c) { String saDesc = sa.getDescription(); for (SpellAbility cardSa : c.getAllSpellAbilities()) { @@ -387,7 +390,7 @@ public class GameCopier { return find(o); } } - + public GameObject find(GameObject o) { GameObject result = cardMap.get(o); if (result != null) diff --git a/forge-game/src/main/java/forge/game/CardTraitBase.java b/forge-game/src/main/java/forge/game/CardTraitBase.java index 0b82277c7f2..4d4cee34f9d 100644 --- a/forge-game/src/main/java/forge/game/CardTraitBase.java +++ b/forge-game/src/main/java/forge/game/CardTraitBase.java @@ -637,4 +637,20 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView, // dont use setHostCard to not trigger the not copied parts yet copy.hostCard = host; } + + + public String getChosenColor() { + return getHostCard().getChosenColor(this); + } + public final Iterable getChosenColors() { + return getHostCard().getChosenColors(this); + } + + public final boolean hasChosenColor() { + return getHostCard().hasChosenColor(this); + } + + public final boolean hasChosenColor(String s) { + return getHostCard().hasChosenColor(s, this); + } } diff --git a/forge-game/src/main/java/forge/game/ForgeScript.java b/forge-game/src/main/java/forge/game/ForgeScript.java index ea64739495d..c1358e6ade1 100644 --- a/forge-game/src/main/java/forge/game/ForgeScript.java +++ b/forge-game/src/main/java/forge/game/ForgeScript.java @@ -54,13 +54,13 @@ public class ForgeScript { } else if (property.startsWith("ChosenColor")) { if (property.endsWith("Source") && isColorlessSource) return false; - return source.hasChosenColor() && colors.hasAnyColor(MagicColor.fromName(source.getChosenColor())); + return spellAbility.hasChosenColor() && colors.hasAnyColor(MagicColor.fromName(spellAbility.getChosenColor())); } else if (property.startsWith("AnyChosenColor")) { if (property.endsWith("Source") && isColorlessSource) return false; - return source.hasChosenColor() - && colors.hasAnyColor(ColorSet.fromNames(source.getChosenColors()).getColor()); + return spellAbility.hasChosenColor() + && colors.hasAnyColor(ColorSet.fromNames(spellAbility.getChosenColors()).getColor()); } else if (property.startsWith("non")) { // ... Other Card types diff --git a/forge-game/src/main/java/forge/game/ability/AbilityApiBased.java b/forge-game/src/main/java/forge/game/ability/AbilityApiBased.java index dba8ae6d801..a6782c6c86f 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityApiBased.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityApiBased.java @@ -19,7 +19,7 @@ public class AbilityApiBased extends AbilityActivated { effect = api.getSpellEffect(); if (api.equals(ApiType.Mana) || api.equals(ApiType.ManaReflected)) { - this.setManaPart(new AbilityManaPart(sourceCard, mapParams)); + this.setManaPart(new AbilityManaPart(sourceCard, this, mapParams)); this.setUndoable(true); // will try at least } 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 2f2647788f4..7dfcb7b0ea1 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -1736,7 +1736,7 @@ public class AbilityUtils { if (sq[0].contains("HasNumChosenColors")) { int sum = 0; for (Card card : AbilityUtils.getDefinedCards(sa.getHostCard(), sq[1], sa)) { - sum += CardUtil.getColors(card).getSharedColors(ColorSet.fromNames(c.getChosenColors())).countColors(); + sum += CardUtil.getColors(card).getSharedColors(ColorSet.fromNames(sa.getChosenColors())).countColors(); } return sum; } @@ -1849,6 +1849,29 @@ public class AbilityUtils { if (l[0].startsWith("ExiledWith")) { return CardFactoryUtil.doXMath(c.getExiledWith(ctb).size(), expr, c); } + + // Count$DevotionDual.. + // Count$Devotion. + if (sq[0].contains("Devotion")) { + int colorOcurrencices = 0; + String colorName = sq[1]; + if (colorName.contains("Chosen")) { + colorName = MagicColor.toShortString(ctb.getChosenColor()); + } + byte colorCode = ManaAtom.fromName(colorName); + if (sq[0].equals("DevotionDual")) { + colorCode |= ManaAtom.fromName(sq[2]); + } + for (Card c0 : player.getCardsIn(ZoneType.Battlefield)) { + for (ManaCostShard sh : c0.getManaCost()) { + if ((sh.getColorMask() & colorCode) != 0) { + colorOcurrencices++; + } + } + colorOcurrencices += c0.getAmountOfKeyword("Your devotion to each color and each combination of colors is increased by one."); + } + return CardFactoryUtil.doXMath(colorOcurrencices, expr, c); + } } return CardFactoryUtil.xCount(c, s2); } diff --git a/forge-game/src/main/java/forge/game/ability/SpellApiBased.java b/forge-game/src/main/java/forge/game/ability/SpellApiBased.java index d7903a2c502..42a65d8eef9 100644 --- a/forge-game/src/main/java/forge/game/ability/SpellApiBased.java +++ b/forge-game/src/main/java/forge/game/ability/SpellApiBased.java @@ -25,7 +25,7 @@ public class SpellApiBased extends Spell { this.setIntrinsic(true); if (api.equals(ApiType.Mana) || api.equals(ApiType.ManaReflected)) { - this.setManaPart(new AbilityManaPart(sourceCard, mapParams)); + this.setManaPart(new AbilityManaPart(sourceCard, this, mapParams)); } if (api.equals(ApiType.ChangeZone) || api.equals(ApiType.ChangeZoneAll)) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java index ef111a521c4..d1aa57c6799 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateAllEffect.java @@ -89,7 +89,7 @@ public class AnimateAllEffect extends AnimateEffectBase { if (sa.hasParam("Colors")) { final String colors = sa.getParam("Colors"); if (colors.equals("ChosenColor")) { - tmpDesc = CardUtil.getShortColorsString(host.getChosenColors()); + tmpDesc = CardUtil.getShortColorsString(sa.getChosenColors()); } else { tmpDesc = CardUtil.getShortColorsString(new ArrayList<>(Arrays.asList(colors.split(",")))); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java index 9bf9d3eb09d..46f50125da1 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java @@ -100,7 +100,7 @@ public class AnimateEffect extends AnimateEffectBase { final String colors = sa.getParam("Colors"); if (colors.equals("ChosenColor")) { - tmpDesc = CardUtil.getShortColorsString(source.getChosenColors()); + tmpDesc = CardUtil.getShortColorsString(sa.getChosenColors()); } else { tmpDesc = CardUtil.getShortColorsString(Arrays.asList(colors.split(","))); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseColorEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseColorEffect.java index e7ce877a81e..b9ff32439a3 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseColorEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseColorEffect.java @@ -75,8 +75,8 @@ public class ChooseColorEffect extends SpellAbilityEffect { if (chosenColors.isEmpty()) { return; } - card.setChosenColors(chosenColors); - p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), Lang.joinHomogenous(chosenColors)), p); + card.setChosenColors(chosenColors, sa); + p.getGame().getAction().nofityOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), Lang.joinHomogenous(chosenColors)), p); } } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CleanUpEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CleanUpEffect.java index f458fe700ef..0f713540d29 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CleanUpEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CleanUpEffect.java @@ -53,7 +53,7 @@ public class CleanUpEffect extends SpellAbilityEffect { source.setChosenType2(""); } if (sa.hasParam("ClearChosenColor")) { - source.setChosenColors(null); + source.setChosenColors(null, sa); } } } 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 1df70724937..65e8de5af25 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 @@ -232,8 +232,8 @@ public class EffectEffect extends SpellAbilityEffect { } // Set Chosen Color(s) - if (hostCard.hasChosenColor()) { - eff.setChosenColors(Lists.newArrayList(hostCard.getChosenColors())); + if (sa.hasChosenColor()) { + eff.setChosenColors(Lists.newArrayList(sa.getChosenColors()), sa); } // Set Chosen Cards diff --git a/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java index a92a7bd3dff..70283050108 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ProtectAllEffect.java @@ -60,7 +60,7 @@ public class ProtectAllEffect extends SpellAbilityEffect { game.getAction().notifyOfValue(sa, choser, Lang.joinHomogenous(gains), choser); } else { if (sa.getParam("Gains").equals("ChosenColor")) { - for (final String color : host.getChosenColors()) { + for (final String color : sa.getChosenColors()) { gains.add(color.toLowerCase()); } } else if (sa.getParam("Gains").equals("TargetedCardColor")) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java index 631ecf9e533..9d1c6274fd5 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ProtectEffect.java @@ -97,7 +97,6 @@ public class ProtectEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { - final Card host = sa.getHostCard(); final Game game = sa.getActivatingPlayer().getGame(); final boolean isChoice = sa.getParam("Gains").contains("Choice"); @@ -117,7 +116,7 @@ public class ProtectEffect extends SpellAbilityEffect { game.getAction().notifyOfValue(sa, choser, Lang.joinHomogenous(gains), choser); } else { if (sa.getParam("Gains").equals("ChosenColor")) { - for (final String color : host.getChosenColors()) { + for (final String color : sa.getChosenColors()) { gains.add(color.toLowerCase()); } } else { diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceManaEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceManaEffect.java index 246a1857255..3a7fcbbec68 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReplaceManaEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceManaEffect.java @@ -62,8 +62,8 @@ public class ReplaceManaEffect extends SpellAbilityEffect { // replace color String color = sa.getParam("ReplaceColor"); if ("Chosen".equals(color)) { - if (card.hasChosenColor()) { - color = MagicColor.toShortString(card.getChosenColor()); + if (sa.hasChosenColor()) { + color = MagicColor.toShortString(sa.getChosenColor()); } } if (sa.hasParam("ReplaceOnly")) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/SubgameEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SubgameEffect.java index 87a6b699243..60d13ea9a74 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SubgameEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SubgameEffect.java @@ -81,8 +81,8 @@ public class SubgameEffect extends SpellAbilityEffect { List chosenColors; SpellAbility cmdColorsa = new SpellAbility.EmptySa(ApiType.ChooseColor, cmd, player); chosenColors = player.getController().chooseColors(prompt,cmdColorsa, 1, 1, colorChoices); - cmd.setChosenColors(chosenColors); - subgame.getAction().notifyOfValue(cmdColorsa, cmd, Localizer.getInstance().getMessage("lblPlayerPickedChosen", player.getName(), Lang.joinHomogenous(chosenColors)), player); + cmd.setChosenColors(chosenColors, cmdColorsa); + subgame.getAction().nofityOfValue(cmdColorsa, cmd, Localizer.getInstance().getMessage("lblPlayerPickedChosen", player.getName(), Lang.joinHomogenous(chosenColors)), player); } cmd.setCommander(true); com.add(cmd); diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java index 8ceb22b0f2a..97670c7373e 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java @@ -62,7 +62,7 @@ public class TokenEffect extends TokenEffectBase { } } if (sa.hasParam("TokenColors")) { - if (sa.getParam("TokenColors").contains("ChosenColor") && !host.hasChosenColor()) { + if (sa.getParam("TokenColors").contains("ChosenColor") && !sa.hasChosenColor()) { 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 b3aa1e457f1..43bf4ff1955 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -297,7 +297,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { private String originalText = "", text = ""; private String chosenType = ""; private String chosenType2 = ""; - private List chosenColors; + private LinkedAbilityTable chosenColorsTable = new LinkedAbilityTable(); private String chosenName = ""; private String chosenName2 = ""; private Integer chosenNumber; @@ -1710,28 +1710,25 @@ public class Card extends GameEntity implements Comparable, IHasSVars { return chosenType2 != null && !chosenType2.isEmpty(); } - public final String getChosenColor() { - if (hasChosenColor()) { - return chosenColors.get(0); - } - return ""; + public String getChosenColor(CardTraitBase ctb) { + return Iterables.getFirst(chosenColorsTable.get(ctb), null); } - public final Iterable getChosenColors() { - if (chosenColors == null) { - return Lists.newArrayList(); - } - return chosenColors; + public final Iterable getChosenColors(CardTraitBase ctb) { + return chosenColorsTable.get(ctb); } - public final void setChosenColors(final List s) { - chosenColors = s; + + public final boolean hasChosenColor(CardTraitBase ctb) { + return !chosenColorsTable.get(ctb).isEmpty(); + } + + public final boolean hasChosenColor(String s, CardTraitBase ctb) { + return chosenColorsTable.contains(s, ctb); + } + + public void setChosenColors(final Iterable colors, CardTraitBase ctb) { + chosenColorsTable.set(colors, ctb); view.updateChosenColors(this); } - public boolean hasChosenColor() { - return chosenColors != null && !chosenColors.isEmpty(); - } - public boolean hasChosenColor(String s) { - return chosenColors != null && chosenColors.contains(s); - } public final Card getChosenCard() { return getChosenCards().getFirst(); @@ -6999,11 +6996,11 @@ public class Card extends GameEntity implements Comparable, IHasSVars { return exiledWithTable; } - public void setExiledWithTable(Table, CardCollection> map) { + public void setExiledWithTable(Table, FCollection> map) { exiledWithTable = new ExileWithTable(map); } - public CardCollectionView getExiledWith(CardTraitBase ctb) { + public FCollection getExiledWith(CardTraitBase ctb) { return exiledWithTable.get(ctb); } diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index 01a0f628ff7..58ba062d8b6 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -129,7 +129,6 @@ public class CardFactory { *

* */ private final static Card copySpellHost(final SpellAbility sourceSA, final SpellAbility targetSA, Player controller) { - final Card source = sourceSA.getHostCard(); final Card original = targetSA.getHostCard(); final Card c = copyCard(original, true); @@ -138,7 +137,7 @@ public class CardFactory { String tmp = ""; final String newColor = sourceSA.getParam("CopyIsColor"); if (newColor.equals("ChosenColor")) { - tmp = CardUtil.getShortColorsString(source.getChosenColors()); + tmp = CardUtil.getShortColorsString(sourceSA.getChosenColors()); } else { tmp = CardUtil.getShortColorsString(Lists.newArrayList(newColor.split(","))); } 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 41acece7191..7a8b8ee33ab 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1052,28 +1052,6 @@ public class CardFactoryUtil { } return doXMath(colorOcurrencices, m, c); } - // Count$DevotionDual.. - // Count$Devotion. - if (sq[0].contains("Devotion")) { - int colorOcurrencices = 0; - String colorName = sq[1]; - if (colorName.contains("Chosen")) { - colorName = MagicColor.toShortString(c.getChosenColor()); - } - byte colorCode = ManaAtom.fromName(colorName); - if (sq[0].equals("DevotionDual")) { - colorCode |= ManaAtom.fromName(sq[2]); - } - for (Card c0 : cc.getCardsIn(ZoneType.Battlefield)) { - for (ManaCostShard sh : c0.getManaCost()) { - if ((sh.getColorMask() & colorCode) != 0) { - colorOcurrencices++; - } - } - colorOcurrencices += c0.getAmountOfKeyword("Your devotion to each color and each combination of colors is increased by one."); - } - return doXMath(colorOcurrencices, m, c); - } if (sq[0].contains("ColorsCtrl")) { final String restriction = l[0].substring(11); diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index 23cc4696c0c..0ee94a10715 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -344,7 +344,7 @@ public class CardView extends GameEntityView { return get(TrackableProperty.ChosenColors); } void updateChosenColors(Card c) { - set(TrackableProperty.ChosenColors, c.getChosenColors()); + //set(TrackableProperty.ChosenColors, c.getChosenColors()); } public FCollectionView getMergedCardsCollection() { diff --git a/forge-game/src/main/java/forge/game/card/ExileWithTable.java b/forge-game/src/main/java/forge/game/card/ExileWithTable.java index 7e6e5de9940..55dec0a78c4 100644 --- a/forge-game/src/main/java/forge/game/card/ExileWithTable.java +++ b/forge-game/src/main/java/forge/game/card/ExileWithTable.java @@ -1,76 +1,18 @@ package forge.game.card; -import org.apache.commons.lang3.ObjectUtils; - import com.google.common.base.Optional; -import com.google.common.collect.ForwardingTable; -import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; -import forge.game.CardTraitBase; import forge.game.staticability.StaticAbility; +import forge.util.collect.FCollection; -public class ExileWithTable extends ForwardingTable, CardCollection> { - private Table, CardCollection> dataTable = HashBasedTable.create(); +public class ExileWithTable extends LinkedAbilityTable { - public ExileWithTable(Table, CardCollection> map) { + public ExileWithTable(Table, FCollection> map) { this.putAll(map); } public ExileWithTable() { } - - - @Override - protected Table, CardCollection> delegate() { - return dataTable; - } - - protected CardCollection putInternal(Card object, Card host, StaticAbility stAb) { - host = ObjectUtils.defaultIfNull(host.getEffectSource(), host); - Optional st = Optional.fromNullable(stAb); - CardCollection old; - if (contains(host, st)) { - old = get(host, st); - old.add(object); - } else { - old = new CardCollection(object); - delegate().put(host, st, old); - } - return old; - } - - public CardCollection put(Card object, Card host) { - return putInternal(object, host, null); - } - - public CardCollection put(Card object, CardTraitBase ctb) { - return putInternal(object, ctb.getOriginalOrHost(), ctb.getGrantorStatic()); - } - - public CardCollectionView get(CardTraitBase ctb) { - Card host = ctb.getOriginalOrHost(); - host = ObjectUtils.defaultIfNull(host.getEffectSource(), host); - Optional st = Optional.fromNullable(ctb.getGrantorStatic()); - if (contains(host, st)) { - return get(host, st); - } else { - return CardCollection.EMPTY; - } - } - - public boolean contains(Card object, CardTraitBase ctb) { - return get(ctb).contains(object); - } - - public boolean remove(Card value) { - boolean changed = false; - for (CardCollection col : delegate().values()) { - if (col.remove(value)) { - changed = true; - } - } - return changed; - } } diff --git a/forge-game/src/main/java/forge/game/card/LinkedAbilityTable.java b/forge-game/src/main/java/forge/game/card/LinkedAbilityTable.java new file mode 100644 index 00000000000..afe524971a1 --- /dev/null +++ b/forge-game/src/main/java/forge/game/card/LinkedAbilityTable.java @@ -0,0 +1,89 @@ +package forge.game.card; + +import org.apache.commons.lang3.ObjectUtils; + +import com.google.common.base.Optional; +import com.google.common.collect.ForwardingTable; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Iterables; +import com.google.common.collect.Table; + +import forge.game.CardTraitBase; +import forge.game.staticability.StaticAbility; +import forge.util.collect.FCollection; + +public class LinkedAbilityTable extends ForwardingTable, FCollection> { + private Table, FCollection> dataTable = HashBasedTable.create(); + + @Override + protected Table, FCollection> delegate() { + return dataTable; + } + + protected FCollection getSupplier() { + return new FCollection(); + } + + protected FCollection putInternal(T object, Card host, StaticAbility stAb) { + host = ObjectUtils.defaultIfNull(host.getEffectSource(), host); + Optional st = Optional.fromNullable(stAb); + FCollection old; + if (contains(host, st)) { + old = get(host, st); + } else { + old = getSupplier(); + delegate().put(host, st, old); + } + old.add(object); + return old; + } + + public FCollection put(T object, Card host) { + return putInternal(object, host, null); + } + + public FCollection put(T object, CardTraitBase ctb) { + return putInternal(object, ctb.getOriginalOrHost(), ctb.getGrantorStatic()); + } + + protected void setInternal(Iterable list, Card host, StaticAbility stAb) { + host = ObjectUtils.defaultIfNull(host.getEffectSource(), host); + Optional st = Optional.fromNullable(stAb); + if (list == null || Iterables.isEmpty(list)) { + delegate().remove(host, st); + } else { + FCollection old = getSupplier(); + old.addAll(list); + delegate().put(host, st, old); + } + } + + public void set(Iterable list, CardTraitBase ctb) { + setInternal(list, ctb.getOriginalOrHost(), ctb.getGrantorStatic()); + } + + public FCollection get(CardTraitBase ctb) { + Card host = ctb.getOriginalOrHost(); + host = ObjectUtils.defaultIfNull(host.getEffectSource(), host); + Optional st = Optional.fromNullable(ctb.getGrantorStatic()); + if (contains(host, st)) { + return get(host, st); + } else { + return FCollection.getEmpty(); + } + } + + public boolean contains(T object, CardTraitBase ctb) { + return get(ctb).contains(object); + } + + public boolean remove(T value) { + boolean changed = false; + for (FCollection col : delegate().values()) { + if (col.remove(value)) { + changed = true; + } + } + return changed; + } +} diff --git a/forge-game/src/main/java/forge/game/card/token/TokenInfo.java b/forge-game/src/main/java/forge/game/card/token/TokenInfo.java index 948abddfe68..cb82f5ff6ec 100644 --- a/forge-game/src/main/java/forge/game/card/token/TokenInfo.java +++ b/forge-game/src/main/java/forge/game/card/token/TokenInfo.java @@ -365,7 +365,7 @@ public class TokenInfo { if (sa.hasParam("TokenColors")) { String colors = sa.getParam("TokenColors"); - colors = colors.replace("ChosenColor", sa.getHostCard().getChosenColor()); + colors = colors.replace("ChosenColor", sa.getHostCard().getChosenColor(sa)); result.setColor(MagicColor.toShortString(colors)); } 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 c83ce6d79db..f0192b8621b 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -3039,8 +3039,8 @@ public class Player extends GameEntity implements Comparable { List chosenColors; SpellAbility cmdColorsa = new SpellAbility.EmptySa(ApiType.ChooseColor, cmd, p); chosenColors = p.getController().chooseColors(prompt,cmdColorsa, 1, 1, colorChoices); - cmd.setChosenColors(chosenColors); - p.getGame().getAction().notifyOfValue(cmdColorsa, cmd, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), Lang.joinHomogenous(chosenColors)), p); + cmd.setChosenColors(chosenColors, cmdColorsa); + p.getGame().getAction().nofityOfValue(cmdColorsa, cmd, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), Lang.joinHomogenous(chosenColors)), p); } cmd.setCommander(true); com.add(cmd); diff --git a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java index 66b641b5f6c..d56da76d408 100644 --- a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java +++ b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java @@ -71,6 +71,7 @@ public class AbilityManaPart implements java.io.Serializable { private transient List lastManaProduced = Lists.newArrayList(); private transient Card sourceCard; + private transient SpellAbility spellAbility; // Spells paid with this mana spell can't be countered. @@ -84,8 +85,9 @@ public class AbilityManaPart implements java.io.Serializable { * @param sourceCard * a {@link forge.game.card.Card} object. */ - public AbilityManaPart(final Card sourceCard, final Map params) { + public AbilityManaPart(final Card sourceCard, final SpellAbility sa, final Map params) { this.sourceCard = sourceCard; + this.spellAbility = sa; origProduced = params.containsKey("Produced") ? params.get("Produced") : "1"; this.manaRestrictions = params.containsKey("RestrictValid") ? params.get("RestrictValid") : ""; @@ -413,9 +415,11 @@ public class AbilityManaPart implements java.io.Serializable { * @return a {@link java.lang.String} object. */ public final String mana() { - if (this.getOrigProduced().contains("Chosen")) { - if (this.getSourceCard() != null && this.getSourceCard().hasChosenColor()) { - return MagicColor.toShortString(this.getSourceCard().getChosenColor()); + if (getOrigProduced().contains("Chosen")) { + if (spellAbility == null) { + return ""; + } else { + return MagicColor.toShortString(spellAbility.getChosenColor()); } } return this.getOrigProduced(); @@ -499,15 +503,15 @@ public class AbilityManaPart implements java.io.Serializable { * a {@link java.lang.String} object. * @return a boolean. */ - public final boolean canProduce(final String s, final SpellAbility sa) { + public final boolean canProduce(final String s) { // Any mana never means Colorless? if (isAnyMana() && !s.equals("C")) { return true; } String origProduced = getOrigProduced(); - if (origProduced.contains("Chosen") && sourceCard != null ) { - if (getSourceCard().hasChosenColor() && MagicColor.toShortString(getSourceCard().getChosenColor()).contains(s)) { + if (origProduced.contains("Chosen") && spellAbility != null ) { + if (spellAbility.hasChosenColor() && MagicColor.toShortString(spellAbility.getChosenColor()).contains(s)) { return true; } } diff --git a/forge-game/src/main/java/forge/game/spellability/AbilitySub.java b/forge-game/src/main/java/forge/game/spellability/AbilitySub.java index 1986274237d..d5c64e7e57e 100644 --- a/forge-game/src/main/java/forge/game/spellability/AbilitySub.java +++ b/forge-game/src/main/java/forge/game/spellability/AbilitySub.java @@ -89,7 +89,7 @@ public final class AbilitySub extends SpellAbility implements java.io.Serializab effect = api.getSpellEffect(); if (api.equals(ApiType.Mana) || api.equals(ApiType.ManaReflected)) { - this.setManaPart(new AbilityManaPart(ca, mapParams)); + this.setManaPart(new AbilityManaPart(ca, this, mapParams)); } if (api.equals(ApiType.ChangeZone) || api.equals(ApiType.ChangeZoneAll)) { diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index e799e86f602..32a620b2c38 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -252,7 +252,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit public boolean canThisProduce(final String s) { AbilityManaPart mp = getManaPart(); - if (mp != null && metConditions() && mp.canProduce(s, this)) { + if (mp != null && metConditions() && mp.canProduce(s)) { return true; } return false; @@ -993,7 +993,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit clone.setPayCosts(getPayCosts().copy()); if (manaPart != null) { - clone.manaPart = new AbilityManaPart(host, mapParams); + clone.manaPart = new AbilityManaPart(host, clone, mapParams); } // need to copy the damage tables diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java b/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java index f716b899fbf..8ed8cd7c9ca 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java @@ -339,7 +339,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables { } if (this.getColorToCheck() != null) { - if (!sa.getHostCard().hasChosenColor(this.getColorToCheck())) { + if (!sa.hasChosenColor(this.getColorToCheck())) { return false; } } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java b/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java index 5c8f0973aee..df214d5c08d 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java @@ -362,7 +362,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables { } if (getColorToCheck() != null) { - if (!sa.getHostCard().hasChosenColor(getColorToCheck())) { + if (!sa.hasChosenColor(getColorToCheck())) { return false; } } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index 214aef7aeaf..c5d42c2edbd 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -215,7 +215,7 @@ public final class StaticAbilityContinuous { Iterables.removeIf(addKeywords, new Predicate() { @Override public boolean apply(String input) { - if (!hostCard.hasChosenColor() && input.contains("ChosenColor")) { + if (!stAb.hasChosenColor() && input.contains("ChosenColor")) { return true; } if (!hostCard.hasChosenType() && input.contains("ChosenType")) { @@ -294,9 +294,9 @@ public final class StaticAbilityContinuous { @Override public String apply(String input) { - if (hostCard.hasChosenColor()) { - input = input.replaceAll("ChosenColor", StringUtils.capitalize(hostCard.getChosenColor())); - input = input.replaceAll("chosenColor", hostCard.getChosenColor().toLowerCase()); + if (stAb.hasChosenColor()) { + input = input.replaceAll("ChosenColor", StringUtils.capitalize(stAb.getChosenColor())); + input = input.replaceAll("chosenColor", stAb.getChosenColor().toLowerCase()); } if (hostCard.hasChosenType()) { input = input.replaceAll("ChosenType", hostCard.getChosenType()); @@ -458,7 +458,7 @@ public final class StaticAbilityContinuous { if (params.containsKey("AddColor")) { final String colors = params.get("AddColor"); if (colors.equals("ChosenColor")) { - addColors = CardUtil.getShortColorsString(hostCard.getChosenColors()); + addColors = CardUtil.getShortColorsString(stAb.getChosenColors()); } else if (colors.equals("All")) { addColors = "W U B R G"; } else { @@ -469,7 +469,7 @@ public final class StaticAbilityContinuous { if (params.containsKey("SetColor")) { final String colors = params.get("SetColor"); if (colors.equals("ChosenColor")) { - addColors = CardUtil.getShortColorsString(hostCard.getChosenColors()); + addColors = CardUtil.getShortColorsString(stAb.getChosenColors()); } else if (colors.equals("All")) { addColors = "W U B R G"; } else { @@ -619,8 +619,8 @@ public final class StaticAbilityContinuous { if (changeColorWordsTo != null) { final byte color; if (changeColorWordsTo.equals("ChosenColor")) { - if (hostCard.hasChosenColor()) { - color = MagicColor.fromName(Iterables.getFirst(hostCard.getChosenColors(), null)); + if (stAb.hasChosenColor()) { + color = MagicColor.fromName(stAb.getChosenColor()); } else { color = 0; } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java b/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java index e786c869b37..d3f6fd1c0e2 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java @@ -83,7 +83,14 @@ public class TriggerTapsForMana extends Trigger { } String produced = (String) prod; if ("ChosenColor".equals(getParam("Produced"))) { - if (!this.getHostCard().hasChosenColor() || !produced.contains(MagicColor.toShortString(this.getHostCard().getChosenColor()))) { + boolean found = false; + for (String color : this.getChosenColors()) { + if (produced.contains(MagicColor.toShortString(color))) { + found = true; + break; + } + } + if (!found) { return false; } } else if (!produced.contains(MagicColor.toShortString(this.getParam("Produced")))) { diff --git a/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java b/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java index 51974682e0c..55e261e30ef 100644 --- a/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java +++ b/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java @@ -482,7 +482,7 @@ public class GameSimulatorTest extends SimulationTestCase { Player p = game.getPlayers().get(1); Card bear = addCard(bearCardName, p); Card hall = addCard("Hall of Triumph", p); - hall.setChosenColors(Lists.newArrayList("green")); + hall.setChosenColors(Lists.newArrayList("green"), hall.getFirstSpellAbility()); game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); game.getAction().checkStateEffects(true); assertEquals(3, bear.getNetToughness()); diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 6c9ac4b51cc..70e3acff1f5 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -2186,7 +2186,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont dummy.setOwner(pPriority); final Map produced = Maps.newHashMap(); produced.put("Produced", "W W W W W W W U U U U U U U B B B B B B B G G G G G G G R R R R R R R 7"); - final AbilityManaPart abMana = new AbilityManaPart(dummy, produced); + final AbilityManaPart abMana = new AbilityManaPart(dummy, null, produced); getGame().getAction().invoke(new Runnable() { @Override public void run() {