From 6cb14c25686f93cc1a8af941a0c9f5cb9975bc95 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sat, 2 Jun 2018 20:24:03 +0200 Subject: [PATCH 01/20] Card: add removeRemembered for Iterable --- forge-game/src/main/java/forge/game/card/Card.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 5720840885d..1e0175cfa88 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -746,6 +746,18 @@ public class Card extends GameEntity implements Comparable { view.updateRemembered(this); } } + + public final void removeRemembered(final Iterable list) { + boolean changed = false; + for (T o : list) { + if (rememberedObjects.remove(o)) { + changed = true; + } + } + if (changed) { + view.updateRemembered(this); + } + } public final void clearRemembered() { if (rememberedObjects.isEmpty()) { return; } rememberedObjects.clear(); From e97b814089b88cf8566ba508706d606cf4331ae8 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sat, 2 Jun 2018 20:34:04 +0200 Subject: [PATCH 02/20] chooseSingleSpellAbility has map params now --- .../src/main/java/forge/ai/PlayerControllerAi.java | 5 +++-- forge-ai/src/main/java/forge/ai/SpellAbilityAi.java | 2 +- .../main/java/forge/ai/ability/ActivateAbilityAi.java | 4 +++- .../java/forge/ai/ability/CanPlayAsDrawbackAi.java | 4 +++- .../java/forge/ai/ability/ChooseGenericEffectAi.java | 4 +++- .../main/java/forge/ai/ability/CopySpellAbilityAi.java | 4 +++- .../game/ability/effects/ActivateAbilityEffect.java | 4 +++- .../game/ability/effects/ChooseGenericEffect.java | 4 +++- .../game/ability/effects/CopySpellAbilityEffect.java | 10 +++++++--- .../main/java/forge/game/player/PlayerController.java | 3 ++- .../util/PlayerControllerForTests.java | 3 ++- .../main/java/forge/player/PlayerControllerHuman.java | 2 +- 12 files changed, 34 insertions(+), 15 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 8e063fc4ccb..7a21356b85b 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -168,12 +168,13 @@ public class PlayerControllerAi extends PlayerController { } @Override - public SpellAbility chooseSingleSpellForEffect(java.util.List spells, SpellAbility sa, String title) { + public SpellAbility chooseSingleSpellForEffect(java.util.List spells, SpellAbility sa, String title, + Map params) { ApiType api = sa.getApi(); if (null == api) { throw new InvalidParameterException("SA is not api-based, this is not supported yet"); } - return SpellApiToAi.Converter.get(api).chooseSingleSpellAbility(player, sa, spells); + return SpellApiToAi.Converter.get(api).chooseSingleSpellAbility(player, sa, spells, params); } @Override diff --git a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java index be3d906ec92..93168edf512 100644 --- a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java @@ -324,7 +324,7 @@ public abstract class SpellAbilityAi { return null; } - public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells) { + public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells, Map params) { System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSingleSpellAbility is used by " + sa.getHostCard().getName() + " for " + this.getClass().getName() + ". Consider declaring an overloaded method"); return spells.get(0); } diff --git a/forge-ai/src/main/java/forge/ai/ability/ActivateAbilityAi.java b/forge-ai/src/main/java/forge/ai/ability/ActivateAbilityAi.java index b71f07080f7..7eba97960da 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ActivateAbilityAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ActivateAbilityAi.java @@ -12,6 +12,7 @@ import forge.game.zone.ZoneType; import forge.util.MyRandom; import java.util.List; +import java.util.Map; public class ActivateAbilityAi extends SpellAbilityAi { @@ -93,7 +94,8 @@ public class ActivateAbilityAi extends SpellAbilityAi { } @Override - public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells) { + public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells, + Map params) { return spells.get(0); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/CanPlayAsDrawbackAi.java b/forge-ai/src/main/java/forge/ai/ability/CanPlayAsDrawbackAi.java index 0b4cf77f7c9..96876913dd9 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CanPlayAsDrawbackAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CanPlayAsDrawbackAi.java @@ -6,6 +6,7 @@ import forge.game.player.Player; import forge.game.spellability.SpellAbility; import java.util.List; +import java.util.Map; public class CanPlayAsDrawbackAi extends SpellAbilityAi { @@ -37,7 +38,8 @@ public class CanPlayAsDrawbackAi extends SpellAbilityAi { @Override - public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells) { + public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells, + Map params) { // This might be called from CopySpellAbilityEffect - to hide warning (for having no overload) use this simple overload return spells.get(0); } 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 05ba5338e55..af986809b36 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.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.collect.Iterables; @@ -79,7 +80,8 @@ public class ChooseGenericEffectAi extends SpellAbilityAi { } @Override - public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells) { + public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells, + Map params) { Card host = sa.getHostCard(); final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa); final Game game = host.getGame(); diff --git a/forge-ai/src/main/java/forge/ai/ability/CopySpellAbilityAi.java b/forge-ai/src/main/java/forge/ai/ability/CopySpellAbilityAi.java index 4471074c3f5..55a0804a562 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CopySpellAbilityAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CopySpellAbilityAi.java @@ -7,6 +7,7 @@ import forge.game.player.PlayerActionConfirmMode; import forge.game.spellability.SpellAbility; import java.util.List; +import java.util.Map; public class CopySpellAbilityAi extends SpellAbilityAi { @@ -36,7 +37,8 @@ public class CopySpellAbilityAi extends SpellAbilityAi { } @Override - public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells) { + public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells, + Map params) { return spells.get(0); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ActivateAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ActivateAbilityEffect.java index fc0aae36d17..3114cf48501 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ActivateAbilityEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ActivateAbilityEffect.java @@ -12,6 +12,7 @@ import forge.util.Lang; import org.apache.commons.lang3.StringUtils; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import java.util.List; @@ -49,7 +50,8 @@ public class ActivateAbilityEffect extends SpellAbilityEffect { if (possibleAb.isEmpty()) { continue; } - SpellAbility manaAb = p.getController().chooseSingleSpellForEffect(possibleAb, sa, "Choose a mana ability:"); + SpellAbility manaAb = p.getController().chooseSingleSpellForEffect( + possibleAb, sa, "Choose a mana ability:", ImmutableMap.of()); p.getController().playChosenSpellAbility(manaAb); } } 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 7cb835542b6..23ab1ad6b46 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 @@ -1,5 +1,6 @@ package forge.game.ability.effects; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; @@ -65,7 +66,8 @@ public class ChooseGenericEffect extends SpellAbilityEffect { int idxChosen = MyRandom.getRandom().nextInt(abilities.size()); chosenSA = abilities.get(idxChosen); } else { - chosenSA = p.getController().chooseSingleSpellForEffect(abilities, sa, "Choose one"); + chosenSA = p.getController().chooseSingleSpellForEffect(abilities, sa, "Choose one", + ImmutableMap.of()); } if (chosenSA != null) { 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 aa4d49c6080..4d74f5e274e 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 @@ -1,5 +1,6 @@ package forge.game.ability.effects; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -83,7 +84,8 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect { for (int multi = 0; multi < spellCount && !tgtSpells.isEmpty(); multi++) { String prompt = "Select " + Lang.getOrdinal(multi + 1) + " spell to copy to stack"; - SpellAbility chosen = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa, prompt); + SpellAbility chosen = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa, prompt, + ImmutableMap.of()); SpellAbility copiedSpell = CardFactory.copySpellAbilityAndSrcCard(card, chosen.getHostCard(), chosen, true); copiedSpell.getHostCard().setController(card.getController(), card.getGame().getNextTimestamp()); copiedSpell.setActivatingPlayer(controller); @@ -92,7 +94,8 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect { } } else if (sa.hasParam("CopyForEachCanTarget")) { - SpellAbility chosenSA = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa, "Select a spell to copy"); + SpellAbility chosenSA = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa, + "Select a spell to copy", ImmutableMap.of()); chosenSA.setActivatingPlayer(controller); // Find subability or rootability that has targets SpellAbility targetedSA = chosenSA; @@ -152,7 +155,8 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect { } } else { - SpellAbility chosenSA = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa, "Select a spell to copy"); + SpellAbility chosenSA = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa, + "Select a spell to copy", ImmutableMap.of()); chosenSA.setActivatingPlayer(controller); for (int i = 0; i < amount; i++) { copies.add(CardFactory.copySpellAbilityAndSrcCard(card, chosenSA.getHostCard(), chosenSA, true)); diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java index 40849fccd4f..3d02dcea56d 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -107,7 +107,8 @@ public abstract class PlayerController { public final T chooseSingleEntityForEffect(FCollectionView optionList, SpellAbility sa, String title) { return chooseSingleEntityForEffect(optionList, null, sa, title, false, null); } public final T chooseSingleEntityForEffect(FCollectionView optionList, SpellAbility sa, String title, boolean isOptional) { return chooseSingleEntityForEffect(optionList, null, sa, title, isOptional, null); } public abstract T chooseSingleEntityForEffect(FCollectionView optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player relatedPlayer); - public abstract SpellAbility chooseSingleSpellForEffect(List spells, SpellAbility sa, String title); + public abstract SpellAbility chooseSingleSpellForEffect(List spells, SpellAbility sa, String title, + Map params); public abstract List chooseEntitiesForEffect(FCollectionView optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, Player relatedPlayer); diff --git a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java index 0f237eadf20..0994bcc54f1 100644 --- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java +++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java @@ -167,7 +167,8 @@ public class PlayerControllerForTests extends PlayerController { } @Override - public SpellAbility chooseSingleSpellForEffect(List spells, SpellAbility sa, String title) { + public SpellAbility chooseSingleSpellForEffect(List spells, SpellAbility sa, String title, + Map params) { return chooseItem(spells); } diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index c050ea72183..ea704cbf6ba 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -537,7 +537,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont @Override public SpellAbility chooseSingleSpellForEffect(final List spells, final SpellAbility sa, - final String title) { + final String title, Map params) { if (spells.size() < 2) { return Iterables.getFirst(spells, null); } From ccb5e6d6a5fea81f94c09367196226327c7aa709 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sat, 2 Jun 2018 20:36:37 +0200 Subject: [PATCH 03/20] AssignGroup API: use for Friend or Foe --- .../src/main/java/forge/ai/SpellApiToAi.java | 1 + .../java/forge/ai/ability/AssignGroupAi.java | 33 +++++++++ .../forge/game/ability/AbilityFactory.java | 2 +- .../main/java/forge/game/ability/ApiType.java | 1 + .../ability/effects/AssignGroupEffect.java | 74 +++++++++++++++++++ 5 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java create mode 100644 forge-game/src/main/java/forge/game/ability/effects/AssignGroupEffect.java diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index c11bd25aad6..ba1b33e24fe 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -25,6 +25,7 @@ public enum SpellApiToAi { .put(ApiType.AnimateAll, AnimateAllAi.class) .put(ApiType.Attach, AttachAi.class) .put(ApiType.Ascend, AlwaysPlayAi.class) + .put(ApiType.AssignGroup, AssignGroupAi.class) .put(ApiType.Balance, BalanceAi.class) .put(ApiType.BecomeMonarch, AlwaysPlayAi.class) .put(ApiType.BecomesBlocked, BecomesBlockedAi.class) diff --git a/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java b/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java new file mode 100644 index 00000000000..caed42cdf5f --- /dev/null +++ b/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java @@ -0,0 +1,33 @@ +package forge.ai.ability; + +import java.util.List; +import java.util.Map; + +import com.google.common.collect.Iterables; + +import forge.ai.SpellAbilityAi; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; + +public class AssignGroupAi extends SpellAbilityAi { + + public AssignGroupAi() { + // TODO Auto-generated constructor stub + } + + public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells, Map params) { + if (sa.hasParam("AILogic")) { + return Iterables.getFirst(spells, null); + } + final String logic = sa.getParam("AILogic"); + + if (logic.equals("FriendOrFoe")) { + if (params.containsKey("Affected") && spells.size() >= 2) { + Player t = (Player) params.get("Affected"); + return spells.get(player.isOpponentOf(t) ? 1 : 0); + } + } + + return Iterables.getFirst(spells, null); + } +} diff --git a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java index e68d8fb454a..b068872a5b4 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java @@ -256,7 +256,7 @@ public final class AbilityFactory { } } - if (api == ApiType.Charm || api == ApiType.GenericChoice) { + if (api == ApiType.Charm || api == ApiType.GenericChoice || api == ApiType.AssignGroup) { final String key = "Choices"; if (mapParams.containsKey(key)) { List names = Lists.newArrayList(mapParams.get(key).split(",")); diff --git a/forge-game/src/main/java/forge/game/ability/ApiType.java b/forge-game/src/main/java/forge/game/ability/ApiType.java index ad4f48c739c..fc8d9ea98d7 100644 --- a/forge-game/src/main/java/forge/game/ability/ApiType.java +++ b/forge-game/src/main/java/forge/game/ability/ApiType.java @@ -21,6 +21,7 @@ public enum ApiType { AnimateAll (AnimateAllEffect.class), Attach (AttachEffect.class), Ascend (AscendEffect.class), + AssignGroup (AssignGroupEffect.class), Balance (BalanceEffect.class), BecomeMonarch (BecomeMonarchEffect.class), BecomesBlocked (BecomesBlockedEffect.class), diff --git a/forge-game/src/main/java/forge/game/ability/effects/AssignGroupEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AssignGroupEffect.java new file mode 100644 index 00000000000..eb53cecf76b --- /dev/null +++ b/forge-game/src/main/java/forge/game/ability/effects/AssignGroupEffect.java @@ -0,0 +1,74 @@ +package forge.game.ability.effects; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; + +import forge.game.Game; +import forge.game.GameObject; +import forge.game.ability.AbilityUtils; +import forge.game.ability.SpellAbilityEffect; +import forge.game.card.Card; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; + +public class AssignGroupEffect extends SpellAbilityEffect { + + /* (non-Javadoc) + * @see forge.game.ability.SpellAbilityEffect#getStackDescription(forge.game.spellability.SpellAbility) + */ + @Override + protected String getStackDescription(SpellAbility sa) { + return sa.getDescription(); + } + + /* + * (non-Javadoc) + * @see forge.game.ability.SpellAbilityEffect#resolve(forge.game.spellability.SpellAbility) + */ + @Override + public void resolve(SpellAbility sa) { + final Card host = sa.getHostCard(); + final Game game = host.getGame(); + + List defined = getDefinedOrTargeted(sa, "Defined"); + + final List abilities = Lists.newArrayList(sa.getAdditionalAbilityList("Choices")); + + Player chooser = sa.getActivatingPlayer(); + if (sa.hasParam("Chooser")) { + final String choose = sa.getParam("Chooser"); + chooser = AbilityUtils.getDefinedPlayers(sa.getHostCard(), choose, sa).get(0); + } + + Multimap result = ArrayListMultimap.create(); + + for (GameObject g : defined) { + final String title = "Choose ability for " + g.toString(); + Map params = Maps.newHashMap(); + params.put("Affected", g); + + result.put(chooser.getController().chooseSingleSpellForEffect(abilities, sa, title, params), g); + } + + // in order of choice list + for (SpellAbility s : abilities) { + // is that in Player order? + Collection l = result.get(s); + + host.addRemembered(l); + AbilityUtils.resolve(s); + host.removeRemembered(l); + + // this will refresh continuous abilities for players and permanents. + game.getAction().checkStaticAbilities(); + game.getTriggerHandler().resetActiveTriggers(false); + } + } + +} From ae5bb38c92956311c44fc051cae7feeff5022564 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sat, 2 Jun 2018 20:37:00 +0200 Subject: [PATCH 04/20] cards: add Pir Whim as example --- forge-gui/res/cardsfolder/upcoming/pirs_whim.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/pirs_whim.txt diff --git a/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt b/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt new file mode 100644 index 00000000000..d4cf2289588 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt @@ -0,0 +1,8 @@ +Name:Pir's Whim +ManaCost:3 G +Types:Sorcery +A:SP$ AssignGroup | Cost$ 3 G | Defined$ Player | Choices$ DBSearch,DBSacrifice | SpellDescription$ For each player, choose friend or foe. Each friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. Each foe sacrifices an artifact or enchantment they control. +SVar:DBSearch:DB$ChangeZone | Origin$ Library | Destination$ Battlefield | DefinedPlayer$ Remembered | ChangeType$ Land | ChangeNum$ 1 | StackDescription$ Each friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. | SpellDescription$ Friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. +SVar:DBSacrifice:DB$Sacrifice | Defined$ Remembered | SacValid$ Artifact,Enchantment | SacMessage$ artifact or enchantment | StackDescription$ Each foe sacrifices an artifact or enchantment they control. | SpellDescription$ Foe sacrifices an artifact or enchantment they control. +SVar:Picture:http://www.wizards.com/global/images/magic/general/pirs_whim.jpg +Oracle:For each player, choose friend or foe. Each friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. Each foe sacrifices an artifact or enchantment they control. From 2a3456d0e22b6c696e7e7d2427b13c89e697dfb0 Mon Sep 17 00:00:00 2001 From: Agetian Date: Sun, 3 Jun 2018 07:58:34 +0300 Subject: [PATCH 05/20] - Corrected the base logic for AssignGroupAi. - Added AILogic to Pir's Whim. --- forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java | 5 +---- forge-gui/res/cardsfolder/upcoming/pirs_whim.txt | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java b/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java index caed42cdf5f..fb1b769347d 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java @@ -16,10 +16,7 @@ public class AssignGroupAi extends SpellAbilityAi { } public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells, Map params) { - if (sa.hasParam("AILogic")) { - return Iterables.getFirst(spells, null); - } - final String logic = sa.getParam("AILogic"); + final String logic = sa.getParamOrDefault("AILogic", ""); if (logic.equals("FriendOrFoe")) { if (params.containsKey("Affected") && spells.size() >= 2) { diff --git a/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt b/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt index d4cf2289588..dafdee4b0e7 100644 --- a/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt +++ b/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt @@ -1,7 +1,7 @@ Name:Pir's Whim ManaCost:3 G Types:Sorcery -A:SP$ AssignGroup | Cost$ 3 G | Defined$ Player | Choices$ DBSearch,DBSacrifice | SpellDescription$ For each player, choose friend or foe. Each friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. Each foe sacrifices an artifact or enchantment they control. +A:SP$ AssignGroup | Cost$ 3 G | Defined$ Player | Choices$ DBSearch,DBSacrifice | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. Each foe sacrifices an artifact or enchantment they control. SVar:DBSearch:DB$ChangeZone | Origin$ Library | Destination$ Battlefield | DefinedPlayer$ Remembered | ChangeType$ Land | ChangeNum$ 1 | StackDescription$ Each friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. | SpellDescription$ Friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. SVar:DBSacrifice:DB$Sacrifice | Defined$ Remembered | SacValid$ Artifact,Enchantment | SacMessage$ artifact or enchantment | StackDescription$ Each foe sacrifices an artifact or enchantment they control. | SpellDescription$ Foe sacrifices an artifact or enchantment they control. SVar:Picture:http://www.wizards.com/global/images/magic/general/pirs_whim.jpg From 80963222d1e76abe54ed5784d708751b20d44cbd Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sun, 3 Jun 2018 13:42:38 +0200 Subject: [PATCH 06/20] CopyPermanent: add Param for Chooser --- .../forge/game/ability/effects/CopyPermanentEffect.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 c42e215fab3..2c026736c05 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 @@ -167,12 +167,18 @@ public class CopyPermanentEffect extends SpellAbilityEffect { } } } else if (sa.hasParam("Choices")) { + Player chooser = activator; + if (sa.hasParam("Chooser")) { + final String choose = sa.getParam("Chooser"); + chooser = AbilityUtils.getDefinedPlayers(sa.getHostCard(), choose, sa).get(0); + } + CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield); choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host); if (!choices.isEmpty()) { String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : "Choose a card "; - Card choosen = activator.getController().chooseSingleEntityForEffect(choices, sa, title, false); + Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false); if (choosen != null) { tgtCards.add(choosen); From 8dd5faf9c9334e993b16f007e160ad07885246ae Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sun, 3 Jun 2018 13:44:50 +0200 Subject: [PATCH 07/20] cards: add Zndrsplt's Judgement --- .../res/cardsfolder/upcoming/zndrsplt_judgment.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt diff --git a/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt b/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt new file mode 100644 index 00000000000..9c09dd67293 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt @@ -0,0 +1,12 @@ +Name:Zndrsplt's Judgment +ManaCost:4 U +Types:Sorcery +A:SP$ AssignGroup | Cost$ 3 G | Defined$ Player | Choices$ FriendRepeat,FoeRepeat | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend creates a token that's a copy of a creature they control. Each foe returns a creature they control to its owner's hand. +SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ DBClone | StackDescription$ Each friend creates a token that's a copy of a creature they control. | SpellDescription$ Friend creates a token that's a copy of a creature they control. +SVar:DBClone:DB$ CopyPermanent | Choices$ Creature.RememberedPlayerCtrl | Chooser$ Remembered | Controller$ Remembered +SVar:FoeRepeat:DB$ RepeatEach | Cost$ U | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | SubAbility$ BounceAll | StackDescription$ Each foe returns a creature they control to its owner's hand. | SpellDescription$ Foe returns a creature they control to its owner's hand. +SVar:PlayChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl | Amount$ 1 | Mandatory$ True | AILogic$ WorstCard | ChoiceTitle$ Choose a creature you control | RememberChosen$ True +SVar:BounceAll:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Hand | ChangeType$ Creature.IsRemembered +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/zndrsplt_judgment.jpg +Oracle:For each player, choose friend or foe. Each friend creates a token that's a copy of a creature they control. Each foe returns a creature they control to its owner's hand. From dc7f692f3895a3b1dbb4b220415c2f4704537d73 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sun, 3 Jun 2018 18:21:02 +0200 Subject: [PATCH 08/20] Game: Counters Put effects need to have Putter as Source --- .../main/java/forge/ai/ComputerUtilCard.java | 2 +- .../src/main/java/forge/game/GameEntity.java | 3 +- .../ability/effects/ChangeZoneEffect.java | 2 +- .../ability/effects/CountersMoveEffect.java | 8 ++--- .../effects/CountersMultiplyEffect.java | 6 ++-- .../ability/effects/CountersNoteEffect.java | 7 +++-- .../effects/CountersProliferateEffect.java | 5 ++-- .../ability/effects/CountersPutAllEffect.java | 15 +++++++--- .../ability/effects/CountersPutEffect.java | 20 ++++++++----- .../effects/CountersPutOrRemoveEffect.java | 7 +++-- .../forge/game/ability/effects/DigEffect.java | 2 +- .../game/ability/effects/ExploreEffect.java | 3 +- .../game/ability/effects/SacrificeEffect.java | 2 +- .../game/ability/effects/SetStateEffect.java | 2 +- .../src/main/java/forge/game/card/Card.java | 18 +++++------- .../java/forge/game/card/CardFactoryUtil.java | 12 +++----- .../java/forge/game/cost/CostPutCounter.java | 2 +- .../forge/game/cost/CostRemoveCounter.java | 2 +- .../main/java/forge/game/player/Player.java | 6 ++-- .../game/trigger/TriggerCounterAddedOnce.java | 29 +++++++++---------- .../ai/simulation/GameSimulatorTest.java | 12 ++++---- .../res/cardsfolder/d/defiant_greatmaw.txt | 2 +- .../h/hapatra_vizier_of_poisons.txt | 2 +- .../res/cardsfolder/n/nest_of_scarabs.txt | 2 +- .../res/cardsfolder/o/obelisk_spider.txt | 2 +- .../src/main/java/forge/player/HumanPlay.java | 4 +-- .../forge/player/PlayerControllerHuman.java | 2 +- 27 files changed, 94 insertions(+), 85 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index ae3a451a74a..bce1ec8a53e 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -1576,7 +1576,7 @@ public class ComputerUtilCard { pumped.addChangedCardKeywords(kws, null, false, false, timestamp); Set types = c.getCounters().keySet(); for(CounterType ct : types) { - pumped.addCounterFireNoEvents(ct, c.getCounters(ct), c, true); + pumped.addCounterFireNoEvents(ct, c.getCounters(ct), ai, true); } //Copies tap-state and extra keywords (auras, equipment, etc.) if (c.isTapped()) { diff --git a/forge-game/src/main/java/forge/game/GameEntity.java b/forge-game/src/main/java/forge/game/GameEntity.java index 61c5ad6457a..cd57b92a10c 100644 --- a/forge-game/src/main/java/forge/game/GameEntity.java +++ b/forge-game/src/main/java/forge/game/GameEntity.java @@ -25,6 +25,7 @@ import forge.game.card.CounterType; import forge.game.event.GameEventCardAttachment; import forge.game.event.GameEventCardAttachment.AttachMethod; import forge.game.keyword.Keyword; +import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.trigger.TriggerType; import forge.util.collect.FCollection; @@ -365,7 +366,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { abstract public void setCounters(final Map allCounters); abstract public boolean canReceiveCounters(final CounterType type); - abstract public void addCounter(final CounterType counterType, final int n, final Card source, final boolean applyMultiplier, final boolean fireEvents); + abstract public void addCounter(final CounterType counterType, final int n, final Player source, final boolean applyMultiplier, final boolean fireEvents); abstract public void subtractCounter(final CounterType counterName, final int n); abstract public void clearCounters(); 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 df665e7a7cb..096e780d397 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 @@ -484,7 +484,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } if (sa.hasParam("WithCounters")) { String[] parse = sa.getParam("WithCounters").split("_"); - tgtC.addEtbCounter(CounterType.getType(parse[0]), Integer.parseInt(parse[1]), hostCard); + tgtC.addEtbCounter(CounterType.getType(parse[0]), Integer.parseInt(parse[1]), player); } if (sa.hasParam("GainControl")) { if (sa.hasParam("NewController")) { 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 5c876c6720b..cea93674399 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 @@ -145,7 +145,7 @@ public class CountersMoveEffect extends SpellAbilityEffect { } if (csum > 0) { - dest.addCounter(cType, csum, host, true); + dest.addCounter(cType, csum, player, true); game.updateLastStateForCard(dest); } return; @@ -201,7 +201,7 @@ public class CountersMoveEffect extends SpellAbilityEffect { if (cnum > 0) { source.subtractCounter(cType, cnum); - dest.addCounter(cType, cnum, host, true); + dest.addCounter(cType, cnum, player, true); game.updateLastStateForCard(dest); updateSource = true; } @@ -262,7 +262,7 @@ public class CountersMoveEffect extends SpellAbilityEffect { if (source.getCounters(cType) >= cntToMove) { source.subtractCounter(cType, cntToMove); - dest.addCounter(cType, cntToMove, host, true); + dest.addCounter(cType, cntToMove, player, true); game.updateLastStateForCard(dest); } } else { @@ -296,7 +296,7 @@ public class CountersMoveEffect extends SpellAbilityEffect { sa, sb.toString(), 0, Math.min(tgtCounters.get(chosenType), cntToMove), params); if (chosenAmount > 0) { - dest.addCounter(chosenType, chosenAmount, host, true); + dest.addCounter(chosenType, chosenAmount, player, true); source.subtractCounter(chosenType, chosenAmount); game.updateLastStateForCard(dest); cntToMove -= chosenAmount; diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersMultiplyEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersMultiplyEffect.java index 08117188072..8eaced12614 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersMultiplyEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersMultiplyEffect.java @@ -7,6 +7,7 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CounterType; +import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.util.Lang; @@ -37,6 +38,7 @@ public class CountersMultiplyEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); final Game game = host.getGame(); + final Player player = sa.getActivatingPlayer(); final CounterType counterType = getCounterType(sa); final int n = Integer.valueOf(sa.getParamOrDefault("Multiplier", "2")) - 1; @@ -50,10 +52,10 @@ public class CountersMultiplyEffect extends SpellAbilityEffect { continue; } if (counterType != null) { - gameCard.addCounter(counterType, gameCard.getCounters(counterType) * n, host, true); + gameCard.addCounter(counterType, gameCard.getCounters(counterType) * n, player, true); } else { for (Map.Entry e : gameCard.getCounters().entrySet()) { - gameCard.addCounter(e.getKey(), e.getValue() * n, host, true); + gameCard.addCounter(e.getKey(), e.getValue() * n, player, true); } } game.updateLastStateForCard(gameCard); diff --git a/forge-game/src/main/java/forge/game/ability/effects/CountersNoteEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CountersNoteEffect.java index b5190983232..21a7f4c9d2c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CountersNoteEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CountersNoteEffect.java @@ -6,6 +6,7 @@ import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CounterType; +import forge.game.player.Player; import forge.game.spellability.SpellAbility; public class CountersNoteEffect extends SpellAbilityEffect { @@ -26,7 +27,7 @@ public class CountersNoteEffect extends SpellAbilityEffect { if (mode.equals(MODE_STORE)) { noteCounters(c, source); } else if (mode.equals(MODE_LOAD)) { - loadCounters(c, source); + loadCounters(c, source, sa.getActivatingPlayer()); } } } @@ -39,11 +40,11 @@ public class CountersNoteEffect extends SpellAbilityEffect { } } - private void loadCounters(Card notee, Card source) { + private void loadCounters(Card notee, Card source, final Player p) { for(Entry svar : source.getSVars().entrySet()) { String key = svar.getKey(); if (key.startsWith(NOTE_COUNTERS)) { - notee.addCounter(CounterType.getType(key.substring(NOTE_COUNTERS.length())), Integer.parseInt(svar.getValue()), source, false); + notee.addCounter(CounterType.getType(key.substring(NOTE_COUNTERS.length())), Integer.parseInt(svar.getValue()), p, false); } // TODO Probably should "remove" the svars that were temporarily used } 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 4b317322118..f5ef5b95ed8 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 @@ -24,6 +24,7 @@ public class CountersProliferateEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { + final Player p = sa.getActivatingPlayer(); final Card host = sa.getHostCard(); final Game game = host.getGame(); Player controller = host.getController(); @@ -32,10 +33,10 @@ public class CountersProliferateEffect extends SpellAbilityEffect { return; for(Entry ge: proliferateChoice.entrySet()) { if( ge.getKey() instanceof Player ) - ((Player) ge.getKey()).addCounter(ge.getValue(), 1, host, true); + ((Player) ge.getKey()).addCounter(ge.getValue(), 1, p, true); else if( ge.getKey() instanceof Card) { Card c = (Card) ge.getKey(); - c.addCounter(ge.getValue(), 1, host, true); + c.addCounter(ge.getValue(), 1, p, true); game.updateLastStateForCard(c); } } 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 29843622384..89999962a72 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 @@ -38,30 +38,37 @@ public class CountersPutAllEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); + final Player activator = sa.getActivatingPlayer(); final String type = sa.getParam("CounterType"); final int counterAmount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("CounterNum"), sa); final String valid = sa.getParam("ValidCards"); final ZoneType zone = sa.hasParam("ValidZone") ? ZoneType.smartValueOf(sa.getParam("ValidZone")) : ZoneType.Battlefield; - final Game game = sa.getActivatingPlayer().getGame(); + final Game game = activator.getGame(); if (counterAmount <= 0) { return; } CardCollectionView cards = game.getCardsIn(zone); - cards = CardLists.getValidCards(cards, valid, sa.getHostCard().getController(), sa.getHostCard()); + cards = CardLists.getValidCards(cards, valid, host.getController(), sa.getHostCard()); if (sa.usesTargeting()) { final Player pl = sa.getTargets().getFirstTargetedPlayer(); cards = CardLists.filterControlledBy(cards, pl); } + Player putter = activator; + if (sa.hasParam("Putter")) { + final String pstr = sa.getParam("Putter"); + putter = AbilityUtils.getDefinedPlayers(host, pstr, sa).get(0); + } + for (final Card tgtCard : cards) { if (game.getZoneOf(tgtCard).is(ZoneType.Battlefield)) { - tgtCard.addCounter(CounterType.valueOf(type), counterAmount, host, true); + tgtCard.addCounter(CounterType.valueOf(type), counterAmount, putter, true); } else { // adding counters to something like re-suspend cards - tgtCard.addCounter(CounterType.valueOf(type), counterAmount, host, false); + tgtCard.addCounter(CounterType.valueOf(type), counterAmount, putter, false); } game.updateLastStateForCard(tgtCard); } 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 d58b3ab209c..99d065efc14 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 @@ -110,6 +110,12 @@ public class CountersPutEffect extends SpellAbilityEffect { } } + Player putter = activator; + if (sa.hasParam("Putter")) { + final String pstr = sa.getParam("Putter"); + putter = 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"); @@ -155,10 +161,10 @@ public class CountersPutEffect extends SpellAbilityEffect { if (eachExistingCounter) { for(CounterType ct : choices) { if (obj instanceof Player) { - ((Player) obj).addCounter(ct, counterAmount, card, true); + ((Player) obj).addCounter(ct, counterAmount, putter, true); } if (obj instanceof Card) { - ((Card) obj).addCounter(ct, counterAmount, card, true); + ((Card) obj).addCounter(ct, counterAmount, putter, true); } } continue; @@ -232,9 +238,9 @@ public class CountersPutEffect extends SpellAbilityEffect { final Zone zone = tgtCard.getGame().getZoneOf(tgtCard); if (zone == null || zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Stack)) { if (etbcounter) { - tgtCard.addEtbCounter(counterType, counterAmount, card); + tgtCard.addEtbCounter(counterType, counterAmount, putter); } else { - tgtCard.addCounter(counterType, counterAmount, card, true); + tgtCard.addCounter(counterType, counterAmount, putter, true); } if (remember) { final int value = tgtCard.getTotalCountersToAdd(); @@ -263,9 +269,9 @@ public class CountersPutEffect extends SpellAbilityEffect { // adding counters to something like re-suspend cards // etbcounter should apply multiplier if (etbcounter) { - tgtCard.addEtbCounter(counterType, counterAmount, card); + tgtCard.addEtbCounter(counterType, counterAmount, putter); } else { - tgtCard.addCounter(counterType, counterAmount, card, false); + tgtCard.addCounter(counterType, counterAmount, putter, false); } } game.updateLastStateForCard(tgtCard); @@ -273,7 +279,7 @@ public class CountersPutEffect extends SpellAbilityEffect { } else if (obj instanceof Player) { // Add Counters to players! Player pl = (Player) obj; - pl.addCounter(counterType, counterAmount, card, true); + pl.addCounter(counterType, counterAmount, putter, true); } } } 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 9273c1ce2c6..979e383ab54 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 @@ -5,6 +5,7 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CounterType; +import forge.game.player.Player; import forge.game.player.PlayerController; import forge.game.player.PlayerController.BinaryChoiceType; import forge.game.spellability.SpellAbility; @@ -81,8 +82,8 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect { private void addOrRemoveCounter(final SpellAbility sa, final Card tgtCard, CounterType ctype, final int counterAmount) { - PlayerController pc = sa.getActivatingPlayer().getController(); - final Card source = sa.getHostCard(); + final Player pl = sa.getActivatingPlayer(); + final PlayerController pc = pl.getController(); Map params = Maps.newHashMap(); params.put("Target", tgtCard); @@ -105,7 +106,7 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect { boolean apply = zone == null || zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Stack); - tgtCard.addCounter(chosenType, counterAmount, source, apply); + tgtCard.addCounter(chosenType, counterAmount, pl, apply); } else { tgtCard.subtractCounter(chosenType, counterAmount); } 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 80af5a1622a..365adf0855a 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 @@ -377,7 +377,7 @@ public class DigEffect extends SpellAbilityEffect { } } else if (destZone2 == ZoneType.Exile) { if (sa.hasParam("ExileWithCounter")) { - c.addCounter(CounterType.getType(sa.getParam("ExileWithCounter")), 1, effectHost, true); + c.addCounter(CounterType.getType(sa.getParam("ExileWithCounter")), 1, player, true); } c.setExiledWith(effectHost); } 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 942512a5ad7..c06be791574 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 @@ -44,7 +44,6 @@ public class ExploreEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { // check if only the activating player counts - final Card card = sa.getHostCard(); final Player pl = sa.getActivatingPlayer(); final PlayerController pc = pl.getController(); final Game game = pl.getGame(); @@ -78,7 +77,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.getTimestamp() == c.getTimestamp()) { - c.addCounter(CounterType.P1P1, 1, card, true); + c.addCounter(CounterType.P1P1, 1, pl, true); } } 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 f3809584b62..7b371dc58c4 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 @@ -43,7 +43,7 @@ public class SacrificeEffect extends SpellAbilityEffect { return; } } else if (sa.hasParam("CumulativeUpkeep")) { - card.addCounter(CounterType.AGE, 1, card, true); + card.addCounter(CounterType.AGE, 1, activator, true); Cost cumCost = new Cost(sa.getParam("CumulativeUpkeep"), true); Cost payCost = new Cost(ManaCost.ZERO, true); int n = card.getCounters(CounterType.AGE); 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 91695cd6580..5562acf460c 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 @@ -104,7 +104,7 @@ public class SetStateEffect extends SpellAbilityEffect { } game.fireEvent(new GameEventCardStatsChanged(tgt)); if (sa.hasParam("Mega")) { - tgt.addCounter(CounterType.P1P1, 1, host, true); + tgt.addCounter(CounterType.P1P1, 1, p, true); } if (remChanged) { host.addRemembered(tgt); 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 1e0175cfa88..f8607957d2b 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -249,7 +249,7 @@ public class Card extends GameEntity implements Comparable { private CardRules cardRules; private final CardView view; - private Table etbCounters = HashBasedTable.create(); + private Table etbCounters = HashBasedTable.create(); private SpellAbility[] basicLandAbilities = new SpellAbility[MagicColor.WUBRG.length]; @@ -1060,15 +1060,15 @@ public class Card extends GameEntity implements Comparable { countersAdded = value; } - public final void addCounter(final CounterType counterType, final int n, final Card source, final boolean applyMultiplier) { + public final void addCounter(final CounterType counterType, final int n, final Player source, final boolean applyMultiplier) { addCounter(counterType, n, source, applyMultiplier, true); } - public final void addCounterFireNoEvents(final CounterType counterType, final int n, final Card source, final boolean applyMultiplier) { + public final void addCounterFireNoEvents(final CounterType counterType, final int n, final Player source, final boolean applyMultiplier) { addCounter(counterType, n, source, applyMultiplier, false); } @Override - public void addCounter(final CounterType counterType, final int n, final Card source, final boolean applyMultiplier, final boolean fireEvents) { + public void addCounter(final CounterType counterType, final int n, final Player source, final boolean applyMultiplier, final boolean fireEvents) { int addAmount = n; if(addAmount < 0) { addAmount = 0; // As per rule 107.1b @@ -4637,7 +4637,7 @@ public class Card extends GameEntity implements Comparable { if (isInPlay()) { if (wither) { - addCounter(CounterType.M1M1, damageIn, source, true); + addCounter(CounterType.M1M1, damageIn, source.getController(), true); damageType = DamageType.M1M1Counters; } else { @@ -5719,11 +5719,7 @@ public class Card extends GameEntity implements Comparable { * and when the Card really enters the Battlefield with the counters * @return map of counters */ - public final void addEtbCounter(CounterType type, Integer val) { - addEtbCounter(type, val, this); - } - - public final void addEtbCounter(CounterType type, Integer val, final Card source) { + public final void addEtbCounter(CounterType type, Integer val, final Player source) { int old = etbCounters.contains(source, type) ? etbCounters.get(source, type) : 0; etbCounters.put(source, type, old + val); } @@ -5733,7 +5729,7 @@ public class Card extends GameEntity implements Comparable { } public final void putEtbCounters() { - for (Table.Cell e : etbCounters.cellSet()) { + for (Table.Cell e : etbCounters.cellSet()) { this.addCounter(e.getColumnKey(), e.getValue(), e.getRowKey(), true); } } 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 c4a17b85912..4819a6c7914 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -4027,12 +4027,8 @@ public class CardFactoryUtil { @Override public void run() { - if (card.isCreature()) { - card.addCounter(CounterType.P1P1, card.getSunburstValue(), card, true); - } else { - card.addCounter(CounterType.CHARGE, card.getSunburstValue(), card, true); - } - + CounterType t = card.isCreature() ? CounterType.P1P1 : CounterType.CHARGE; + card.addCounter(t, card.getSunburstValue(), card.getController(), true); } }; @@ -4091,9 +4087,9 @@ public class CardFactoryUtil { final Card c = game.getAction().exile(this.getHostCard(), this); int counters = AbilityUtils.calculateAmount(c, k[1], this); - c.addCounter(CounterType.TIME, counters, c, true); + c.addCounter(CounterType.TIME, counters, getActivatingPlayer(), true); - String sb = TextUtil.concatWithSpace(this.getActivatingPlayer().toString(),"has suspended", c.getName(), "with", String.valueOf(counters),"time counters on it."); + String sb = TextUtil.concatWithSpace(getActivatingPlayer().toString(),"has suspended", c.getName(), "with", String.valueOf(counters),"time counters on it."); game.getGameLog().add(GameLogEntryType.STACK_RESOLVE, sb); } }; 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 be83e5d0490..c33bbea5441 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPutCounter.java +++ b/forge-game/src/main/java/forge/game/cost/CostPutCounter.java @@ -188,7 +188,7 @@ public class CostPutCounter extends CostPartWithList { */ @Override protected Card doPayment(SpellAbility ability, Card targetCard){ - targetCard.addCounter(this.getCounter(), 1, ability.getHostCard(), false); + targetCard.addCounter(this.getCounter(), 1, ability.getActivatingPlayer(), false); return targetCard; } 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 9d30526dad1..d4b2d6b9c5c 100644 --- a/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java +++ b/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java @@ -114,7 +114,7 @@ public class CostRemoveCounter extends CostPartWithList { public final void refund(final Card source) { int refund = this.getCardList().size() == 1 ? this.cntRemoved : 1; // is wrong for Ooze Flux and Novijen Sages for (final Card c : this.getCardList()) { - c.addCounter(this.counter, refund, source, false); + c.addCounter(this.counter, refund, source.getController(), false); } } 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 f24bf5b3113..ef98aee7dcd 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -876,12 +876,12 @@ public class Player extends GameEntity implements Comparable { return true; } - public final void addCounter(final CounterType counterType, final int n, final Card source, final boolean applyMultiplier) { + public final void addCounter(final CounterType counterType, final int n, final Player source, final boolean applyMultiplier) { addCounter(counterType, n, source, applyMultiplier, true); } @Override - public void addCounter(CounterType counterType, int n, final Card source, boolean applyMultiplier, boolean fireEvents) { + public void addCounter(CounterType counterType, int n, final Player source, boolean applyMultiplier, boolean fireEvents) { if (!canReceiveCounters(counterType)) { return; } @@ -983,7 +983,7 @@ public class Player extends GameEntity implements Comparable { } public final void addPoisonCounters(final int num, final Card source) { int oldPoison = getCounters(CounterType.POISON); - addCounter(CounterType.POISON, num, source, false, true); + addCounter(CounterType.POISON, num, source.getController(), false, true); if (oldPoison != getCounters(CounterType.POISON)) { game.fireEvent(new GameEventPlayerPoisoned(this, source, oldPoison, num)); diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedOnce.java index 74b5f898122..549a3d81670 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedOnce.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedOnce.java @@ -53,15 +53,21 @@ public class TriggerCounterAddedOnce extends Trigger { /** {@inheritDoc} */ @Override public final boolean performTest(final Map runParams2) { - final CounterType addedType = (CounterType) runParams2.get("CounterType"); + if (hasParam("CounterType")) { + final CounterType addedType = (CounterType) runParams2.get("CounterType"); + final String type = getParam("CounterType"); + if (!type.equals(addedType.toString())) { + return false; + } + } if (hasParam("ValidCard")) { if (!runParams2.containsKey("Card")) return false; final Card addedTo = (Card) runParams2.get("Card"); - if (!addedTo.isValid(getParam("ValidCard").split(","), this.getHostCard().getController(), - this.getHostCard(), null)) { + if (!addedTo.isValid(getParam("ValidCard").split(","), getHostCard().getController(), + getHostCard(), null)) { return false; } } @@ -71,8 +77,8 @@ public class TriggerCounterAddedOnce extends Trigger { return false; final Player addedTo = (Player) runParams2.get("Player"); - if (!addedTo.isValid(getParam("ValidPlayer").split(","), this.getHostCard().getController(), - this.getHostCard(), null)) { + if (!addedTo.isValid(getParam("ValidPlayer").split(","), getHostCard().getController(), + getHostCard(), null)) { return false; } } @@ -81,21 +87,14 @@ public class TriggerCounterAddedOnce extends Trigger { if (!runParams2.containsKey("Source")) return false; - final Card source = (Card) runParams2.get("Source"); + final Player source = (Player) runParams2.get("Source"); if (source == null) { return false; } - if (!source.isValid(getParam("ValidSource").split(","), this.getHostCard().getController(), - this.getHostCard(), null)) { - return false; - } - } - - if (hasParam("CounterType")) { - final String type = getParam("CounterType"); - if (!type.equals(addedType.toString())) { + if (!source.isValid(getParam("ValidSource").split(","), getHostCard().getController(), + getHostCard(), null)) { return false; } } 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 7fea93ce0e4..8508b594ac1 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 @@ -215,7 +215,7 @@ public class GameSimulatorTest extends SimulationTestCase { Game game = initAndCreateGame(); Player p = game.getPlayers().get(1); Card sorin = addCard("Sorin, Solemn Visitor", p); - sorin.addCounter(CounterType.LOYALTY, 5, sorin, false); + sorin.addCounter(CounterType.LOYALTY, 5, p, false); game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); game.getAction().checkStateEffects(true); @@ -259,7 +259,7 @@ public class GameSimulatorTest extends SimulationTestCase { String bearCardName = "Runeclaw Bear"; addCard(bearCardName, p); Card gideon = addCard("Gideon, Ally of Zendikar", p); - gideon.addCounter(CounterType.LOYALTY, 4, gideon, false); + gideon.addCounter(CounterType.LOYALTY, 4, p, false); game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); game.getAction().checkStateEffects(true); @@ -378,7 +378,7 @@ public class GameSimulatorTest extends SimulationTestCase { Game game = initAndCreateGame(); Player p = game.getPlayers().get(1); Card sarkhan = addCard(sarkhanCardName, p); - sarkhan.addCounter(CounterType.LOYALTY, 4, sarkhan, false); + sarkhan.addCounter(CounterType.LOYALTY, 4, p, false); game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); game.getAction().checkStateEffects(true); @@ -412,7 +412,7 @@ public class GameSimulatorTest extends SimulationTestCase { addCard(ornithoperCardName, p); addCard(bearCardName, p); Card ajani = addCard(ajaniCardName, p); - ajani.addCounter(CounterType.LOYALTY, 4, ajani, false); + ajani.addCounter(CounterType.LOYALTY, 4, p, false); game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); game.getAction().checkStateEffects(true); @@ -443,7 +443,7 @@ public class GameSimulatorTest extends SimulationTestCase { SpellAbility boltSA = boltCard.getFirstSpellAbility(); Card ajani = addCard(ajaniCardName, p); - ajani.addCounter(CounterType.LOYALTY, 8, ajani, false); + ajani.addCounter(CounterType.LOYALTY, 8, p, false); game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); game.getAction().checkStateEffects(true); @@ -493,7 +493,7 @@ public class GameSimulatorTest extends SimulationTestCase { addCard("Swamp", p); addCard("Swamp", p); Card depths = addCard("Dark Depths", p); - depths.addCounter(CounterType.ICE, 10, depths, false); + depths.addCounter(CounterType.ICE, 10, p, false); Card thespian = addCard("Thespian's Stage", p); game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); game.getAction().checkStateEffects(true); diff --git a/forge-gui/res/cardsfolder/d/defiant_greatmaw.txt b/forge-gui/res/cardsfolder/d/defiant_greatmaw.txt index ff594980ec4..d8bb7ad3ec7 100644 --- a/forge-gui/res/cardsfolder/d/defiant_greatmaw.txt +++ b/forge-gui/res/cardsfolder/d/defiant_greatmaw.txt @@ -4,6 +4,6 @@ Types:Creature Hippo PT:4/5 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounter | TriggerDescription$ When CARDNAME enters the battlefield, put two -1/-1 counters on target creature you control. SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature | CounterType$ M1M1 | CounterNum$ 2 -T:Mode$ CounterAddedOnce | ValidCard$ Creature.Self | ValidSource$ Card.YouCtrl | CounterType$ M1M1 | TriggerZones$ Battlefield | Execute$ RemoveCounter | TriggerDescription$ Whenever you put one or more -1/-1 counters on CARDNAME, remove a -1/-1 counter from another target creature you control. +T:Mode$ CounterAddedOnce | ValidCard$ Creature.Self | ValidSource$ You | CounterType$ M1M1 | TriggerZones$ Battlefield | Execute$ RemoveCounter | TriggerDescription$ Whenever you put one or more -1/-1 counters on CARDNAME, remove a -1/-1 counter from another target creature you control. SVar:RemoveCounter:DB$ RemoveCounter | ValidTgts$ Creature.YouCtrl+Other | AITgts$ Creature.counters_GE1_M1M1 | TgtPrompt$ Select another target creature you control | CounterType$ M1M1 | CounterNum$ 1 Oracle:When Defiant Greatmaw enters the battlefield, put two -1/-1 counters on target creature you control.\nWhenever you put one or more -1/-1 counters on Defiant Greatmaw, remove a -1/-1 counter from another target creature you control. diff --git a/forge-gui/res/cardsfolder/h/hapatra_vizier_of_poisons.txt b/forge-gui/res/cardsfolder/h/hapatra_vizier_of_poisons.txt index 74a0f9befe4..bf8ef1713bd 100644 --- a/forge-gui/res/cardsfolder/h/hapatra_vizier_of_poisons.txt +++ b/forge-gui/res/cardsfolder/h/hapatra_vizier_of_poisons.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Human Cleric PT:2/2 T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Opponent | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may put a -1/-1 counter on target creature. SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ M1M1 | CounterNum$ 1 | IsCurse$ True -T:Mode$ CounterAddedOnce | ValidCard$ Creature | ValidSource$ Card.YouCtrl | CounterType$ M1M1 | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever you put one or more -1/-1 counters on a creature, create a 1/1 green Snake creature token with deathtouch. +T:Mode$ CounterAddedOnce | ValidCard$ Creature | ValidSource$ You | CounterType$ M1M1 | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever you put one or more -1/-1 counters on a creature, create a 1/1 green Snake creature token with deathtouch. SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenName$ Snake | TokenTypes$ Creature,Snake | TokenOwner$ You | TokenColors$ Green | TokenPower$ 1 | TokenToughness$ 1 | TokenKeywords$ Deathtouch | TokenImage$ g 1 1 snake AKH DeckHas:Ability$Counters & Ability$Token Oracle:Whenever Hapatra, Vizier of Poisons deals combat damage to a player, you may put a -1/-1 counter on target creature.\nWhenever you put one or more -1/-1 counters on a creature, create a 1/1 green Snake creature token with deathtouch. diff --git a/forge-gui/res/cardsfolder/n/nest_of_scarabs.txt b/forge-gui/res/cardsfolder/n/nest_of_scarabs.txt index 8ef46e2da80..b53230e10d4 100644 --- a/forge-gui/res/cardsfolder/n/nest_of_scarabs.txt +++ b/forge-gui/res/cardsfolder/n/nest_of_scarabs.txt @@ -1,7 +1,7 @@ Name:Nest of Scarabs ManaCost:2 B Types:Enchantment -T:Mode$ CounterAddedOnce | ValidCard$ Creature | ValidSource$ Card.YouCtrl | CounterType$ M1M1 | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever you put one or more -1/-1 counters on a creature, create that many 1/1 black Insect creature tokens. +T:Mode$ CounterAddedOnce | ValidCard$ Creature | ValidSource$ You | CounterType$ M1M1 | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever you put one or more -1/-1 counters on a creature, create that many 1/1 black Insect creature tokens. SVar:TrigToken:DB$ Token | TokenAmount$ X | References$ X | TokenName$ Insect | TokenTypes$ Creature,Insect | TokenOwner$ You | TokenColors$ Black | TokenPower$ 1 | TokenToughness$ 1 | TokenImage$ b 1 1 insect AKH SVar:X:TriggerCount$Amount DeckHints:Ability$Counters diff --git a/forge-gui/res/cardsfolder/o/obelisk_spider.txt b/forge-gui/res/cardsfolder/o/obelisk_spider.txt index 89b2df21f08..6d67d82d05c 100644 --- a/forge-gui/res/cardsfolder/o/obelisk_spider.txt +++ b/forge-gui/res/cardsfolder/o/obelisk_spider.txt @@ -5,7 +5,7 @@ PT:1/4 K:Reach T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Creature | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME deals combat damage to a creature, put a -1/-1 counter on that creature. SVar:TrigPutCounter:DB$PutCounter | Defined$ TriggeredTargetLKICopy | CounterType$ M1M1 | CounterNum$ 1 -T:Mode$ CounterAddedOnce | ValidCard$ Creature | ValidSource$ Card.YouCtrl | CounterType$ M1M1 | TriggerZones$ Battlefield | Execute$ TrigDrain | TriggerDescription$ Whenever you put one or more -1/-1 counters on a creature, each opponent loses 1 life and you gain 1 life. +T:Mode$ CounterAddedOnce | ValidCard$ Creature | ValidSource$ You | CounterType$ M1M1 | TriggerZones$ Battlefield | Execute$ TrigDrain | TriggerDescription$ Whenever you put one or more -1/-1 counters on a creature, each opponent loses 1 life and you gain 1 life. SVar:TrigDrain:DB$ LoseLife | Defined$ Player.Opponent | LifeAmount$ 1 | SubAbility$ DBGainLife SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1 DeckHas:Ability$Counters diff --git a/forge-gui/src/main/java/forge/player/HumanPlay.java b/forge-gui/src/main/java/forge/player/HumanPlay.java index 21f04529811..fd96df17d56 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/player/HumanPlay.java @@ -438,7 +438,7 @@ public class HumanPlay { return false; } - source.addCounter(counterType, amount, source, false); + source.addCounter(counterType, amount, p, false); } else { CardCollectionView list = p.getGame().getCardsIn(ZoneType.Battlefield); @@ -456,7 +456,7 @@ public class HumanPlay { continue; } Card selected = inp.getFirstSelected(); - selected.addCounter(counterType, 1, source, false); + selected.addCounter(counterType, 1, p, false); amount--; } } diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index ea704cbf6ba..d33e1ecc56d 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -2085,7 +2085,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont if (subtract) { card.subtractCounter(counter, count); } else { - card.addCounter(counter, count, card, false); + card.addCounter(counter, count, card.getController(), false); } } From f1907012f77a8c2ed5c5dec9432e7522735aba0e Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sun, 3 Jun 2018 19:01:28 +0200 Subject: [PATCH 09/20] fixed manacost --- forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt b/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt index 9c09dd67293..733ca7ffed2 100644 --- a/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt +++ b/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt @@ -1,7 +1,7 @@ Name:Zndrsplt's Judgment ManaCost:4 U Types:Sorcery -A:SP$ AssignGroup | Cost$ 3 G | Defined$ Player | Choices$ FriendRepeat,FoeRepeat | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend creates a token that's a copy of a creature they control. Each foe returns a creature they control to its owner's hand. +A:SP$ AssignGroup | Cost$ 4 U | Defined$ Player | Choices$ FriendRepeat,FoeRepeat | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend creates a token that's a copy of a creature they control. Each foe returns a creature they control to its owner's hand. SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ DBClone | StackDescription$ Each friend creates a token that's a copy of a creature they control. | SpellDescription$ Friend creates a token that's a copy of a creature they control. SVar:DBClone:DB$ CopyPermanent | Choices$ Creature.RememberedPlayerCtrl | Chooser$ Remembered | Controller$ Remembered SVar:FoeRepeat:DB$ RepeatEach | Cost$ U | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | SubAbility$ BounceAll | StackDescription$ Each foe returns a creature they control to its owner's hand. | SpellDescription$ Foe returns a creature they control to its owner's hand. From 1ac0eb83cfae3e3b88af6eaf443d6442600b2c88 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sun, 3 Jun 2018 20:45:34 +0200 Subject: [PATCH 10/20] cards: fixed zndrsplt judgment, add regna sanction --- .../res/cardsfolder/upcoming/regna_sanction.txt | 15 +++++++++++++++ .../cardsfolder/upcoming/zndrsplt_judgment.txt | 7 ++++--- 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/regna_sanction.txt diff --git a/forge-gui/res/cardsfolder/upcoming/regna_sanction.txt b/forge-gui/res/cardsfolder/upcoming/regna_sanction.txt new file mode 100644 index 00000000000..ff123091bbf --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/regna_sanction.txt @@ -0,0 +1,15 @@ +Name:Regna's Sanction +ManaCost:3 W +Types:Sorcery +A:SP$ AssignGroup | Cost$ 3 W | Defined$ Player | Choices$ FriendRepeat,FoeRepeat | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend puts a +1/+1 counter on each creature they control. Each foe chooses one untapped creature they control, then taps the rest. +SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ DBPutCounter | ClearRememberedBeforeLoop$ True | StackDescription$ Each friend puts a +1/+1 counter on each creature they control. | SpellDescription$ Friend puts a +1/+1 counter on each creature they control. +SVar:DBPutCounter:DB$ PutCounterAll | ValidCards$ Creature.RememberedPlayerCtrl | CounterType$ P1P1 | CounterNum$ 1 | Putter$ Remembered +SVar:FoeRepeat:DB$ RepeatEach | AILogic$ OpponentHasMultipleCreatures | RepeatPlayers$ Remembered | ClearRememberedBeforeLoop$ True | RepeatSubAbility$ DBChoose | SubAbility$ DBTapAll | StackDescription$ Each foe chooses one untapped creature they control, then taps the rest. | SpellDescription$ Foe chooses one untapped creature they control, then taps the rest. +SVar:DBChoose:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Creature.untapped+RememberedPlayerCtrl | Mandatory$ True | RememberChosen$ True | SubAbility$ DBImprint +#Need to imprint all non remembered cards +SVar:DBImprint:DB$ Pump | ImprintCards$ Valid Creature.IsNotRemembered+RememberedPlayerCtrl +SVar:DBTapAll:DB$ TapAll | ValidCards$ Creature.IsImprinted | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/regna_sanction.jpg +Oracle:For each player, choose friend or foe. Each friend puts a +1/+1 counter on each creature they control. Each foe chooses one untapped creature they control, then taps the rest. diff --git a/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt b/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt index 733ca7ffed2..3be51d7a6cf 100644 --- a/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt +++ b/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt @@ -2,11 +2,12 @@ Name:Zndrsplt's Judgment ManaCost:4 U Types:Sorcery A:SP$ AssignGroup | Cost$ 4 U | Defined$ Player | Choices$ FriendRepeat,FoeRepeat | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend creates a token that's a copy of a creature they control. Each foe returns a creature they control to its owner's hand. -SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ DBClone | StackDescription$ Each friend creates a token that's a copy of a creature they control. | SpellDescription$ Friend creates a token that's a copy of a creature they control. +SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ DBClone | ClearRememberedBeforeLoop$ True | StackDescription$ Each friend creates a token that's a copy of a creature they control. | SpellDescription$ Friend creates a token that's a copy of a creature they control. SVar:DBClone:DB$ CopyPermanent | Choices$ Creature.RememberedPlayerCtrl | Chooser$ Remembered | Controller$ Remembered -SVar:FoeRepeat:DB$ RepeatEach | Cost$ U | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | SubAbility$ BounceAll | StackDescription$ Each foe returns a creature they control to its owner's hand. | SpellDescription$ Foe returns a creature they control to its owner's hand. +SVar:FoeRepeat:DB$ RepeatEach | Cost$ U | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | ClearRememberedBeforeLoop$ True | SubAbility$ BounceAll | StackDescription$ Each foe returns a creature they control to its owner's hand. | SpellDescription$ Foe returns a creature they control to its owner's hand. SVar:PlayChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl | Amount$ 1 | Mandatory$ True | AILogic$ WorstCard | ChoiceTitle$ Choose a creature you control | RememberChosen$ True -SVar:BounceAll:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Hand | ChangeType$ Creature.IsRemembered +SVar:BounceAll:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Hand | ChangeType$ Creature.IsRemembered | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True SVar:RemAIDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/zndrsplt_judgment.jpg Oracle:For each player, choose friend or foe. Each friend creates a token that's a copy of a creature they control. Each foe returns a creature they control to its owner's hand. From eaa5078521626afb33f49a1c6d57aea96457b854 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sun, 3 Jun 2018 22:01:56 +0200 Subject: [PATCH 11/20] CountersPut: use Placer --- .../ability/effects/CountersPutAllEffect.java | 12 +++++----- .../ability/effects/CountersPutEffect.java | 22 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) 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 89999962a72..cf27b138ff8 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 @@ -57,18 +57,18 @@ public class CountersPutAllEffect extends SpellAbilityEffect { cards = CardLists.filterControlledBy(cards, pl); } - Player putter = activator; - if (sa.hasParam("Putter")) { - final String pstr = sa.getParam("Putter"); - putter = AbilityUtils.getDefinedPlayers(host, pstr, sa).get(0); + Player placer = activator; + if (sa.hasParam("Placer")) { + final String pstr = sa.getParam("Placer"); + placer = AbilityUtils.getDefinedPlayers(host, pstr, sa).get(0); } for (final Card tgtCard : cards) { if (game.getZoneOf(tgtCard).is(ZoneType.Battlefield)) { - tgtCard.addCounter(CounterType.valueOf(type), counterAmount, putter, true); + tgtCard.addCounter(CounterType.valueOf(type), counterAmount, placer, true); } else { // adding counters to something like re-suspend cards - tgtCard.addCounter(CounterType.valueOf(type), counterAmount, putter, false); + tgtCard.addCounter(CounterType.valueOf(type), counterAmount, placer, false); } game.updateLastStateForCard(tgtCard); } 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 99d065efc14..5d73ca81e51 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 @@ -110,10 +110,10 @@ public class CountersPutEffect extends SpellAbilityEffect { } } - Player putter = activator; - if (sa.hasParam("Putter")) { - final String pstr = sa.getParam("Putter"); - putter = AbilityUtils.getDefinedPlayers(sa.getHostCard(), pstr, sa).get(0); + 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"); @@ -161,10 +161,10 @@ public class CountersPutEffect extends SpellAbilityEffect { if (eachExistingCounter) { for(CounterType ct : choices) { if (obj instanceof Player) { - ((Player) obj).addCounter(ct, counterAmount, putter, true); + ((Player) obj).addCounter(ct, counterAmount, placer, true); } if (obj instanceof Card) { - ((Card) obj).addCounter(ct, counterAmount, putter, true); + ((Card) obj).addCounter(ct, counterAmount, placer, true); } } continue; @@ -238,9 +238,9 @@ public class CountersPutEffect extends SpellAbilityEffect { final Zone zone = tgtCard.getGame().getZoneOf(tgtCard); if (zone == null || zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Stack)) { if (etbcounter) { - tgtCard.addEtbCounter(counterType, counterAmount, putter); + tgtCard.addEtbCounter(counterType, counterAmount, placer); } else { - tgtCard.addCounter(counterType, counterAmount, putter, true); + tgtCard.addCounter(counterType, counterAmount, placer, true); } if (remember) { final int value = tgtCard.getTotalCountersToAdd(); @@ -269,9 +269,9 @@ public class CountersPutEffect extends SpellAbilityEffect { // adding counters to something like re-suspend cards // etbcounter should apply multiplier if (etbcounter) { - tgtCard.addEtbCounter(counterType, counterAmount, putter); + tgtCard.addEtbCounter(counterType, counterAmount, placer); } else { - tgtCard.addCounter(counterType, counterAmount, putter, false); + tgtCard.addCounter(counterType, counterAmount, placer, false); } } game.updateLastStateForCard(tgtCard); @@ -279,7 +279,7 @@ public class CountersPutEffect extends SpellAbilityEffect { } else if (obj instanceof Player) { // Add Counters to players! Player pl = (Player) obj; - pl.addCounter(counterType, counterAmount, putter, true); + pl.addCounter(counterType, counterAmount, placer, true); } } } From d5b96c005147d8a197b95e59957c53476a6673ae Mon Sep 17 00:00:00 2001 From: Hanmac Date: Sun, 3 Jun 2018 22:02:54 +0200 Subject: [PATCH 12/20] cards: updated regna sanction --- forge-gui/res/cardsfolder/upcoming/regna_sanction.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/forge-gui/res/cardsfolder/upcoming/regna_sanction.txt b/forge-gui/res/cardsfolder/upcoming/regna_sanction.txt index ff123091bbf..931bb46c8d0 100644 --- a/forge-gui/res/cardsfolder/upcoming/regna_sanction.txt +++ b/forge-gui/res/cardsfolder/upcoming/regna_sanction.txt @@ -3,13 +3,14 @@ ManaCost:3 W Types:Sorcery A:SP$ AssignGroup | Cost$ 3 W | Defined$ Player | Choices$ FriendRepeat,FoeRepeat | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend puts a +1/+1 counter on each creature they control. Each foe chooses one untapped creature they control, then taps the rest. SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ DBPutCounter | ClearRememberedBeforeLoop$ True | StackDescription$ Each friend puts a +1/+1 counter on each creature they control. | SpellDescription$ Friend puts a +1/+1 counter on each creature they control. -SVar:DBPutCounter:DB$ PutCounterAll | ValidCards$ Creature.RememberedPlayerCtrl | CounterType$ P1P1 | CounterNum$ 1 | Putter$ Remembered +SVar:DBPutCounter:DB$ PutCounterAll | ValidCards$ Creature.RememberedPlayerCtrl | CounterType$ P1P1 | CounterNum$ 1 | Placer$ Remembered SVar:FoeRepeat:DB$ RepeatEach | AILogic$ OpponentHasMultipleCreatures | RepeatPlayers$ Remembered | ClearRememberedBeforeLoop$ True | RepeatSubAbility$ DBChoose | SubAbility$ DBTapAll | StackDescription$ Each foe chooses one untapped creature they control, then taps the rest. | SpellDescription$ Foe chooses one untapped creature they control, then taps the rest. SVar:DBChoose:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Creature.untapped+RememberedPlayerCtrl | Mandatory$ True | RememberChosen$ True | SubAbility$ DBImprint #Need to imprint all non remembered cards -SVar:DBImprint:DB$ Pump | ImprintCards$ Valid Creature.IsNotRemembered+RememberedPlayerCtrl -SVar:DBTapAll:DB$ TapAll | ValidCards$ Creature.IsImprinted | SubAbility$ DBCleanup +SVar:DBImprint:DB$ Pump | ImprintCards$ Valid Creature.IsNotRemembered+RememberedPlayerCtrl | SubAbility$ DBCleanupAll SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True +SVar:DBTapAll:DB$ TapAll | ValidCards$ Creature.IsImprinted | SubAbility$ DBCleanupAll +SVar:DBCleanupAll:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True | ClearChosenCard$ True SVar:RemAIDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/regna_sanction.jpg Oracle:For each player, choose friend or foe. Each friend puts a +1/+1 counter on each creature they control. Each foe chooses one untapped creature they control, then taps the rest. From b43a313793f194e7f07d0b0f3fa45ec5fe910777 Mon Sep 17 00:00:00 2001 From: Agetian Date: Mon, 4 Jun 2018 07:35:47 +0300 Subject: [PATCH 13/20] - Renamed two cards to match the current standard. - Implemented basic AI playability of AssignGroup (Friend/Foe) cards based on NeedsToPlayVar. - Will need separate AI logic for different cases to improve further (can be tested in canPlayAI). --- forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java | 7 +++++-- forge-gui/res/cardsfolder/upcoming/pirs_whim.txt | 6 ++++++ .../upcoming/{regna_sanction.txt => regnas_sanction.txt} | 5 ++++- .../{zndrsplt_judgment.txt => zndrsplts_judgment.txt} | 5 ++++- 4 files changed, 19 insertions(+), 4 deletions(-) rename forge-gui/res/cardsfolder/upcoming/{regna_sanction.txt => regnas_sanction.txt} (91%) rename forge-gui/res/cardsfolder/upcoming/{zndrsplt_judgment.txt => zndrsplts_judgment.txt} (91%) diff --git a/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java b/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java index fb1b769347d..691a21904ce 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AssignGroupAi.java @@ -11,8 +11,11 @@ import forge.game.spellability.SpellAbility; public class AssignGroupAi extends SpellAbilityAi { - public AssignGroupAi() { - // TODO Auto-generated constructor stub + protected boolean canPlayAI(Player ai, SpellAbility sa) { + // TODO: Currently this AI relies on the card-specific limiting hints (NeedsToPlay / NeedsToPlayVar), + // otherwise the AI considers the card playable. + + return true; } public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List spells, Map params) { diff --git a/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt b/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt index dafdee4b0e7..fcaceefbbc0 100644 --- a/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt +++ b/forge-gui/res/cardsfolder/upcoming/pirs_whim.txt @@ -4,5 +4,11 @@ Types:Sorcery A:SP$ AssignGroup | Cost$ 3 G | Defined$ Player | Choices$ DBSearch,DBSacrifice | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. Each foe sacrifices an artifact or enchantment they control. SVar:DBSearch:DB$ChangeZone | Origin$ Library | Destination$ Battlefield | DefinedPlayer$ Remembered | ChangeType$ Land | ChangeNum$ 1 | StackDescription$ Each friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. | SpellDescription$ Friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. SVar:DBSacrifice:DB$Sacrifice | Defined$ Remembered | SacValid$ Artifact,Enchantment | SacMessage$ artifact or enchantment | StackDescription$ Each foe sacrifices an artifact or enchantment they control. | SpellDescription$ Foe sacrifices an artifact or enchantment they control. +SVar:NeedsToPlayVar:Z GE1 +SVar:Z:SVar$Z1/Plus.C1 +SVar:Z1:SVar$C2/Plus.C3 +SVar:C1:Count$Valid Land.YourTeamCtrl+inZoneLibrary +SVar:C2:Count$Valid Enchantment.OppCtrl+inZoneBattlefield +SVar:C3:Count$Valid Artifact.OppCtrl+inZoneBattlefield SVar:Picture:http://www.wizards.com/global/images/magic/general/pirs_whim.jpg Oracle:For each player, choose friend or foe. Each friend searches their library for a land card, puts it onto the battlefield tapped, then shuffles their library. Each foe sacrifices an artifact or enchantment they control. diff --git a/forge-gui/res/cardsfolder/upcoming/regna_sanction.txt b/forge-gui/res/cardsfolder/upcoming/regnas_sanction.txt similarity index 91% rename from forge-gui/res/cardsfolder/upcoming/regna_sanction.txt rename to forge-gui/res/cardsfolder/upcoming/regnas_sanction.txt index ff123091bbf..58f6ce08095 100644 --- a/forge-gui/res/cardsfolder/upcoming/regna_sanction.txt +++ b/forge-gui/res/cardsfolder/upcoming/regnas_sanction.txt @@ -10,6 +10,9 @@ SVar:DBChoose:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Creatu SVar:DBImprint:DB$ Pump | ImprintCards$ Valid Creature.IsNotRemembered+RememberedPlayerCtrl SVar:DBTapAll:DB$ TapAll | ValidCards$ Creature.IsImprinted | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True -SVar:RemAIDeck:True +SVar:NeedsToPlayVar:Z GE3 +SVar:Z:SVar$Z1/Plus.Z2 +SVar:Z1:Count$Valid Creature.YourTeamCtrl+inZoneBattlefield +SVar:Z2:Count$Valid Creature.OppCtrl+inZoneBattlefield+untapped SVar:Picture:http://www.wizards.com/global/images/magic/general/regna_sanction.jpg Oracle:For each player, choose friend or foe. Each friend puts a +1/+1 counter on each creature they control. Each foe chooses one untapped creature they control, then taps the rest. diff --git a/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt b/forge-gui/res/cardsfolder/upcoming/zndrsplts_judgment.txt similarity index 91% rename from forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt rename to forge-gui/res/cardsfolder/upcoming/zndrsplts_judgment.txt index 3be51d7a6cf..2187cd86827 100644 --- a/forge-gui/res/cardsfolder/upcoming/zndrsplt_judgment.txt +++ b/forge-gui/res/cardsfolder/upcoming/zndrsplts_judgment.txt @@ -8,6 +8,9 @@ SVar:FoeRepeat:DB$ RepeatEach | Cost$ U | RepeatPlayers$ Remembered | RepeatSubA SVar:PlayChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl | Amount$ 1 | Mandatory$ True | AILogic$ WorstCard | ChoiceTitle$ Choose a creature you control | RememberChosen$ True SVar:BounceAll:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Hand | ChangeType$ Creature.IsRemembered | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True -SVar:RemAIDeck:True +SVar:NeedsToPlayVar:Z GE2 +SVar:Z:SVar$Z1/Plus.Z2 +SVar:Z1:Count$Valid Creature.YourTeamCtrl+inZoneBattlefield +SVar:Z2:Count$Valid Creature.OppCtrl+inZoneBattlefield SVar:Picture:http://www.wizards.com/global/images/magic/general/zndrsplt_judgment.jpg Oracle:For each player, choose friend or foe. Each friend creates a token that's a copy of a creature they control. Each foe returns a creature they control to its owner's hand. From 97cd2130b4a6eaed5b8b7669ccfe67b147d8330d Mon Sep 17 00:00:00 2001 From: Hanmac Date: Thu, 7 Jun 2018 07:34:24 +0200 Subject: [PATCH 14/20] cards: add Khorvath's Fury --- .../res/cardsfolder/upcoming/khorvaths_fury.txt | 14 ++++++++++++++ .../cardsfolder/upcoming/zndrsplts_judgment.txt | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/khorvaths_fury.txt diff --git a/forge-gui/res/cardsfolder/upcoming/khorvaths_fury.txt b/forge-gui/res/cardsfolder/upcoming/khorvaths_fury.txt new file mode 100644 index 00000000000..cc877528536 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/khorvaths_fury.txt @@ -0,0 +1,14 @@ +Name:Khorvath's Fury +ManaCost:4 R +Types:Sorcery +A:SP$ AssignGroup | Cost$ 4 R | Defined$ Player | Choices$ FriendRepeat,FoeRepeat | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend discards all cards from their hand, then draws that many cards plus one. CARDNAME deals damage to each foe equal to the number of cards in their hand. +SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | ClearRememberedBeforeLoop$ True | RepeatSubAbility$ DBDiscard | StackDescription$ SpellDescription | SpellDescription$ Each friend discards all cards from their hand, then draws that many cards plus one. +SVar:DBDiscard:DB$ Discard | Defined$ Player.IsRemembered | Mode$ Hand | RememberDiscarded$ True | SubAbility$ DBDraw +SVar:DBDraw:DB$ Draw | NumCards$ X | Defined$ Player.IsRemembered | References$ X | SubAbility$ DBCleanup +SVar:FoeRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | ClearRememberedBeforeLoop$ True | RepeatSubAbility$ DBDmg | DamageMap$ True | StackDescription$ SpellDescription | SpellDescription$ CARDNAME deals damage to each foe equal to the number of cards in their hand. +SVar:DBDmg:DB$ DealDamage | Defined$ Player.IsRemembered | NumDmg$ Y | References$ Y +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Remembered$Amount.Plus.1 +SVar:Y:Count$ValidHand Card.RememberedPlayerCtrl +SVar:Picture:http://www.wizards.com/global/images/magic/general/khorvaths_fury.jpg +Oracle:For each player, choose friend or foe. Each friend discards all cards from their hand, then draws that many cards plus one. Khorvath's Fury deals damage to each foe equal to the number of cards in their hand. diff --git a/forge-gui/res/cardsfolder/upcoming/zndrsplts_judgment.txt b/forge-gui/res/cardsfolder/upcoming/zndrsplts_judgment.txt index 2187cd86827..ef57e37a24d 100644 --- a/forge-gui/res/cardsfolder/upcoming/zndrsplts_judgment.txt +++ b/forge-gui/res/cardsfolder/upcoming/zndrsplts_judgment.txt @@ -4,7 +4,7 @@ Types:Sorcery A:SP$ AssignGroup | Cost$ 4 U | Defined$ Player | Choices$ FriendRepeat,FoeRepeat | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend creates a token that's a copy of a creature they control. Each foe returns a creature they control to its owner's hand. SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ DBClone | ClearRememberedBeforeLoop$ True | StackDescription$ Each friend creates a token that's a copy of a creature they control. | SpellDescription$ Friend creates a token that's a copy of a creature they control. SVar:DBClone:DB$ CopyPermanent | Choices$ Creature.RememberedPlayerCtrl | Chooser$ Remembered | Controller$ Remembered -SVar:FoeRepeat:DB$ RepeatEach | Cost$ U | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | ClearRememberedBeforeLoop$ True | SubAbility$ BounceAll | StackDescription$ Each foe returns a creature they control to its owner's hand. | SpellDescription$ Foe returns a creature they control to its owner's hand. +SVar:FoeRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | ClearRememberedBeforeLoop$ True | SubAbility$ BounceAll | StackDescription$ Each foe returns a creature they control to its owner's hand. | SpellDescription$ Foe returns a creature they control to its owner's hand. SVar:PlayChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl | Amount$ 1 | Mandatory$ True | AILogic$ WorstCard | ChoiceTitle$ Choose a creature you control | RememberChosen$ True SVar:BounceAll:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Hand | ChangeType$ Creature.IsRemembered | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True From c54d24a362afc337e80f58a704c2a7039492786a Mon Sep 17 00:00:00 2001 From: Agetian Date: Fri, 8 Jun 2018 07:18:49 +0300 Subject: [PATCH 15/20] - Simple limiting SVar for Khovrath's Fury AI until a better logic can be devised. - Ideally should at least account for the fact that it should not overdraw cards and deck itself. --- forge-gui/res/cardsfolder/upcoming/khorvaths_fury.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/forge-gui/res/cardsfolder/upcoming/khorvaths_fury.txt b/forge-gui/res/cardsfolder/upcoming/khorvaths_fury.txt index cc877528536..88a9bcf369f 100644 --- a/forge-gui/res/cardsfolder/upcoming/khorvaths_fury.txt +++ b/forge-gui/res/cardsfolder/upcoming/khorvaths_fury.txt @@ -10,5 +10,7 @@ SVar:DBDmg:DB$ DealDamage | Defined$ Player.IsRemembered | NumDmg$ Y | Reference SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Remembered$Amount.Plus.1 SVar:Y:Count$ValidHand Card.RememberedPlayerCtrl +SVar:NeedsToPlayVar:Z GE4 +SVar:Z:Count$ValidHand Card.OppCtrl SVar:Picture:http://www.wizards.com/global/images/magic/general/khorvaths_fury.jpg Oracle:For each player, choose friend or foe. Each friend discards all cards from their hand, then draws that many cards plus one. Khorvath's Fury deals damage to each foe equal to the number of cards in their hand. From d851a4fc8d087b45616328232a92fea49c121129 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Fri, 8 Jun 2018 06:51:33 +0200 Subject: [PATCH 16/20] cards: add Virtus's Maneuver --- .../res/cardsfolder/upcoming/virtuss_maneuver.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt diff --git a/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt b/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt new file mode 100644 index 00000000000..502969493dd --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt @@ -0,0 +1,11 @@ +Name:Virtus's Maneuver +ManaCost:2 B +Types:Sorcery +A:SP$ AssignGroup | Cost$ 2 B | Defined$ Player | Choices$ FriendRepeat,DBSacrifice | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend returns a creature card from their graveyard to their hand. Each foe sacrifices a creature they control. +SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | ClearRememberedBeforeLoop$ True | SubAbility$ BounceAll | StackDescription$ SpellDescription | SpellDescription$ Each friend returns a creature card from their graveyard to their hand. +SVar:PlayChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl | Amount$ 1 | Mandatory$ True | ChoiceZone$ Graveyard | ChoiceTitle$ Choose a creature in your graveyard | RememberChosen$ True +SVar:ReturnAll:DB$ ChangeZoneAll | Origin$ Graveyard | Destination$ Hand | ChangeType$ Creature.IsRemembered | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True +SVar:DBSacrifice:DB$Sacrifice | Defined$ Remembered | SacValid$ Creature | SacMessage$ creature | StackDescription$ SpellDescription | SpellDescription$ Each foe sacrifices a creature they control. +SVar:Picture:http://www.wizards.com/global/images/magic/general/virtuss_maneuver.jpg +Oracle:For each player, choose friend or foe. Each friend returns a creature card from their graveyard to their hand. Each foe sacrifices a creature they control. From 2f02b03d6a6de80665ffa13abcddca3112fd6d66 Mon Sep 17 00:00:00 2001 From: Hanmac Date: Fri, 8 Jun 2018 06:55:00 +0200 Subject: [PATCH 17/20] Generous Patron: you need to be the Source of the counter for this effect to trigger --- forge-gui/res/cardsfolder/upcoming/generous_patron.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/upcoming/generous_patron.txt b/forge-gui/res/cardsfolder/upcoming/generous_patron.txt index 2dba1257878..521fbf9e2c3 100644 --- a/forge-gui/res/cardsfolder/upcoming/generous_patron.txt +++ b/forge-gui/res/cardsfolder/upcoming/generous_patron.txt @@ -4,7 +4,7 @@ Types:Creature Elf Advisor PT:1/4 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPut | TriggerDescription$ When CARDNAME enters the battlefield, support 2. (Put a +1/+1 counter on each of up to two other target creatures.) SVar:TrigPut:DB$PutCounter | ValidTgts$ Creature.Other | TgtPrompt$ Select target creature other than CARDNAME | TargetMin$ 0 | TargetMax$ 2 | CounterType$ P1P1 | CounterNum$ 1 -T:Mode$ CounterAddedOnce | ValidCard$ Creature.YouDontCtrl | TriggerZones$ Battlefield | CounterType$ P1P1 | Execute$ DBDraw | TriggerDescription$ Whenever you put one or more counters on a creature you don't control, draw a card. +T:Mode$ CounterAddedOnce | ValidCard$ Creature.YouDontCtrl | ValidSource$ You | TriggerZones$ Battlefield | CounterType$ P1P1 | Execute$ DBDraw | TriggerDescription$ Whenever you put one or more counters on a creature you don't control, draw a card. SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 1 DeckHas:Ability$Counters DeckHints:Ability$Counters From a2223fc6f99acab72b9b5a7c061ce2c1a7e50180 Mon Sep 17 00:00:00 2001 From: Agetian Date: Fri, 8 Jun 2018 10:00:36 +0300 Subject: [PATCH 18/20] - Fixed Virtus's Maneuver "friend" ability. - Added a simple AI limiting NeedsToPlay svar. --- forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt b/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt index 502969493dd..790870a9e37 100644 --- a/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt +++ b/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt @@ -3,9 +3,13 @@ ManaCost:2 B Types:Sorcery A:SP$ AssignGroup | Cost$ 2 B | Defined$ Player | Choices$ FriendRepeat,DBSacrifice | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend returns a creature card from their graveyard to their hand. Each foe sacrifices a creature they control. SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | ClearRememberedBeforeLoop$ True | SubAbility$ BounceAll | StackDescription$ SpellDescription | SpellDescription$ Each friend returns a creature card from their graveyard to their hand. -SVar:PlayChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl | Amount$ 1 | Mandatory$ True | ChoiceZone$ Graveyard | ChoiceTitle$ Choose a creature in your graveyard | RememberChosen$ True +SVar:PlayChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl | Amount$ 1 | Mandatory$ True | ChoiceZone$ Graveyard | ChoiceTitle$ Choose a creature in your graveyard | RememberChosen$ True | SubAbility$ ReturnAll SVar:ReturnAll:DB$ ChangeZoneAll | Origin$ Graveyard | Destination$ Hand | ChangeType$ Creature.IsRemembered | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True SVar:DBSacrifice:DB$Sacrifice | Defined$ Remembered | SacValid$ Creature | SacMessage$ creature | StackDescription$ SpellDescription | SpellDescription$ Each foe sacrifices a creature they control. +SVar:NeedsToPlayVar:Z GE2 +SVar:Z:SVar$Z1/Plus.Z2 +SVar:Z1:Count$ValidGraveyard Creature.YourTeamCtrl +SVar:Z2:Count$Valid Creature.OppCtrl+inZoneBattlefield SVar:Picture:http://www.wizards.com/global/images/magic/general/virtuss_maneuver.jpg Oracle:For each player, choose friend or foe. Each friend returns a creature card from their graveyard to their hand. Each foe sacrifices a creature they control. From 653329be095c34c3fd839daaa93f151b9505e7ab Mon Sep 17 00:00:00 2001 From: Agetian Date: Fri, 8 Jun 2018 10:09:29 +0300 Subject: [PATCH 19/20] - Fixed Virtus's Maneuver (take two) --- forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt b/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt index 790870a9e37..aae76276af4 100644 --- a/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt +++ b/forge-gui/res/cardsfolder/upcoming/virtuss_maneuver.txt @@ -2,8 +2,8 @@ Name:Virtus's Maneuver ManaCost:2 B Types:Sorcery A:SP$ AssignGroup | Cost$ 2 B | Defined$ Player | Choices$ FriendRepeat,DBSacrifice | AILogic$ FriendOrFoe | SpellDescription$ For each player, choose friend or foe. Each friend returns a creature card from their graveyard to their hand. Each foe sacrifices a creature they control. -SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | ClearRememberedBeforeLoop$ True | SubAbility$ BounceAll | StackDescription$ SpellDescription | SpellDescription$ Each friend returns a creature card from their graveyard to their hand. -SVar:PlayChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl | Amount$ 1 | Mandatory$ True | ChoiceZone$ Graveyard | ChoiceTitle$ Choose a creature in your graveyard | RememberChosen$ True | SubAbility$ ReturnAll +SVar:FriendRepeat:DB$ RepeatEach | RepeatPlayers$ Remembered | RepeatSubAbility$ PlayChoose | ClearRememberedBeforeLoop$ True | SubAbility$ ReturnAll | StackDescription$ SpellDescription | SpellDescription$ Each friend returns a creature card from their graveyard to their hand. +SVar:PlayChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl | Amount$ 1 | Mandatory$ True | ChoiceZone$ Graveyard | ChoiceTitle$ Choose a creature in your graveyard | RememberChosen$ True SVar:ReturnAll:DB$ ChangeZoneAll | Origin$ Graveyard | Destination$ Hand | ChangeType$ Creature.IsRemembered | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True SVar:DBSacrifice:DB$Sacrifice | Defined$ Remembered | SacValid$ Creature | SacMessage$ creature | StackDescription$ SpellDescription | SpellDescription$ Each foe sacrifices a creature they control. From 939e461c081849c8ce4e171d685435b12f9221e5 Mon Sep 17 00:00:00 2001 From: Agetian Date: Fri, 8 Jun 2018 10:47:32 +0300 Subject: [PATCH 20/20] - Fixed Regna's Sanction. --- forge-gui/res/cardsfolder/upcoming/regnas_sanction.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/upcoming/regnas_sanction.txt b/forge-gui/res/cardsfolder/upcoming/regnas_sanction.txt index ec67f71854b..12f421c3171 100644 --- a/forge-gui/res/cardsfolder/upcoming/regnas_sanction.txt +++ b/forge-gui/res/cardsfolder/upcoming/regnas_sanction.txt @@ -7,7 +7,7 @@ SVar:DBPutCounter:DB$ PutCounterAll | ValidCards$ Creature.RememberedPlayerCtrl SVar:FoeRepeat:DB$ RepeatEach | AILogic$ OpponentHasMultipleCreatures | RepeatPlayers$ Remembered | ClearRememberedBeforeLoop$ True | RepeatSubAbility$ DBChoose | SubAbility$ DBTapAll | StackDescription$ Each foe chooses one untapped creature they control, then taps the rest. | SpellDescription$ Foe chooses one untapped creature they control, then taps the rest. SVar:DBChoose:DB$ ChooseCard | Defined$ Remembered | Amount$ 1 | Choices$ Creature.untapped+RememberedPlayerCtrl | Mandatory$ True | RememberChosen$ True | SubAbility$ DBImprint #Need to imprint all non remembered cards -SVar:DBImprint:DB$ Pump | ImprintCards$ Valid Creature.IsNotRemembered+RememberedPlayerCtrl | SubAbility$ DBCleanupAll +SVar:DBImprint:DB$ Pump | ImprintCards$ Valid Creature.IsNotRemembered+RememberedPlayerCtrl | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True SVar:DBTapAll:DB$ TapAll | ValidCards$ Creature.IsImprinted | SubAbility$ DBCleanupAll SVar:DBCleanupAll:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True | ClearChosenCard$ True