diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 3645edf1e1d..08791bf1750 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -2141,7 +2141,7 @@ public class AiController { } private List filterListByAiLogic(List list, final String logic) { - return filterList(list, CardTraitPredicates.hasParam("AiLogic", logic)); + return filterList(list, CardTraitPredicates.hasParam("AILogic", logic)); } public List chooseModeForAbility(SpellAbility sa, List possible, int min, int num, boolean allowRepeat) { diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index bf76807cf24..3972fa472bc 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -3007,11 +3007,11 @@ public class ComputerUtil { repParams, ReplacementLayer.Other); - if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "NoLife"))) { + if (Iterables.any(list, CardTraitPredicates.hasParam("AILogic", "NoLife"))) { return false; - } else if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "LoseLife"))) { + } else if (Iterables.any(list, CardTraitPredicates.hasParam("AILogic", "LoseLife"))) { return false; - } else if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "LichDraw"))) { + } else if (Iterables.any(list, CardTraitPredicates.hasParam("AILogic", "LichDraw"))) { return false; } return true; @@ -3036,13 +3036,13 @@ public class ComputerUtil { ReplacementLayer.Other ); - if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "NoLife"))) { + if (Iterables.any(list, CardTraitPredicates.hasParam("AILogic", "NoLife"))) { // no life gain is not negative return false; - } else if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "LoseLife"))) { + } else if (Iterables.any(list, CardTraitPredicates.hasParam("AILogic", "LoseLife"))) { // lose life is only negative is the player can lose life return player.canLoseLife(); - } else if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "LichDraw"))) { + } else if (Iterables.any(list, CardTraitPredicates.hasParam("AILogic", "LichDraw"))) { // if it would draw more cards than player has, then its negative return player.getCardsIn(ZoneType.Library).size() <= n; } diff --git a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java index 931baf986f7..df93a804d00 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java @@ -1,10 +1,12 @@ package forge.ai.ability; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import forge.ai.*; import forge.card.CardType; import forge.card.ColorSet; +import forge.game.CardTraitPredicates; import forge.game.Game; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; @@ -20,6 +22,7 @@ import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbilityContinuous; import forge.game.staticability.StaticAbilityLayer; import forge.game.zone.ZoneType; +import forge.util.FileSection; import java.util.Arrays; import java.util.List; @@ -54,6 +57,23 @@ public class AnimateAi extends SpellAbilityAi { if ("EOT".equals(aiLogic) && ph.getPhase().isBefore(PhaseType.MAIN2)) { return false; } + if ("BoneManCantRegenerate".equals(aiLogic)) { + Card host = sa.getHostCard(); + String svar = AbilityUtils.getSVar(sa, sa.getParam("staticAbilities")); + if (svar == null) { + return false; + } + Map map = FileSection.parseToMap(svar, FileSection.DOLLAR_SIGN_KV_SEPARATOR); + if (!map.containsKey("Description")) { + return false; + } + + // check for duplicate static ability + if (Iterables.any(host.getStaticAbilities(), CardTraitPredicates.hasParam("Description", map.get("Description")))) { + return false; + } + // TODO check if Bone Man would deal damage to something that otherwise would regenerate + } return super.checkAiLogic(ai, sa, aiLogic); } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java index 6ff4caa7212..27db2fc2bb6 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersMoveAi.java @@ -475,8 +475,8 @@ public class CountersMoveAi extends SpellAbilityAi { @Override protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable options, boolean isOptional, Player targetedPlayer, Map params) { - if (sa.hasParam("AiLogic")) { - String logic = sa.getParam("AiLogic"); + if (sa.hasParam("AILogic")) { + String logic = sa.getParam("AILogic"); if ("ToValid".equals(logic)) { // cards like Forgotten Ancient diff --git a/forge-ai/src/main/java/forge/ai/ability/EffectAi.java b/forge-ai/src/main/java/forge/ai/ability/EffectAi.java index bcfda543dd4..f1e8ff3755a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/EffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/EffectAi.java @@ -1,6 +1,9 @@ package forge.ai.ability; import java.util.List; +import java.util.Map; + +import org.checkerframework.checker.nullness.qual.Nullable; import com.google.common.base.Predicate; import com.google.common.base.Predicates; @@ -15,7 +18,10 @@ import forge.ai.PlayerControllerAi; import forge.ai.SpecialCardAi; import forge.ai.SpellAbilityAi; import forge.ai.SpellApiToAi; +import forge.game.CardTraitPredicates; import forge.game.Game; +import forge.game.ability.AbilityKey; +import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.Card; import forge.game.card.CardCollection; @@ -28,11 +34,17 @@ import forge.game.combat.CombatUtil; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; +import forge.game.player.PlayerCollection; +import forge.game.replacement.ReplacementEffect; +import forge.game.replacement.ReplacementLayer; +import forge.game.replacement.ReplacementType; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetRestrictions; +import forge.game.zone.MagicStack; import forge.game.zone.ZoneType; import forge.util.MyRandom; +import forge.util.TextUtil; public class EffectAi extends SpellAbilityAi { @Override @@ -256,6 +268,59 @@ public class EffectAi extends SpellAbilityAi { return true; } return false; + } else if (logic.equals("CantRegenerate")) { + if (sa.usesTargeting()) { + CardCollection list = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa); + list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED, new Predicate() { + + @Override + public boolean apply(@Nullable Card input) { + Map runParams = AbilityKey.mapFromAffected(input); + runParams.put(AbilityKey.Regeneration, true); + List repDestoryList = game.getReplacementHandler().getReplacementList(ReplacementType.Destroy, runParams, ReplacementLayer.Other); + // no Destroy Replacement, or one non-Regeneration one like Totem-Armor + if (repDestoryList.isEmpty() || Iterables.any(repDestoryList, Predicates.not(CardTraitPredicates.hasParam("Regeneration")))) { + return false; + } + + if (cantRegenerateCheckCombat(input) || cantRegenerateCheckStack(input)) { + return true; + } + + return false; + } + }); + + if (list.isEmpty()) { + return false; + } + // TODO check Stack for Effects that would destroy the selected card? + sa.getTargets().add(ComputerUtilCard.getBestAI(list)); + return true; + } else if (sa.getParent() != null) { + // sub ability should be okay + return true; + } else if ("Self".equals(sa.getParam("RememberObjects"))) { + // the ones affecting itself are Nimbus cards, were opponent can activate this effect + Card host = sa.getHostCard(); + if (!host.canBeDestroyed()) { + return false; + } + + Map runParams = AbilityKey.mapFromAffected(sa.getHostCard()); + runParams.put(AbilityKey.Regeneration, true); + List repDestoryList = game.getReplacementHandler().getReplacementList(ReplacementType.Destroy, runParams, ReplacementLayer.Other); + // no Destroy Replacement, or one non-Regeneration one like Totem-Armor + if (repDestoryList.isEmpty() || Iterables.any(repDestoryList, Predicates.not(CardTraitPredicates.hasParam("Regeneration")))) { + return false; + } + + if (cantRegenerateCheckCombat(host) || cantRegenerateCheckStack(host)) { + return true; + } + + return false; + } } } else { //no AILogic return false; @@ -319,4 +384,193 @@ public class EffectAi extends SpellAbilityAi { return super.doTriggerAINoCost(aiPlayer, sa, mandatory); } + + protected boolean cantRegenerateCheckCombat(Card host) { + final Game game = host.getGame(); + if (!game.getPhaseHandler().inCombat()) { + return false; + } + if (!game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DAMAGE)) { + return false; + } + + Combat combat = game.getCombat(); + + if (game.getPhaseHandler().isPlayerTurn(host.getController())) { + // attacking player + if (!combat.isAttacking(host)) { + return false; + } + // TODO predict lethal combat damage + return combat.isBlocked(host); + } else { + // TODO predict lethal combat damage + return combat.isBlocking(host); + } + } + + protected boolean cantRegenerateCheckStack(Card host) { + final Game game = host.getGame(); + + // do this only in reaction to a threatening spell on directly on the stack + MagicStack stack = game.getStack(); + if (stack.isEmpty()) { + return false; + } + // TODO check Stack for Effects that would destroy host, either direct or indirect + SpellAbility stackSa = stack.peekAbility(); + if (stackSa == null) { + return false; + } + + // regenerate is a replace destroy, meaning either destroyed by effect + // or destroyed by state based action, when dying by lethal damage + SpellAbility subAbility = stackSa; + while (subAbility != null) { + ApiType apiType = subAbility.getApi(); + if (apiType == null) { + continue; + } + + if (ApiType.DestroyAll == apiType) { + // or skip to sub abilities? + if (subAbility.hasParam("NoRegen")) { + return false; + } + if (subAbility.usesTargeting() && !Iterables.contains(subAbility.getTargets().getTargetPlayers(), host.getController())) { + return false; + } + String valid = subAbility.getParamOrDefault("ValidCards", ""); + + // Ugh. If calculateAmount needs to be called with DestroyAll it _needs_ + // to use the X variable + // We really need a better solution to this + if (valid.contains("X")) { + valid = TextUtil.fastReplace(valid, + "X", Integer.toString(AbilityUtils.calculateAmount(subAbility.getHostCard(), "X", subAbility))); + } + + // host card is valid + if (host.isValid(valid.split(","), subAbility.getActivatingPlayer(), subAbility.getHostCard(), subAbility)) { + return true; + } + // failed to check via valid, need to pass through the filterList method + CardCollectionView list = game.getCardsIn(ZoneType.Battlefield); + + if (subAbility.usesTargeting()) { + list = CardLists.filterControlledBy(list, new PlayerCollection(subAbility.getTargets().getTargetPlayers())); + } + + list = AbilityUtils.filterListByType(list, valid, subAbility); + if (list.contains(host)) { + return true; + } + // check for defined + } else if (ApiType.Destroy == apiType) { + if (subAbility.hasParam("NoRegen")) { + return false; + } + if (subAbility.hasParam("Sacrifice")) { + return false; + } + // simulate getTargetCards + if (subAbility.usesTargeting()) { + // isTargeting checks parents, i think that might be wrong + if (subAbility.getTargets().contains(host)) { + return true; + } + } else { + if (AbilityUtils.getDefinedObjects(subAbility.getHostCard(), subAbility.getParam("Defined"), subAbility).contains(host)) { + return true; + } + } + + if (CardUtil.getRadiance(subAbility).contains(host)) { + return true; + } + + // check for target or indirect target + } else if (ApiType.DamageAll == apiType) { + if (!subAbility.hasParam("ValidCards")) { + continue; + } + String valid = subAbility.getParamOrDefault("ValidCards", ""); + if (valid.isEmpty()) { + continue; + } + + Card source = game.getChangeZoneLKIInfo(subAbility.getHostCard()); + if (source.isWitherDamage()) { + return false; + } + + // host card is valid + if (host.isValid(valid.split(","), subAbility.getActivatingPlayer(), subAbility.getHostCard(), subAbility)) { + // TODO check if damage would be lethal + return true; + } + // failed to check via valid, need to pass through the filterList method + CardCollectionView list = game.getCardsIn(ZoneType.Battlefield); + if (subAbility.usesTargeting()) { + list = CardLists.filterControlledBy(list, new PlayerCollection(subAbility.getTargets().getTargetPlayers())); + } + + list = AbilityUtils.filterListByType(list, valid, subAbility); + if (list.contains(host)) { + // TODO check if damage would be lethal + return true; + } + } else if (ApiType.DealDamage == apiType) { + // skip choices + if (subAbility.hasParam("CardChoices") || subAbility.hasParam("PlayerChoices")) { + continue; + } + + final List definedSources = AbilityUtils.getDefinedCards(subAbility.getHostCard(), subAbility.getParam("DamageSource"), subAbility); + if (definedSources == null || definedSources.isEmpty()) { + continue; + } + + boolean targeting = false; + // simulate getTargetCards + if (subAbility.usesTargeting()) { + // isTargeting checks parents, i think that might be wrong + if (subAbility.getTargets().contains(host)) { + targeting = true; + } + } else { + if (AbilityUtils.getDefinedObjects(subAbility.getHostCard(), subAbility.getParam("Defined"), subAbility).contains(host)) { + targeting = true; + } + } + + for (Card source : definedSources) { + final Card sourceLKI = game.getChangeZoneLKIInfo(source); + + if (sourceLKI.isWitherDamage()) { + return false; + } + + if (subAbility.hasParam("RelativeTarget")) { + targeting = false; + if (AbilityUtils.getDefinedEntities(subAbility.getHostCard(), subAbility.getParam("Defined"), subAbility).contains(host)) { + targeting = true; + } + } + // TODO predict damage + if (targeting) { + return true; + } + } + + if (CardUtil.getRadiance(subAbility).contains(host)) { + return true; + } + } + + subAbility = subAbility.getSubAbility(); + } + + return false; + } } diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java b/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java index b0702c90883..995af654eff 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java @@ -166,12 +166,6 @@ public abstract class PumpAiBase extends SpellAbilityAi { return false; } return ph.isPlayerTurn(ai) || (combat != null && combat.isAttacking(card) && card.getNetCombatDamage() > 0); - } else if (keyword.endsWith("CARDNAME can't be regenerated.")) { - if (card.getShieldCount() > 0) { - return true; - } - return card.hasKeyword("If CARDNAME would be destroyed, regenerate it.") && combat != null - && (combat.isBlocked(card) || combat.isBlocking(card)); } else return !keyword.endsWith("CARDNAME's activated abilities can't be activated."); //too complex } 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 b045a5627bc..04bac16178d 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java @@ -63,6 +63,7 @@ public final class AbilityFactory { "ChooseSubAbility", // Can choose a player via ChoosePlayer "CantChooseSubAbility", // Can't choose a player via ChoosePlayer "AnimateSubAbility", // For ChangeZone Effects to Animate before ETB + "RegenerationAbility", // for Regeneration Effect "ReturnAbility" // for Delayed Trigger on Magpie ); diff --git a/forge-game/src/main/java/forge/game/ability/effects/FogEffect.java b/forge-game/src/main/java/forge/game/ability/effects/FogEffect.java index 1886bbd2d70..c8206e86c8b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/FogEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/FogEffect.java @@ -38,6 +38,8 @@ public class FogEffect extends SpellAbilityEffect { game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); game.getEndOfTurn().addUntil(new GameCommand() { + private static final long serialVersionUID = -3297629217432253089L; + @Override public void run() { game.getAction().exile(eff, null); diff --git a/forge-game/src/main/java/forge/game/ability/effects/RegenerateAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RegenerateAllEffect.java index 16587a8e95b..647f369accf 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RegenerateAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RegenerateAllEffect.java @@ -2,7 +2,6 @@ package forge.game.ability.effects; import forge.game.Game; import forge.game.card.Card; -import forge.game.card.CardCollectionView; import forge.game.card.CardLists; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; @@ -28,11 +27,8 @@ public class RegenerateAllEffect extends RegenerateBaseEffect { final Game game = hostCard.getGame(); final String valid = sa.getParamOrDefault("ValidCards", ""); - CardCollectionView list = game.getCardsIn(ZoneType.Battlefield); - list = CardLists.getValidCards(list, valid, hostCard.getController(), hostCard, sa); - // create Effect for Regeneration - createRegenerationEffect(sa, list); + createRegenerationEffect(sa, CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), valid, hostCard.getController(), hostCard, sa)); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java index e1759f790f4..8b4db06bc18 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java @@ -1,5 +1,7 @@ package forge.game.ability.effects; +import java.util.Collection; + import forge.GameCommand; import forge.game.Game; import forge.game.ability.AbilityFactory; @@ -11,14 +13,15 @@ import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementHandler; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; -import forge.game.trigger.Trigger; -import forge.game.trigger.TriggerHandler; import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; public abstract class RegenerateBaseEffect extends SpellAbilityEffect { - public void createRegenerationEffect(SpellAbility sa, final Iterable list) { + public void createRegenerationEffect(SpellAbility sa, final Collection list) { + if (list.isEmpty()) { + return; + } final Card hostCard = sa.getHostCard(); final Game game = hostCard.getGame(); @@ -41,6 +44,11 @@ public abstract class RegenerateBaseEffect extends SpellAbilityEffect { SpellAbility saReg = AbilityFactory.getAbility(effect, eff); AbilitySub saExile = (AbilitySub)AbilityFactory.getAbility(exileEff, eff); + if (sa.hasAdditionalAbility("RegenerationAbility")) { + AbilitySub trigSA = (AbilitySub)sa.getAdditionalAbility("RegenerationAbility").copy(eff, sa.getActivatingPlayer(), false); + saExile.setSubAbility(trigSA); + } + saReg.setSubAbility(saExile); re.setOverridingAbility(saReg); eff.addReplacementEffect(re); @@ -50,18 +58,6 @@ public abstract class RegenerateBaseEffect extends SpellAbilityEffect { eff.addRemembered(AbilityUtils.getDefinedObjects(hostCard, sa.getParam("RememberObjects"), sa)); } - if (sa.hasParam("RegenerationTrigger")) { - final String str = sa.getSVar(sa.getParam("RegenerationTrigger")); - - SpellAbility trigSA = AbilityFactory.getAbility(str, eff); - - final String trigStr = "Mode$ Regenerated | ValidCause$ Effect.Self | TriggerZones$ Command " - + " | TriggerDescription$ " + trigSA.getDescription(); - final Trigger trigger = TriggerHandler.parseTrigger(trigStr, eff, true); - trigger.setOverridingAbility(trigSA); - eff.addTrigger(trigger); - } - // Copy text changes if (sa.isIntrinsic()) { eff.copyChangedTextFrom(hostCard); @@ -69,7 +65,7 @@ public abstract class RegenerateBaseEffect extends SpellAbilityEffect { // add RegenEffect as Shield to the Affected Cards for (final Card c : list) { - c.addShield(eff); + c.incShieldCount(); } game.getTriggerHandler().suppressMode(TriggerType.ChangesZone); game.getAction().moveTo(ZoneType.Command, eff, sa, AbilityKey.newMap()); diff --git a/forge-game/src/main/java/forge/game/ability/effects/RegenerateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RegenerateEffect.java index e3575ee2b99..4f88bc10f93 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RegenerateEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RegenerateEffect.java @@ -1,10 +1,12 @@ package forge.game.ability.effects; -import java.util.Iterator; import java.util.List; +import forge.game.Game; import forge.game.card.Card; +import forge.game.card.CardCollection; import forge.game.spellability.SpellAbility; +import forge.util.Lang; public class RegenerateEffect extends RegenerateBaseEffect { @@ -15,26 +17,13 @@ public class RegenerateEffect extends RegenerateBaseEffect { @Override protected String getStackDescription(SpellAbility sa) { final StringBuilder sb = new StringBuilder(); - final List tgtCards = getTargetCards(sa); + final List tgtCards = getDefinedCardsOrTargeted(sa); - if (tgtCards.size() > 0) { + if (!tgtCards.isEmpty()) { sb.append("Regenerate "); - - final Iterator it = tgtCards.iterator(); - while (it.hasNext()) { - final Card tgtC = it.next(); - if (tgtC.isFaceDown()) { - sb.append("Morph"); - } else { - sb.append(tgtC); - } - - if (it.hasNext()) { - sb.append(", "); - } - } + sb.append(Lang.joinHomogenous(tgtCards)); + sb.append("."); } - sb.append("."); return sb.toString(); } @@ -45,8 +34,26 @@ public class RegenerateEffect extends RegenerateBaseEffect { */ @Override public void resolve(SpellAbility sa) { + final Game game = sa.getHostCard().getGame(); + CardCollection result = new CardCollection(); + + for (Card c : getDefinedCardsOrTargeted(sa)) { + if (!c.isInPlay()) { + continue; + } + + // check if the object is still in game or if it was moved + Card gameCard = game.getCardState(c, null); + // gameCard is LKI in that case, the card is not in game anymore + // or the timestamp did change + // this should check Self too + if (gameCard == null || !c.equalsWithTimestamp(gameCard)) { + continue; + } + result.add(gameCard); + } // create Effect for Regeneration - createRegenerationEffect(sa, getDefinedCardsOrTargeted(sa)); + createRegenerationEffect(sa, result); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java index f9f9aeff912..c1976ad42ba 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java @@ -1,14 +1,10 @@ package forge.game.ability.effects; -import java.util.Map; - import forge.game.Game; -import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.event.GameEventCardRegenerated; import forge.game.spellability.SpellAbility; -import forge.game.trigger.TriggerType; public class RegenerationEffect extends SpellAbilityEffect { @@ -21,9 +17,7 @@ public class RegenerationEffect extends SpellAbilityEffect { final Card host = sa.getHostCard(); final Game game = host.getGame(); for (Card c : getTargetCards(sa)) { - if (!c.canBeShielded() || !c.isInPlay()) { - continue; - } + // checks already done in ReplacementEffect c.setDamage(0); c.setHasBeenDealtDeathtouchDamage(false); @@ -39,14 +33,9 @@ public class RegenerationEffect extends SpellAbilityEffect { game.fireEvent(new GameEventCardRegenerated(c)); if (host.isImmutable()) { - c.subtractShield(host); + c.decShieldCount(); host.removeRemembered(c); } - - // Run triggers - final Map runParams = AbilityKey.mapFromCard(c); - runParams.put(AbilityKey.Cause, host); - game.getTriggerHandler().runTrigger(TriggerType.Regenerated, runParams, false); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RevealEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RevealEffect.java index 0f1b6f6c695..e08175329d5 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RevealEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RevealEffect.java @@ -5,7 +5,6 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; import forge.game.Game; -import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -14,7 +13,6 @@ import forge.game.card.CardCollectionView; import forge.game.card.CardLists; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; import forge.util.Aggregates; @@ -83,7 +81,6 @@ public class RevealEffect extends SpellAbilityEffect { game.getAction().reveal(revealed, p); } for (final Card c : revealed) { - game.getTriggerHandler().runTrigger(TriggerType.Revealed, AbilityKey.mapFromCard(c), false); if (sa.hasParam("RememberRevealed")) { host.addRemembered(c); } 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 b1213436b5c..e6558d2288a 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -268,7 +268,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { private boolean hasBeenDealtExcessDamageThisTurn; // regeneration - private FCollection shields = new FCollection<>(); + private int shieldCount = 0; private int regeneratedThisTurn; private int turnInZone; @@ -3230,28 +3230,22 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } // shield = regeneration - public final Iterable getShields() { - return shields; - } public final int getShieldCount() { - return shields.size(); + return shieldCount; } - public final void addShield(final Card shield) { - if (shields.add(shield)) { - view.updateShieldCount(this); - } + public final void incShieldCount() { + shieldCount++; + view.updateShieldCount(this); } - public final void subtractShield(final Card shield) { - if (shields.remove(shield)) { - view.updateShieldCount(this); - } + public final void decShieldCount() { + shieldCount--; + view.updateShieldCount(this); } - public final void resetShield() { - if (shields.isEmpty()) { return; } - shields.clear(); + public final void resetShieldCount() { + shieldCount = 0; view.updateShieldCount(this); } @@ -3267,7 +3261,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } public final boolean canBeShielded() { - return !hasKeyword("CARDNAME can't be regenerated."); + return !StaticAbilityCantRegenerate.cantRegenerate(this); } // is this "Card" supposed to be a token? @@ -6597,7 +6591,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { setHasBeenDealtDeathtouchDamage(false); setHasBeenDealtExcessDamageThisTurn(false); setRegeneratedThisTurn(0); - resetShield(); + resetShieldCount(); setBecameTargetThisTurn(false); setFoughtThisTurn(false); clearMustBlockCards(); 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 0f9dbc5211f..3bac3517abf 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -2574,15 +2574,6 @@ public class CardFactoryUtil { final ReplacementEffect re = makeEtbCounter(sb.toString(), card, intrinsic); - inst.addReplacement(re); - } else if (keyword.equals("If CARDNAME would be destroyed, regenerate it.")) { - String repeffstr = "Event$ Destroy | ActiveZones$ Battlefield | ValidCard$ Card.Self" - + " | Secondary$ True | Regeneration$ True | Description$ " + keyword; - String effect = "DB$ Regeneration | Defined$ ReplacedCard"; - ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, host, intrinsic, card); - SpellAbility sa = AbilityFactory.getAbility(effect, card); - re.setOverridingAbility(sa); - inst.addReplacement(re); } @@ -2639,30 +2630,6 @@ public class CardFactoryUtil { ReplacementEffect re = ReplacementHandler.parseReplacement(rep, host, intrinsic, card); inst.addReplacement(re); } - else if (keyword.startsWith("If CARDNAME would be put into a graveyard " - + "from anywhere, reveal CARDNAME and shuffle it into its owner's library instead.")) { - StringBuilder sb = new StringBuilder("Event$ Moved | Destination$ Graveyard | ValidCard$ Card.Self "); - - // to show it on Nexus - if (host.isPermanent()) { - sb.append("| Secondary$ True"); - } - sb.append("| Description$ ").append(keyword); - - String ab = "DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Library | Defined$ ReplacedCard | Reveal$ True | Shuffle$ True"; - - SpellAbility sa = AbilityFactory.getAbility(ab, card); - - if (!intrinsic) { - sa.setIntrinsic(false); - } - - ReplacementEffect re = ReplacementHandler.parseReplacement(sb.toString(), host, intrinsic, card); - - re.setOverridingAbility(sa); - - inst.addReplacement(re); - } if (keyword.equals("CARDNAME enters the battlefield tapped.")) { String effect = "DB$ Tap | Defined$ Self | ETB$ True " diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantRegenerate.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantRegenerate.java new file mode 100644 index 00000000000..a7ea6a1f89e --- /dev/null +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantRegenerate.java @@ -0,0 +1,33 @@ +package forge.game.staticability; + +import forge.game.Game; +import forge.game.card.Card; +import forge.game.zone.ZoneType; + +public class StaticAbilityCantRegenerate { + + static String MODE = "CantRegenerate"; + + public static boolean cantRegenerate(final Card card) { + final Game game = card.getGame(); + for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { + for (final StaticAbility stAb : ca.getStaticAbilities()) { + if (!stAb.checkConditions(MODE)) { + continue; + } + + if (applyCantRegenerateAbility(stAb, card)) { + return true; + } + } + } + return false; + } + + public static boolean applyCantRegenerateAbility(final StaticAbility stAb, final Card card) { + if (!stAb.matchesValidParam("ValidCard", card)) { + return false; + } + return true; + } +} diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerRegenerated.java b/forge-game/src/main/java/forge/game/trigger/TriggerRegenerated.java deleted file mode 100644 index a5d021b956b..00000000000 --- a/forge-game/src/main/java/forge/game/trigger/TriggerRegenerated.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Forge: Play Magic: the Gathering. - * Copyright (C) 2011 Forge Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package forge.game.trigger; - -import java.util.Map; - -import forge.game.ability.AbilityKey; -import forge.game.card.Card; -import forge.game.spellability.SpellAbility; -import forge.util.Localizer; - -/** - *

- * Trigger_Destroyed class. - *

- * - * @author Forge - * @version $Id: TriggerDestroyed.java 17802 2012-10-31 08:05:14Z Max mtg $ - */ -public class TriggerRegenerated extends Trigger { - - /** - *

- * Constructor for Trigger_Destroyed. - *

- * - * @param params - * a {@link java.util.HashMap} object. - * @param host - * a {@link forge.game.card.Card} object. - * @param intrinsic - * the intrinsic - */ - public TriggerRegenerated(final Map params, final Card host, final boolean intrinsic) { - super(params, host, intrinsic); - } - - /** {@inheritDoc} - * @param runParams*/ - @Override - public final boolean performTest(final Map runParams) { - if (!matchesValidParam("ValidCause", runParams.get(AbilityKey.Cause))) { - return false; - } - if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Card))) { - return false; - } - return true; - } - - /** {@inheritDoc} */ - @Override - public final void setTriggeringObjects(final SpellAbility sa, Map runParams) { - sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card, AbilityKey.Cause); - } - - @Override - public String getImportantStackObjects(SpellAbility sa) { - StringBuilder sb = new StringBuilder(); - sb.append(Localizer.getInstance().getMessage("lblRegenerated")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); - //sb.append("Destroyer: ").append(sa.getTriggeringObject("Causer")); - return sb.toString(); - } -} diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerRevealed.java b/forge-game/src/main/java/forge/game/trigger/TriggerRevealed.java deleted file mode 100644 index 498439ffdfc..00000000000 --- a/forge-game/src/main/java/forge/game/trigger/TriggerRevealed.java +++ /dev/null @@ -1,37 +0,0 @@ -package forge.game.trigger; - -import java.util.Map; - -import forge.game.ability.AbilityKey; -import forge.game.card.Card; -import forge.game.spellability.SpellAbility; -import forge.util.Localizer; - -@Deprecated -public class TriggerRevealed extends Trigger { - - public TriggerRevealed(Map params, Card host, boolean intrinsic) { - super(params, host, intrinsic); - } - - @Override - public boolean performTest(Map runParams) { - if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Card))) { - return false; - } - return true; - } - - @Override - public void setTriggeringObjects(SpellAbility sa, Map runParams) { - sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card); - } - - @Override - public String getImportantStackObjects(SpellAbility sa) { - StringBuilder sb = new StringBuilder(); - sb.append(Localizer.getInstance().getMessage("lblRevealed")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); - return sb.toString(); - } - -} diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerType.java b/forge-game/src/main/java/forge/game/trigger/TriggerType.java index 6723f597b35..9ec8e641045 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerType.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerType.java @@ -1,184 +1,182 @@ -package forge.game.trigger; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Map; - -import forge.game.card.Card; - - -/** - * TODO: Write javadoc for this type. - * - */ -public enum TriggerType { - Abandoned(TriggerAbandoned.class), - AbilityCast(TriggerSpellAbilityCastOrCopy.class), - AbilityResolves(TriggerAbilityResolves.class), - AbilityTriggered(TriggerAbilityTriggered.class), - Adapt(TriggerAdapt.class), - Always(TriggerAlways.class), - Attached(TriggerAttached.class), - AttackerBlocked(TriggerAttackerBlocked.class), - AttackerBlockedOnce(TriggerAttackerBlockedOnce.class), - AttackerBlockedByCreature(TriggerAttackerBlockedByCreature.class), - AttackersDeclared(TriggerAttackersDeclared.class), - AttackersDeclaredOneTarget(TriggerAttackersDeclared.class), - AttackerUnblocked(TriggerAttackerUnblocked.class), - AttackerUnblockedOnce(TriggerAttackerUnblockedOnce.class), - Attacks(TriggerAttacks.class), - BecomeMonarch(TriggerBecomeMonarch.class), - BecomeMonstrous(TriggerBecomeMonstrous.class), - BecomeRenowned(TriggerBecomeRenowned.class), - BecomesCrewed(TriggerBecomesCrewed.class), - BecomesTarget(TriggerBecomesTarget.class), - BecomesTargetOnce(TriggerBecomesTargetOnce.class), - BlockersDeclared(TriggerBlockersDeclared.class), - Blocks(TriggerBlocks.class), - Championed(TriggerChampioned.class), - ChangesController(TriggerChangesController.class), - ChangesZone(TriggerChangesZone.class), - ChangesZoneAll(TriggerChangesZoneAll.class), - ChaosEnsues(TriggerChaosEnsues.class), - Clashed(TriggerClashed.class), - ClassLevelGained(TriggerClassLevelGained.class), - ConjureAll(TriggerConjureAll.class), - CounterAdded(TriggerCounterAdded.class), - CounterAddedOnce(TriggerCounterAddedOnce.class), - CounterPlayerAddedAll(TriggerCounterPlayerAddedAll.class), - CounterAddedAll(TriggerCounterAddedAll.class), - Countered(TriggerCountered.class), - CounterRemoved(TriggerCounterRemoved.class), - CounterRemovedOnce(TriggerCounterRemovedOnce.class), - Crewed(TriggerCrewed.class), - Cycled(TriggerCycled.class), - DamageAll(TriggerDamageAll.class), - DamageDealtOnce(TriggerDamageDealtOnce.class), - DamageDone(TriggerDamageDone.class), - DamageDoneOnce(TriggerDamageDoneOnce.class), - DamageDoneOnceByController(TriggerDamageDoneOnceByController.class), - DamagePrevented(TriggerDamagePrevented.class), - DamagePreventedOnce(TriggerDamagePreventedOnce.class), - DayTimeChanges (TriggerDayTimeChanges.class), - Destroyed(TriggerDestroyed.class), - Devoured(TriggerDevoured.class), - Discarded(TriggerDiscarded.class), - DiscardedAll(TriggerDiscardedAll.class), - Drawn(TriggerDrawn.class), - DungeonCompleted(TriggerCompletedDungeon.class), - Evolved(TriggerEvolved.class), - ExcessDamage(TriggerExcessDamage.class), - Enlisted(TriggerEnlisted.class), - Exerted(TriggerExerted.class), - Exiled(TriggerExiled.class), - Exploited(TriggerExploited.class), - Explores(TriggerExplores.class), - Fight(TriggerFight.class), - FightOnce(TriggerFightOnce.class), - FlippedCoin(TriggerFlippedCoin.class), - Foretell(TriggerForetell.class), - Immediate(TriggerImmediate.class), - Investigated(TriggerInvestigated.class), - IsForetold(TriggerIsForetold.class), - LandPlayed(TriggerLandPlayed.class), - LifeGained(TriggerLifeGained.class), - LifeLost(TriggerLifeLost.class), - LifeLostAll(TriggerLifeLostAll.class), - LosesGame(TriggerLosesGame.class), - ManaAdded(TriggerManaAdded.class), - MilledAll(TriggerMilledAll.class), - Mutates(TriggerMutates.class), - NewGame(TriggerNewGame.class), - PayCumulativeUpkeep(TriggerPayCumulativeUpkeep.class), - PayEcho(TriggerPayEcho.class), - PayLife(TriggerPayLife.class), - Phase(TriggerPhase.class), - PhaseIn(TriggerPhaseIn.class), - PhaseOut(TriggerPhaseOut.class), - PlanarDice(TriggerPlanarDice.class), - PlaneswalkedFrom(TriggerPlaneswalkedFrom.class), - PlaneswalkedTo(TriggerPlaneswalkedTo.class), - Proliferate(TriggerProliferate.class), - Regenerated(TriggerRegenerated.class), - Revealed(TriggerRevealed.class), - RingTemptsYou(TriggerRingTemptsYou.class), - RolledDie(TriggerRolledDie.class), - RolledDieOnce(TriggerRolledDieOnce.class), - RoomEntered(TriggerEnteredRoom.class), - Sacrificed(TriggerSacrificed.class), - Scry(TriggerScry.class), - SearchedLibrary(TriggerSearchedLibrary.class), - SeekAll(TriggerSeekAll.class), - SetInMotion(TriggerSetInMotion.class), - Shuffled(TriggerShuffled.class), - Specializes(TriggerSpecializes.class), - SpellAbilityCast(TriggerSpellAbilityCastOrCopy.class), - SpellAbilityCopy(TriggerSpellAbilityCastOrCopy.class), - SpellCast(TriggerSpellAbilityCastOrCopy.class), - SpellCastOrCopy(TriggerSpellAbilityCastOrCopy.class), - SpellCopy(TriggerSpellAbilityCastOrCopy.class), - Surveil(TriggerSurveil.class), - TakesInitiative(TriggerTakesInitiative.class), - Taps(TriggerTaps.class), - TapsForMana(TriggerTapsForMana.class), - TokenCreated(TriggerTokenCreated.class), - TokenCreatedOnce(TriggerTokenCreatedOnce.class), - Trains(TriggerTrains.class), - Transformed(TriggerTransformed.class), - TurnBegin(TriggerTurnBegin.class), - TurnFaceUp(TriggerTurnFaceUp.class), - Unattach(TriggerUnattach.class), - Untaps(TriggerUntaps.class), - Vote(TriggerVote.class); - - private final Constructor constructor; - - TriggerType(Class clasz) { - constructor = findConstructor(clasz); - } - - private static Constructor findConstructor(Class clasz) { - @SuppressWarnings("unchecked") - Constructor[] cc = (Constructor[]) clasz.getDeclaredConstructors(); - for (Constructor c : cc) { - Class[] pp = c.getParameterTypes(); - if (pp[0].isAssignableFrom(Map.class)) { - return c; - } - } - throw new RuntimeException("No constructor found that would take Map as 1st parameter in class " + clasz.getName()); - } - - /** - * TODO: Write javadoc for this method. - * @param value - * @return - */ - public static TriggerType smartValueOf(String value) { - final String valToCompate = value.trim(); - for (final TriggerType v : TriggerType.values()) { - if (v.name().compareToIgnoreCase(valToCompate) == 0) { - return v; - } - } - - throw new RuntimeException("Element " + value + " not found in TriggerType enum"); - } - - /** - * TODO: Write javadoc for this method. - * @param mapParams - * @param host - * @param intrinsic - * @return - */ - public Trigger createTrigger(Map mapParams, Card host, boolean intrinsic) { - try { - Trigger res = constructor.newInstance(mapParams, host, intrinsic); - res.setMode(this); - return res; - } catch (IllegalArgumentException | InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - } -} +package forge.game.trigger; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; + +import forge.game.card.Card; + + +/** + * TODO: Write javadoc for this type. + * + */ +public enum TriggerType { + Abandoned(TriggerAbandoned.class), + AbilityCast(TriggerSpellAbilityCastOrCopy.class), + AbilityResolves(TriggerAbilityResolves.class), + AbilityTriggered(TriggerAbilityTriggered.class), + Adapt(TriggerAdapt.class), + Always(TriggerAlways.class), + Attached(TriggerAttached.class), + AttackerBlocked(TriggerAttackerBlocked.class), + AttackerBlockedOnce(TriggerAttackerBlockedOnce.class), + AttackerBlockedByCreature(TriggerAttackerBlockedByCreature.class), + AttackersDeclared(TriggerAttackersDeclared.class), + AttackersDeclaredOneTarget(TriggerAttackersDeclared.class), + AttackerUnblocked(TriggerAttackerUnblocked.class), + AttackerUnblockedOnce(TriggerAttackerUnblockedOnce.class), + Attacks(TriggerAttacks.class), + BecomeMonarch(TriggerBecomeMonarch.class), + BecomeMonstrous(TriggerBecomeMonstrous.class), + BecomeRenowned(TriggerBecomeRenowned.class), + BecomesCrewed(TriggerBecomesCrewed.class), + BecomesTarget(TriggerBecomesTarget.class), + BecomesTargetOnce(TriggerBecomesTargetOnce.class), + BlockersDeclared(TriggerBlockersDeclared.class), + Blocks(TriggerBlocks.class), + Championed(TriggerChampioned.class), + ChangesController(TriggerChangesController.class), + ChangesZone(TriggerChangesZone.class), + ChangesZoneAll(TriggerChangesZoneAll.class), + ChaosEnsues(TriggerChaosEnsues.class), + Clashed(TriggerClashed.class), + ClassLevelGained(TriggerClassLevelGained.class), + ConjureAll(TriggerConjureAll.class), + CounterAdded(TriggerCounterAdded.class), + CounterAddedOnce(TriggerCounterAddedOnce.class), + CounterPlayerAddedAll(TriggerCounterPlayerAddedAll.class), + CounterAddedAll(TriggerCounterAddedAll.class), + Countered(TriggerCountered.class), + CounterRemoved(TriggerCounterRemoved.class), + CounterRemovedOnce(TriggerCounterRemovedOnce.class), + Crewed(TriggerCrewed.class), + Cycled(TriggerCycled.class), + DamageAll(TriggerDamageAll.class), + DamageDealtOnce(TriggerDamageDealtOnce.class), + DamageDone(TriggerDamageDone.class), + DamageDoneOnce(TriggerDamageDoneOnce.class), + DamageDoneOnceByController(TriggerDamageDoneOnceByController.class), + DamagePrevented(TriggerDamagePrevented.class), + DamagePreventedOnce(TriggerDamagePreventedOnce.class), + DayTimeChanges (TriggerDayTimeChanges.class), + Destroyed(TriggerDestroyed.class), + Devoured(TriggerDevoured.class), + Discarded(TriggerDiscarded.class), + DiscardedAll(TriggerDiscardedAll.class), + Drawn(TriggerDrawn.class), + DungeonCompleted(TriggerCompletedDungeon.class), + Evolved(TriggerEvolved.class), + ExcessDamage(TriggerExcessDamage.class), + Enlisted(TriggerEnlisted.class), + Exerted(TriggerExerted.class), + Exiled(TriggerExiled.class), + Exploited(TriggerExploited.class), + Explores(TriggerExplores.class), + Fight(TriggerFight.class), + FightOnce(TriggerFightOnce.class), + FlippedCoin(TriggerFlippedCoin.class), + Foretell(TriggerForetell.class), + Immediate(TriggerImmediate.class), + Investigated(TriggerInvestigated.class), + IsForetold(TriggerIsForetold.class), + LandPlayed(TriggerLandPlayed.class), + LifeGained(TriggerLifeGained.class), + LifeLost(TriggerLifeLost.class), + LifeLostAll(TriggerLifeLostAll.class), + LosesGame(TriggerLosesGame.class), + ManaAdded(TriggerManaAdded.class), + MilledAll(TriggerMilledAll.class), + Mutates(TriggerMutates.class), + NewGame(TriggerNewGame.class), + PayCumulativeUpkeep(TriggerPayCumulativeUpkeep.class), + PayEcho(TriggerPayEcho.class), + PayLife(TriggerPayLife.class), + Phase(TriggerPhase.class), + PhaseIn(TriggerPhaseIn.class), + PhaseOut(TriggerPhaseOut.class), + PlanarDice(TriggerPlanarDice.class), + PlaneswalkedFrom(TriggerPlaneswalkedFrom.class), + PlaneswalkedTo(TriggerPlaneswalkedTo.class), + Proliferate(TriggerProliferate.class), + RingTemptsYou(TriggerRingTemptsYou.class), + RolledDie(TriggerRolledDie.class), + RolledDieOnce(TriggerRolledDieOnce.class), + RoomEntered(TriggerEnteredRoom.class), + Sacrificed(TriggerSacrificed.class), + Scry(TriggerScry.class), + SearchedLibrary(TriggerSearchedLibrary.class), + SeekAll(TriggerSeekAll.class), + SetInMotion(TriggerSetInMotion.class), + Shuffled(TriggerShuffled.class), + Specializes(TriggerSpecializes.class), + SpellAbilityCast(TriggerSpellAbilityCastOrCopy.class), + SpellAbilityCopy(TriggerSpellAbilityCastOrCopy.class), + SpellCast(TriggerSpellAbilityCastOrCopy.class), + SpellCastOrCopy(TriggerSpellAbilityCastOrCopy.class), + SpellCopy(TriggerSpellAbilityCastOrCopy.class), + Surveil(TriggerSurveil.class), + TakesInitiative(TriggerTakesInitiative.class), + Taps(TriggerTaps.class), + TapsForMana(TriggerTapsForMana.class), + TokenCreated(TriggerTokenCreated.class), + TokenCreatedOnce(TriggerTokenCreatedOnce.class), + Trains(TriggerTrains.class), + Transformed(TriggerTransformed.class), + TurnBegin(TriggerTurnBegin.class), + TurnFaceUp(TriggerTurnFaceUp.class), + Unattach(TriggerUnattach.class), + Untaps(TriggerUntaps.class), + Vote(TriggerVote.class); + + private final Constructor constructor; + + TriggerType(Class clasz) { + constructor = findConstructor(clasz); + } + + private static Constructor findConstructor(Class clasz) { + @SuppressWarnings("unchecked") + Constructor[] cc = (Constructor[]) clasz.getDeclaredConstructors(); + for (Constructor c : cc) { + Class[] pp = c.getParameterTypes(); + if (pp[0].isAssignableFrom(Map.class)) { + return c; + } + } + throw new RuntimeException("No constructor found that would take Map as 1st parameter in class " + clasz.getName()); + } + + /** + * TODO: Write javadoc for this method. + * @param value + * @return + */ + public static TriggerType smartValueOf(String value) { + final String valToCompate = value.trim(); + for (final TriggerType v : TriggerType.values()) { + if (v.name().compareToIgnoreCase(valToCompate) == 0) { + return v; + } + } + + throw new RuntimeException("Element " + value + " not found in TriggerType enum"); + } + + /** + * TODO: Write javadoc for this method. + * @param mapParams + * @param host + * @param intrinsic + * @return + */ + public Trigger createTrigger(Map mapParams, Card host, boolean intrinsic) { + try { + Trigger res = constructor.newInstance(mapParams, host, intrinsic); + res.setMode(this); + return res; + } catch (IllegalArgumentException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } +} diff --git a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java index 7557f73d4ed..3610f61775e 100644 --- a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java +++ b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java @@ -66,6 +66,10 @@ public class WrappedAbility extends Ability { ApiType.SacrificeAll, ApiType.Pump, + ApiType.Regenerate, // Updated + ApiType.RegenerateAll, // No Triggered + ApiType.Regeneration, // Replacement Effect only + ApiType.DelayedTrigger ); diff --git a/forge-gui/res/cardsfolder/a/aetherborn_marauder.txt b/forge-gui/res/cardsfolder/a/aetherborn_marauder.txt index b9f8bb42cb0..e2edf9fede6 100644 --- a/forge-gui/res/cardsfolder/a/aetherborn_marauder.txt +++ b/forge-gui/res/cardsfolder/a/aetherborn_marauder.txt @@ -5,5 +5,5 @@ PT:2/2 K:Flying K:Lifelink T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMoveCounters | TriggerDescription$ When CARDNAME enters the battlefield, move any number of +1/+1 counters from other permanents you control onto CARDNAME. -SVar:TrigMoveCounters:DB$ MoveCounter | ValidSource$ Permanent.YouCtrl+Other+counters_GE1_P1P1 | Defined$ Self | CounterType$ P1P1 | CounterNum$ Any | AiLogic$ FromValid +SVar:TrigMoveCounters:DB$ MoveCounter | ValidSource$ Permanent.YouCtrl+Other+counters_GE1_P1P1 | Defined$ Self | CounterType$ P1P1 | CounterNum$ Any | AILogic$ FromValid Oracle:Flying, lifelink\nWhen Aetherborn Marauder enters the battlefield, move any number of +1/+1 counters from other permanents you control onto Aetherborn Marauder. diff --git a/forge-gui/res/cardsfolder/a/alhammarrets_archive.txt b/forge-gui/res/cardsfolder/a/alhammarrets_archive.txt index 45794accddd..060c8fed385 100644 --- a/forge-gui/res/cardsfolder/a/alhammarrets_archive.txt +++ b/forge-gui/res/cardsfolder/a/alhammarrets_archive.txt @@ -1,7 +1,7 @@ Name:Alhammarret's Archive ManaCost:5 Types:Legendary Artifact -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainDouble | AiLogic$ DoubleLife | Description$ If you would gain life, you gain twice that much life instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainDouble | AILogic$ DoubleLife | Description$ If you would gain life, you gain twice that much life instead. SVar:GainDouble:DB$ ReplaceEffect | VarName$ LifeGained | VarValue$ X SVar:X:ReplaceCount$LifeGained/Twice R:Event$ Draw | ActiveZones$ Battlefield | ValidPlayer$ You | NotFirstCardInDrawStep$ True | ReplaceWith$ DrawTwo | Description$ If you would draw a card except the first one you draw in each of your draw steps, draw two cards instead. diff --git a/forge-gui/res/cardsfolder/a/angel_of_vitality.txt b/forge-gui/res/cardsfolder/a/angel_of_vitality.txt index 2c5167616a3..03fe81db05b 100644 --- a/forge-gui/res/cardsfolder/a/angel_of_vitality.txt +++ b/forge-gui/res/cardsfolder/a/angel_of_vitality.txt @@ -3,7 +3,7 @@ ManaCost:2 W Types:Creature Angel PT:2/2 K:Flying -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AiLogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AILogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. SVar:GainLife:DB$ ReplaceEffect | VarName$ LifeGained | VarValue$ X SVar:X:ReplaceCount$LifeGained/Plus.1 SVar:PlayMain1:True diff --git a/forge-gui/res/cardsfolder/b/blightsteel_colossus.txt b/forge-gui/res/cardsfolder/b/blightsteel_colossus.txt index adefdef0521..509ed8b1433 100644 --- a/forge-gui/res/cardsfolder/b/blightsteel_colossus.txt +++ b/forge-gui/res/cardsfolder/b/blightsteel_colossus.txt @@ -5,5 +5,6 @@ PT:11/11 K:Trample K:Infect K:Indestructible -K:If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +R:Event$ Moved | Destination$ Graveyard | ValidCard$ Card.Self | ReplaceWith$ DBShuffle | Description$ If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +SVar:DBShuffle:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Library | Defined$ ReplacedCard | Reveal$ True | Shuffle$ True Oracle:Trample, infect, indestructible\nIf Blightsteel Colossus would be put into a graveyard from anywhere, reveal Blightsteel Colossus and shuffle it into its owner's library instead. diff --git a/forge-gui/res/cardsfolder/b/bone_shaman.txt b/forge-gui/res/cardsfolder/b/bone_shaman.txt index 90a764984dd..8881e294033 100644 --- a/forge-gui/res/cardsfolder/b/bone_shaman.txt +++ b/forge-gui/res/cardsfolder/b/bone_shaman.txt @@ -2,7 +2,7 @@ Name:Bone Shaman ManaCost:2 R R Types:Creature Giant Shaman PT:3/3 -A:AB$ Animate | Cost$ B | Defined$ Self | staticAbilities$ BoneShamanStatic | StackDescription$ CARDNAME gains "Creatures dealt damage by CARDNAME this turn can't be regenerated this turn." | SpellDescription$ Until end of turn, CARDNAME gains "Creatures dealt damage by CARDNAME this turn can't be regenerated this turn." -SVar:BoneShamanStatic:Mode$ Continuous | Affected$ Creature.DamagedBy | AddHiddenKeyword$ CARDNAME can't be regenerated. | Description$ Creatures dealt damage by CARDNAME this turn can't be regenerated this turn. +A:AB$ Animate | Cost$ B | Defined$ Self | staticAbilities$ BoneShamanStatic | AILogic$ BoneManCantRegenerate | StackDescription$ SpellDescription | SpellDescription$ Until end of turn, CARDNAME gains "Creatures dealt damage by CARDNAME this turn can't be regenerated this turn." +SVar:BoneShamanStatic:Mode$ CantRegenerate | ValidCard$ Creature.DamagedBy | Description$ Creatures dealt damage by CARDNAME this turn can't be regenerated this turn. AI:RemoveDeck:All Oracle:{B}: Until end of turn, Bone Shaman gains "Creatures dealt damage by Bone Shaman this turn can't be regenerated this turn." diff --git a/forge-gui/res/cardsfolder/b/boon_reflection.txt b/forge-gui/res/cardsfolder/b/boon_reflection.txt index 68a8a1c68af..06ff925a168 100644 --- a/forge-gui/res/cardsfolder/b/boon_reflection.txt +++ b/forge-gui/res/cardsfolder/b/boon_reflection.txt @@ -1,7 +1,7 @@ Name:Boon Reflection ManaCost:4 W Types:Enchantment -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainDouble | AiLogic$ DoubleLife | Description$ If you would gain life, you gain twice that much life instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainDouble | AILogic$ DoubleLife | Description$ If you would gain life, you gain twice that much life instead. SVar:GainDouble:DB$ ReplaceEffect | VarName$ LifeGained | VarValue$ X SVar:X:ReplaceCount$LifeGained/Twice SVar:PlayMain1:True diff --git a/forge-gui/res/cardsfolder/c/capital_punishment.txt b/forge-gui/res/cardsfolder/c/capital_punishment.txt index f1bdef22faf..7fa3e149aff 100644 --- a/forge-gui/res/cardsfolder/c/capital_punishment.txt +++ b/forge-gui/res/cardsfolder/c/capital_punishment.txt @@ -1,7 +1,7 @@ Name:Capital Punishment ManaCost:4 B B Types:Sorcery -A:SP$ Vote | Cost$ 4 B B | Defined$ Player | StoreVoteNum$ True | VoteType$ Death,Taxes | SubAbility$ DBVoteDeath | AiLogic$ DeathOrTaxes | SpellDescription$ Council's dilemma — Starting with you, each player votes for death or taxes. Each opponent sacrifices a creature for each death vote and discards a card for each taxes vote. +A:SP$ Vote | Cost$ 4 B B | Defined$ Player | StoreVoteNum$ True | VoteType$ Death,Taxes | SubAbility$ DBVoteDeath | AILogic$ DeathOrTaxes | SpellDescription$ Council's dilemma — Starting with you, each player votes for death or taxes. Each opponent sacrifices a creature for each death vote and discards a card for each taxes vote. SVar:DBVoteDeath:DB$ Sacrifice | Defined$ Player.Opponent | SacValid$ Creature | SacMessage$ Creature | Amount$ VoteNumDeath | SubAbility$ DBVoteTaxes SVar:DBVoteTaxes:DB$ Discard | Defined$ Player.Opponent | NumCards$ VoteNumTaxes | Mode$ TgtChoose Oracle:Council's dilemma — Starting with you, each player votes for death or taxes. Each opponent sacrifices a creature for each death vote and discards a card for each taxes vote. diff --git a/forge-gui/res/cardsfolder/c/carbonize.txt b/forge-gui/res/cardsfolder/c/carbonize.txt index 9bea4c5378b..540df0e5068 100644 --- a/forge-gui/res/cardsfolder/c/carbonize.txt +++ b/forge-gui/res/cardsfolder/c/carbonize.txt @@ -2,5 +2,6 @@ Name:Carbonize ManaCost:2 R Types:Instant A:SP$ DealDamage | ValidTgts$ Any | NumDmg$ 3 | SubAbility$ DB | ReplaceDyingDefined$ ThisTargetedCard.Creature | SpellDescription$ CARDNAME deals 3 damage to any target. If it's a creature, it can't be regenerated this turn, and if it would die this turn, exile it instead. -SVar:DB:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ ParentTarget | ConditionDefined$ ParentTarget | ConditionPresent$ Creature | StackDescription$ None +SVar:DB:DB$ Effect | RememberObjects$ ParentTarget | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | ConditionDefined$ ParentTarget | ConditionPresent$ Creature | AILogic$ CantRegenerate | StackDescription$ None +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. Oracle:Carbonize deals 3 damage to any target. If it's a creature, it can't be regenerated this turn, and if it would die this turn, exile it instead. diff --git a/forge-gui/res/cardsfolder/c/clergy_of_the_holy_nimbus.txt b/forge-gui/res/cardsfolder/c/clergy_of_the_holy_nimbus.txt index 496bbad29f6..f9d18c005c0 100644 --- a/forge-gui/res/cardsfolder/c/clergy_of_the_holy_nimbus.txt +++ b/forge-gui/res/cardsfolder/c/clergy_of_the_holy_nimbus.txt @@ -2,6 +2,8 @@ Name:Clergy of the Holy Nimbus ManaCost:W Types:Creature Human Cleric PT:1/1 -K:If CARDNAME would be destroyed, regenerate it. -A:AB$ Pump | Cost$ 1 | Activator$ Player.Opponent | Defined$ Self | KW$ HIDDEN CARDNAME can't be regenerated. | IsCurse$ True | SpellDescription$ CARDNAME can't be regenerated this turn. Only your opponents may activate this ability. +R:Event$ Destroy | ActiveZones$ Battlefield | ValidCard$ Card.Self | Regeneration$ True | ReplaceWith$ DBRegeneration | Description$ If CARDNAME would be destroyed, regenerate it. +SVar:DBRegeneration:DB$ Regeneration | Defined$ ReplacedCard +A:AB$ Effect | Cost$ 1 | Activator$ Player.Opponent | RememberObjects$ Self | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | AILogic$ CantRegenerate | SpellDescription$ CARDNAME can't be regenerated this turn. Only your opponents may activate this ability. +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. Oracle:If Clergy of the Holy Nimbus would be destroyed, regenerate it.\n{1}: Clergy of the Holy Nimbus can't be regenerated this turn. Only your opponents may activate this ability. diff --git a/forge-gui/res/cardsfolder/d/darksteel_colossus.txt b/forge-gui/res/cardsfolder/d/darksteel_colossus.txt index 92c063b0dfe..fce3ac1f94d 100644 --- a/forge-gui/res/cardsfolder/d/darksteel_colossus.txt +++ b/forge-gui/res/cardsfolder/d/darksteel_colossus.txt @@ -4,5 +4,6 @@ Types:Artifact Creature Golem PT:11/11 K:Trample K:Indestructible -K:If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +R:Event$ Moved | Destination$ Graveyard | ValidCard$ Card.Self | ReplaceWith$ DBShuffle | Description$ If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +SVar:DBShuffle:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Library | Defined$ ReplacedCard | Reveal$ True | Shuffle$ True Oracle:Trample, indestructible\nIf Darksteel Colossus would be put into a graveyard from anywhere, reveal Darksteel Colossus and shuffle it into its owner's library instead. diff --git a/forge-gui/res/cardsfolder/d/debt_of_loyalty.txt b/forge-gui/res/cardsfolder/d/debt_of_loyalty.txt index c0d9ba4d9e0..e7c2a587602 100644 --- a/forge-gui/res/cardsfolder/d/debt_of_loyalty.txt +++ b/forge-gui/res/cardsfolder/d/debt_of_loyalty.txt @@ -1,7 +1,7 @@ Name:Debt of Loyalty ManaCost:1 W W Types:Instant -A:SP$ Regenerate | Cost$ 1 W W | ValidTgts$ Creature | TgtPrompt$ Select target creature | RegenerationTrigger$ TrigGainControl | SpellDescription$ Regenerate target creature. You gain control of that creature if it regenerates this way. -SVar:TrigGainControl:ST$ GainControl | Cost$ 0 | Defined$ TriggeredCard | NewController$ You +A:SP$ Regenerate | Cost$ 1 W W | ValidTgts$ Creature | TgtPrompt$ Select target creature | RegenerationAbility$ TrigGainControl | SpellDescription$ Regenerate target creature. You gain control of that creature if it regenerates this way. +SVar:TrigGainControl:DB$ GainControl | Defined$ ReplacedCard | NewController$ You AI:RemoveDeck:All Oracle:Regenerate target creature. You gain control of that creature if it regenerates this way. diff --git a/forge-gui/res/cardsfolder/d/disintegrate.txt b/forge-gui/res/cardsfolder/d/disintegrate.txt index 89a1dcf8f75..ea6045cab8c 100644 --- a/forge-gui/res/cardsfolder/d/disintegrate.txt +++ b/forge-gui/res/cardsfolder/d/disintegrate.txt @@ -2,6 +2,7 @@ Name:Disintegrate ManaCost:X R Types:Sorcery A:SP$ DealDamage | Cost$ X R | ValidTgts$ Any | NumDmg$ X | SubAbility$ DB | ReplaceDyingDefined$ ThisTargetedCard.Creature | SpellDescription$ CARDNAME deals X damage to any target. That creature can't be regenerated this turn. If the creature would die this turn, exile it instead. -SVar:DB:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ ParentTarget | ConditionDefined$ ParentTarget | ConditionPresent$ Creature +SVar:DB:DB$ Effect | RememberObjects$ ParentTarget | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | ConditionDefined$ ParentTarget | ConditionPresent$ Creature | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. SVar:X:Count$xPaid Oracle:Disintegrate deals X damage to any target. If it's a creature, it can't be regenerated this turn, and if it would die this turn, exile it instead. diff --git a/forge-gui/res/cardsfolder/e/engulfing_flames.txt b/forge-gui/res/cardsfolder/e/engulfing_flames.txt index 039ce78f7be..0612670b5d3 100644 --- a/forge-gui/res/cardsfolder/e/engulfing_flames.txt +++ b/forge-gui/res/cardsfolder/e/engulfing_flames.txt @@ -3,5 +3,6 @@ ManaCost:R Types:Instant K:Flashback:3 R A:SP$ DealDamage | Cost$ R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 1 | SubAbility$ DB | SpellDescription$ CARDNAME deals 1 damage to target creature. It can't be regenerated this turn. -SVar:DB:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ Targeted +SVar:DB:DB$ Effect | RememberObjects$ Targeted | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. Oracle:Engulfing Flames deals 1 damage to target creature. It can't be regenerated this turn.\nFlashback {3}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.) diff --git a/forge-gui/res/cardsfolder/f/faerie_dragon.txt b/forge-gui/res/cardsfolder/f/faerie_dragon.txt index bd249607b8a..a6da28a571d 100644 --- a/forge-gui/res/cardsfolder/f/faerie_dragon.txt +++ b/forge-gui/res/cardsfolder/f/faerie_dragon.txt @@ -33,8 +33,9 @@ SVar:Black:DB$ ChooseCard | Choices$ Permanent | IncludeSpellsOnStack$ True | At SVar:DBAnimateB:DB$ Animate | Defined$ ChosenCard | Colors$ Black | OverwriteColors$ True | Duration$ Permanent | LockInText$ True | SubAbility$ DBCleanup SVar:Blue:DB$ ChooseCard | Choices$ Permanent | IncludeSpellsOnStack$ True | AtRandom$ True | LockInText$ True | SubAbility$ DBAnimateU | SpellDescription$ A spell or permanent chosen at random becomes blue. (Mana symbols on that permanent remain unchanged.) SVar:DBAnimateU:DB$ Animate | Defined$ ChosenCard | Colors$ Blue | OverwriteColors$ True | Duration$ Permanent | LockInText$ True | SubAbility$ DBCleanup -SVar:NoRegen:DB$ ChooseCard | Choices$ Creature | AtRandom$ True | SubAbility$ DBPump13 | SpellDescription$ A creature chosen at random can't be regenerated this turn. -SVar:DBPump13:DB$ Pump | Defined$ ChosenCard | KW$ HIDDEN CARDNAME can't be regenerated. | SubAbility$ DBCleanup +SVar:NoRegen:DB$ ChooseCard | Choices$ Creature | AtRandom$ True | SubAbility$ DBNoRegen | SpellDescription$ A creature chosen at random can't be regenerated this turn. +SVar:DBNoRegen:DB$ Effect | RememberObjects$ ChosenCard | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegenST | IsCurse$ True | StackDescription$ None | SubAbility$ DBCleanup | AILogic$ CantRegenerate +SVar:NoRegenST:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. SVar:LilSneak:DB$ ChooseCard | Choices$ Creature | AtRandom$ True | SubAbility$ DBPump14 | RememberChosen$ True | SpellDescription$ If a creature chosen at random has power 2 or less, it is unblockable this turn. SVar:DBPump14:DB$ Effect | ConditionDefined$ Remembered | ConditionPresent$ Card.powerLE2 | RememberObjects$ Remembered | ExileOnMoved$ Battlefield | StaticAbilities$ Unblockable | SubAbility$ DBCleanup SVar:Unblockable:Mode$ CantBlockBy | ValidAttacker$ Card.IsRemembered | Description$ This creature can't be blocked this turn. diff --git a/forge-gui/res/cardsfolder/f/flamebreak.txt b/forge-gui/res/cardsfolder/f/flamebreak.txt index 61d967acf6f..d0e0bd03232 100644 --- a/forge-gui/res/cardsfolder/f/flamebreak.txt +++ b/forge-gui/res/cardsfolder/f/flamebreak.txt @@ -2,5 +2,6 @@ Name:Flamebreak ManaCost:R R R Types:Sorcery A:SP$ DamageAll | Cost$ R R R | ValidCards$ Creature.withoutFlying | ValidPlayers$ Player | NumDmg$ 3 | RememberDamagedCreature$ True | SubAbility$ DBNoRegen | SpellDescription$ CARDNAME deals 3 damage to each creature without flying and each player. Creatures dealt damage this way can't be regenerated this turn. | StackDescription$ SpellDescription -SVar:DBNoRegen:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ Remembered | StackDescription$ None +SVar:DBNoRegen:DB$ Effect | RememberObjects$ Remembered | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | ConditionDefined$ Remembered | ConditionPresent$ Creature | StackDescription$ None | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. Oracle:Flamebreak deals 3 damage to each creature without flying and each player. Creatures dealt damage this way can't be regenerated this turn. diff --git a/forge-gui/res/cardsfolder/f/forgotten_ancient.txt b/forge-gui/res/cardsfolder/f/forgotten_ancient.txt index 2a17b001427..98a5ca02a30 100644 --- a/forge-gui/res/cardsfolder/f/forgotten_ancient.txt +++ b/forge-gui/res/cardsfolder/f/forgotten_ancient.txt @@ -5,5 +5,5 @@ PT:0/3 T:Mode$ SpellCast | ValidCard$ Card | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever a player casts a spell, you may put a +1/+1 counter on CARDNAME. SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigMoveCounter | TriggerDescription$ At the beginning of your upkeep, you may move any number of +1/+1 counters from CARDNAME onto other creatures. -SVar:TrigMoveCounter:DB$ MoveCounter | Source$ Self | ValidDefined$ Creature.Other | CounterType$ P1P1 | CounterNum$ Any | AiLogic$ ToValid | StackDescription$ You may move any number of +1/+1 counters from CARDNAME onto other creatures. +SVar:TrigMoveCounter:DB$ MoveCounter | Source$ Self | ValidDefined$ Creature.Other | CounterType$ P1P1 | CounterNum$ Any | AILogic$ ToValid | StackDescription$ You may move any number of +1/+1 counters from CARDNAME onto other creatures. Oracle:Whenever a player casts a spell, you may put a +1/+1 counter on Forgotten Ancient.\nAt the beginning of your upkeep, you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures. diff --git a/forge-gui/res/cardsfolder/f/furnace_brood.txt b/forge-gui/res/cardsfolder/f/furnace_brood.txt index 537198d3a5f..c01f5812118 100644 --- a/forge-gui/res/cardsfolder/f/furnace_brood.txt +++ b/forge-gui/res/cardsfolder/f/furnace_brood.txt @@ -2,6 +2,7 @@ Name:Furnace Brood ManaCost:3 R Types:Creature Elemental PT:3/3 -A:AB$ Pump | Cost$ R | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME can't be regenerated. | IsCurse$ True | SpellDescription$ Target creature can't be regenerated this turn. +A:AB$ Effect | Cost$ R | ValidTgts$ Creature | TgtPrompt$ Select target creature | RememberObjects$ Targeted | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | AILogic$ CantRegenerate | SpellDescription$ Target creature can't be regenerated this turn. +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. AI:RemoveDeck:All Oracle:{R}: Target creature can't be regenerated this turn. diff --git a/forge-gui/res/cardsfolder/g/gravebind.txt b/forge-gui/res/cardsfolder/g/gravebind.txt index 976548047ae..3785bc589a1 100644 --- a/forge-gui/res/cardsfolder/g/gravebind.txt +++ b/forge-gui/res/cardsfolder/g/gravebind.txt @@ -1,7 +1,8 @@ Name:Gravebind ManaCost:B Types:Instant -A:SP$ Pump | Cost$ B | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME can't be regenerated. | IsCurse$ True | SubAbility$ DelTrigSlowtrip | SpellDescription$ Target creature can't be regenerated this turn. Draw a card at the beginning of the next turn's upkeep. +A:SP$ Effect | ValidTgts$ Creature | TgtPrompt$ Select target creature | RememberObjects$ Targeted | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | SubAbility$ DelTrigSlowtrip | AILogic$ CantRegenerate | SpellDescription$ Target creature can't be regenerated this turn. Draw a card at the beginning of the next turn's upkeep. +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. SVar:DelTrigSlowtrip:DB$ DelayedTrigger | NextTurn$ True | Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ DrawSlowtrip | TriggerDescription$ Draw a card. SVar:DrawSlowtrip:DB$ Draw | NumCards$ 1 | Defined$ You AI:RemoveDeck:All diff --git a/forge-gui/res/cardsfolder/h/heron_of_hope.txt b/forge-gui/res/cardsfolder/h/heron_of_hope.txt index f9bb88cb89b..0d35e230f7d 100644 --- a/forge-gui/res/cardsfolder/h/heron_of_hope.txt +++ b/forge-gui/res/cardsfolder/h/heron_of_hope.txt @@ -3,7 +3,7 @@ ManaCost:3 W Types:Creature Bird PT:2/3 K:Flying -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AiLogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AILogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. SVar:GainLife:DB$ ReplaceEffect | VarName$ LifeGained | VarValue$ X SVar:X:ReplaceCount$LifeGained/Plus.1 A:AB$ Pump | Cost$ 1 W | Defined$ Self | KW$ Lifelink | SpellDescription$ CARDNAME gains lifelink until end of turn. diff --git a/forge-gui/res/cardsfolder/h/honor_troll.txt b/forge-gui/res/cardsfolder/h/honor_troll.txt index 7bb2f5cc053..b496100a7a8 100644 --- a/forge-gui/res/cardsfolder/h/honor_troll.txt +++ b/forge-gui/res/cardsfolder/h/honor_troll.txt @@ -3,7 +3,7 @@ ManaCost:2 G Types:Creature Troll Druid PT:2/3 K:Vigilance -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AiLogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AILogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. SVar:GainLife:DB$ ReplaceEffect | VarName$ LifeGained | VarValue$ X SVar:X:ReplaceCount$LifeGained/Plus.1 SVar:PlayMain1:True diff --git a/forge-gui/res/cardsfolder/h/hurr_jackal.txt b/forge-gui/res/cardsfolder/h/hurr_jackal.txt index bb9afa19e56..c937f9ab059 100644 --- a/forge-gui/res/cardsfolder/h/hurr_jackal.txt +++ b/forge-gui/res/cardsfolder/h/hurr_jackal.txt @@ -2,6 +2,7 @@ Name:Hurr Jackal ManaCost:R Types:Creature Jackal PT:1/1 -A:AB$ Pump | Cost$ T | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME can't be regenerated. | IsCurse$ True | SpellDescription$ Target creature can't be regenerated this turn. +A:AB$ Effect | Cost$ T | ValidTgts$ Creature | TgtPrompt$ Select target creature | RememberObjects$ Targeted | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | AILogic$ CantRegenerate | SpellDescription$ Target creature can't be regenerated this turn. +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. AI:RemoveDeck:All Oracle:{T}: Target creature can't be regenerated this turn. diff --git a/forge-gui/res/cardsfolder/i/incinerate.txt b/forge-gui/res/cardsfolder/i/incinerate.txt index 21f84a8b690..f1eca1072c1 100644 --- a/forge-gui/res/cardsfolder/i/incinerate.txt +++ b/forge-gui/res/cardsfolder/i/incinerate.txt @@ -1,6 +1,7 @@ Name:Incinerate ManaCost:1 R Types:Instant -A:SP$ DealDamage | Cost$ 1 R | ValidTgts$ Any | NumDmg$ 3 | SubAbility$ DB | SpellDescription$ CARDNAME deals 3 damage to any target. A creature dealt damage this way can't be regenerated this turn. -SVar:DB:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ Targeted +A:SP$ DealDamage | Cost$ 1 R | ValidTgts$ Any | NumDmg$ 3 | SubAbility$ DB | RememberDamagedCreature$ True | SpellDescription$ CARDNAME deals 3 damage to any target. A creature dealt damage this way can't be regenerated this turn. +SVar:DB:DB$ Effect | RememberObjects$ Remembered | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | ConditionDefined$ Remembered | ConditionPresent$ Creature | StackDescription$ None | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. Oracle:Incinerate deals 3 damage to any target. A creature dealt damage this way can't be regenerated this turn. diff --git a/forge-gui/res/cardsfolder/j/jaya_ballard_task_mage.txt b/forge-gui/res/cardsfolder/j/jaya_ballard_task_mage.txt index ffc1955922a..c84ff94db72 100644 --- a/forge-gui/res/cardsfolder/j/jaya_ballard_task_mage.txt +++ b/forge-gui/res/cardsfolder/j/jaya_ballard_task_mage.txt @@ -3,7 +3,8 @@ ManaCost:1 R R Types:Legendary Creature Human Spellshaper PT:2/2 A:AB$ Destroy | Cost$ R T Discard<1/Card> | ValidTgts$ Permanent.Blue | TgtPrompt$ Select target blue permanent | SpellDescription$ Destroy target blue permanent. -A:AB$ DealDamage | Cost$ 1 R T Discard<1/Card> | ValidTgts$ Any | NumDmg$ 3 | SubAbility$ DBNoRegen | SpellDescription$ CARDNAME deals 3 damage to target creature or player. A creature dealt damage this way can't be regenerated this turn. +A:AB$ DealDamage | Cost$ 1 R T Discard<1/Card> | ValidTgts$ Any | NumDmg$ 3 | RememberDamaged$ True | SubAbility$ DBNoRegen | SpellDescription$ CARDNAME deals 3 damage to target creature or player. A creature dealt damage this way can't be regenerated this turn. A:AB$ DamageAll | Cost$ 5 R R T Discard<1/Card> | NumDmg$ 6 | ValidPlayers$ Player | ValidCards$ Creature | ValidDescription$ each creature and each player. | SpellDescription$ CARDNAME deals 6 damage to each creature and each player. -SVar:DBNoRegen:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ Targeted +SVar:DBNoRegen:DB$ Effect | RememberObjects$ Remembered | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | ConditionDefined$ Remembered | ConditionPresent$ Creature | StackDescription$ None | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. Oracle:{R}, {T}, Discard a card: Destroy target blue permanent.\n{1}{R}, {T}, Discard a card: Jaya Ballard, Task Mage deals 3 damage to any target. A creature dealt damage this way can't be regenerated this turn.\n{5}{R}{R}, {T}, Discard a card: Jaya Ballard deals 6 damage to each creature and each player. diff --git a/forge-gui/res/cardsfolder/k/knight_of_dawns_light.txt b/forge-gui/res/cardsfolder/k/knight_of_dawns_light.txt index 6dc386a9e85..fd2584ede5b 100644 --- a/forge-gui/res/cardsfolder/k/knight_of_dawns_light.txt +++ b/forge-gui/res/cardsfolder/k/knight_of_dawns_light.txt @@ -3,7 +3,7 @@ ManaCost:1 W Types:Creature Human Knight PT:2/2 K:First Strike -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AiLogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AILogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. SVar:GainLife:DB$ ReplaceEffect | VarName$ LifeGained | VarValue$ X SVar:X:ReplaceCount$LifeGained/Plus.1 A:AB$ Pump | Cost$ 1 W | Defined$ Self | NumAtt$ +1 | NumDef$ +1 | SpellDescription$ CARDNAME gets +1/+1 until end of turn. diff --git a/forge-gui/res/cardsfolder/k/knight_of_the_holy_nimbus.txt b/forge-gui/res/cardsfolder/k/knight_of_the_holy_nimbus.txt index 58777ccf198..b03315e0bf6 100644 --- a/forge-gui/res/cardsfolder/k/knight_of_the_holy_nimbus.txt +++ b/forge-gui/res/cardsfolder/k/knight_of_the_holy_nimbus.txt @@ -3,6 +3,8 @@ ManaCost:W W Types:Creature Human Rebel Knight PT:2/2 K:Flanking -K:If CARDNAME would be destroyed, regenerate it. -A:AB$ Pump | Cost$ 2 | Activator$ Player.Opponent | Defined$ Self | KW$ HIDDEN CARDNAME can't be regenerated. | IsCurse$ True | SpellDescription$ CARDNAME can't be regenerated this turn. Only your opponents may activate this ability. +R:Event$ Destroy | ActiveZones$ Battlefield | ValidCard$ Card.Self | Regeneration$ True | ReplaceWith$ DBRegeneration | Description$ If CARDNAME would be destroyed, regenerate it. +SVar:DBRegeneration:DB$ Regeneration | Defined$ ReplacedCard +A:AB$ Effect | Cost$ 2 | Activator$ Player.Opponent | RememberObjects$ Self | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | AILogic$ CantRegenerate | SpellDescription$ CARDNAME can't be regenerated this turn. Only your opponents may activate this ability. +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. Oracle:Flanking (Whenever a creature without flanking blocks this creature, the blocking creature gets -1/-1 until end of turn.)\nIf Knight of the Holy Nimbus would be destroyed, regenerate it. (Tap it, remove it from combat, and heal all damage on it.)\n{2}: Knight of the Holy Nimbus can't be regenerated this turn. Only your opponents may activate this ability. diff --git a/forge-gui/res/cardsfolder/l/legacy_weapon.txt b/forge-gui/res/cardsfolder/l/legacy_weapon.txt index 432a3bc074d..01d9845b92b 100644 --- a/forge-gui/res/cardsfolder/l/legacy_weapon.txt +++ b/forge-gui/res/cardsfolder/l/legacy_weapon.txt @@ -2,6 +2,7 @@ Name:Legacy Weapon ManaCost:7 Types:Legendary Artifact A:AB$ ChangeZone | Cost$ W U B R G | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | Origin$ Battlefield | Destination$ Exile | SpellDescription$ Exile target permanent. -K:If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +R:Event$ Moved | Destination$ Graveyard | ValidCard$ Card.Self | ReplaceWith$ DBShuffle | Description$ If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +SVar:DBShuffle:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Library | Defined$ ReplacedCard | Reveal$ True | Shuffle$ True AI:RemoveDeck:Random Oracle:{W}{U}{B}{R}{G}: Exile target permanent.\nIf Legacy Weapon would be put into a graveyard from anywhere, reveal Legacy Weapon and shuffle it into its owner's library instead. diff --git a/forge-gui/res/cardsfolder/l/lich.txt b/forge-gui/res/cardsfolder/l/lich.txt index 2b48719b9d4..97f0ea4353c 100644 --- a/forge-gui/res/cardsfolder/l/lich.txt +++ b/forge-gui/res/cardsfolder/l/lich.txt @@ -5,7 +5,7 @@ R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ SVar:LoseLife:DB$ LoseLife | LifeAmount$ LifeTotal SVar:LifeTotal:Count$YourLifeTotal S:Mode$ Continuous | Affected$ You | AddKeyword$ You don't lose the game for having 0 or less life. | Description$ You don't lose the game for having 0 or less life. -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | AiLogic$ LichDraw | ReplaceWith$ Draw | Description$ If you would gain life, draw that many cards instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | AILogic$ LichDraw | ReplaceWith$ Draw | Description$ If you would gain life, draw that many cards instead. SVar:Draw:DB$ Draw | Defined$ You | NumCards$ X SVar:X:ReplaceCount$LifeGained T:Mode$ DamageDoneOnce | ValidTarget$ You | TriggerZones$ Battlefield | Execute$ TrigLoseOrSac | TriggerDescription$ Whenever you're dealt damage, sacrifice that many nontoken permanents. If you can't, you lose the game. diff --git a/forge-gui/res/cardsfolder/l/lieutenants_of_the_guard.txt b/forge-gui/res/cardsfolder/l/lieutenants_of_the_guard.txt index 9decd599d16..12fe0d6c3b7 100644 --- a/forge-gui/res/cardsfolder/l/lieutenants_of_the_guard.txt +++ b/forge-gui/res/cardsfolder/l/lieutenants_of_the_guard.txt @@ -3,7 +3,7 @@ ManaCost:4 W Types:Creature Human Soldier PT:2/2 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ Council's dilemma — When CARDNAME enters the battlefield, starting with you, each player votes for strength or numbers. Put a +1/+1 counter on CARDNAME for each strength vote and create a 1/1 white Soldier creature token for each numbers vote. -SVar:TrigChangeZone:DB$ Vote | Defined$ Player | StoreVoteNum$ True | VoteType$ Strength,Numbers | SubAbility$ DBVoteStrength | AiLogic$ StrengthOrNumbers +SVar:TrigChangeZone:DB$ Vote | Defined$ Player | StoreVoteNum$ True | VoteType$ Strength,Numbers | SubAbility$ DBVoteStrength | AILogic$ StrengthOrNumbers SVar:DBVoteStrength:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ VoteNumStrength | SubAbility$ DBVoteNumbers SVar:DBVoteNumbers:DB$ Token | TokenAmount$ VoteNumNumbers | TokenScript$ w_1_1_soldier | TokenOwner$ You DeckHas:Ability$Counters|Token diff --git a/forge-gui/res/cardsfolder/l/lim_duls_cohort.txt b/forge-gui/res/cardsfolder/l/lim_duls_cohort.txt index 222d5804c6b..eb588779dbd 100644 --- a/forge-gui/res/cardsfolder/l/lim_duls_cohort.txt +++ b/forge-gui/res/cardsfolder/l/lim_duls_cohort.txt @@ -2,8 +2,9 @@ Name:Lim-Dul's Cohort ManaCost:1 B B Types:Creature Zombie PT:2/3 -T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigBlocks | TriggerDescription$ Whenever Lim-Dûl's Cohort blocks or becomes blocked by a creature, that creature can't be regenerated this turn. -T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigBlocked | Secondary$ True | TriggerDescription$ Whenever Lim-Dûl's Cohort blocks or becomes blocked by a creature, that creature can't be regenerated this turn. -SVar:TrigBlocks:DB$ Pump | Defined$ TriggeredAttackerLKICopy | KW$ HIDDEN CARDNAME can't be regenerated. -SVar:TrigBlocked:DB$ Pump | Defined$ TriggeredBlockerLKICopy | KW$ HIDDEN CARDNAME can't be regenerated. +T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigBlocks | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, that creature can't be regenerated this turn. +T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigBlocked | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, that creature can't be regenerated this turn. +SVar:TrigBlocks:DB$ Effect | RememberObjects$ TriggeredAttackerLKICopy | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | AILogic$ CantRegenerate +SVar:TrigBlocked:DB$ Effect | RememberObjects$ TriggeredBlockerLKICopy | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. Oracle:Whenever Lim-Dûl's Cohort blocks or becomes blocked by a creature, that creature can't be regenerated this turn. diff --git a/forge-gui/res/cardsfolder/l/lim_duls_hex.txt b/forge-gui/res/cardsfolder/l/lim_duls_hex.txt index 35b4334c5d0..73eb8112b14 100644 --- a/forge-gui/res/cardsfolder/l/lim_duls_hex.txt +++ b/forge-gui/res/cardsfolder/l/lim_duls_hex.txt @@ -1,7 +1,7 @@ Name:Lim-Dul's Hex ManaCost:1 B Types:Enchantment -T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRepeat | TriggerDescription$ At the beginning of your upkeep, for each player, Lim-Dûl's Hex deals 1 damage to that player unless they pay {B} or {3}. +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRepeat | TriggerDescription$ At the beginning of your upkeep, for each player, CARDNAME deals 1 damage to that player unless they pay {B} or {3}. SVar:TrigRepeat:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBChoose SVar:DBChoose:DB$ GenericChoice | Defined$ Player.IsRemembered | Choices$ PayB,Pay3 | AILogic$ PayUnlessCost SVar:PayB:DB$ DealDamage | Defined$ Player.IsRemembered | NumDmg$ 1 | UnlessCost$ B | UnlessPayer$ Player.IsRemembered | SpellDescription$ CARDNAME deals 1 damage to you unless you pay {B} diff --git a/forge-gui/res/cardsfolder/l/lim_duls_paladin.txt b/forge-gui/res/cardsfolder/l/lim_duls_paladin.txt index 6a7a844ae38..6824a99c5f2 100644 --- a/forge-gui/res/cardsfolder/l/lim_duls_paladin.txt +++ b/forge-gui/res/cardsfolder/l/lim_duls_paladin.txt @@ -3,7 +3,7 @@ ManaCost:2 B R Types:Creature Human Knight PT:0/3 K:Trample -T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigDiscard | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, you may discard a card. If you don't, sacrifice Lim-Dûl's Paladin and draw a card. +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigDiscard | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, you may discard a card. If you don't, sacrifice CARDNAME and draw a card. SVar:TrigDiscard:DB$ Discard | NumCards$ 1 | Mode$ TgtChoose | Optional$ True | RememberDiscarded$ True | SubAbility$ DBSacrifice SVar:DBSacrifice:DB$ Sacrifice | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | SubAbility$ DBDraw SVar:DBDraw:DB$ Draw | NumCards$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | SubAbility$ DBCleanup diff --git a/forge-gui/res/cardsfolder/m/matopi_golem.txt b/forge-gui/res/cardsfolder/m/matopi_golem.txt index f44c75eb506..04fb3e4fc5d 100644 --- a/forge-gui/res/cardsfolder/m/matopi_golem.txt +++ b/forge-gui/res/cardsfolder/m/matopi_golem.txt @@ -2,7 +2,8 @@ Name:Matopi Golem ManaCost:5 Types:Artifact Creature Golem PT:3/3 -A:AB$ Regenerate | Cost$ 1 | RegenerationTrigger$ TrigPutCounter | SpellDescription$ Regenerate CARDNAME. When it regenerates this way, put a -1/-1 counter on it. -SVar:TrigPutCounter:DB$ PutCounter | Defined$ TriggeredCardLKICopy | CounterType$ M1M1 | CounterNum$ 1 | SpellDescription$ When it regenerates this way, put a -1/-1 counter on it. +A:AB$ Regenerate | Cost$ 1 | RegenerationAbility$ DBImmediateTrigger | StackDescription$ SpellDescription | SpellDescription$ Regenerate CARDNAME. When it regenerates this way, put a -1/-1 counter on it. +SVar:DBImmediateTrigger:DB$ ImmediateTrigger | Execute$ TrigPutCounter | TriggerDescription$ When it regenerates this way, put a -1/-1 counter on it. +SVar:TrigPutCounter:DB$ PutCounter | Defined$ EffectSource | CounterType$ M1M1 | CounterNum$ 1 DeckHas:Ability$Counters Oracle:{1}: Regenerate Matopi Golem. When it regenerates this way, put a -1/-1 counter on it. diff --git a/forge-gui/res/cardsfolder/m/messenger_jays.txt b/forge-gui/res/cardsfolder/m/messenger_jays.txt index 8f243ea2c02..bbeec633ed6 100644 --- a/forge-gui/res/cardsfolder/m/messenger_jays.txt +++ b/forge-gui/res/cardsfolder/m/messenger_jays.txt @@ -4,7 +4,7 @@ Types:Creature Bird PT:2/1 K:Flying T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigVote | TriggerDescription$ Council's dilemma — When CARDNAME enters the battlefield, starting with you, each player votes for feather or quill. Put a +1/+1 counter on CARDNAME for each feather vote and draw a card for each quill vote. For each card drawn this way, discard a card. -SVar:TrigVote:DB$ Vote | Defined$ Player | StoreVoteNum$ True | VoteType$ Feather,Quill | SubAbility$ DBVoteFeather | AiLogic$ FeatherOrQuill +SVar:TrigVote:DB$ Vote | Defined$ Player | StoreVoteNum$ True | VoteType$ Feather,Quill | SubAbility$ DBVoteFeather | AILogic$ FeatherOrQuill SVar:DBVoteFeather:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ VoteNumFeather | SubAbility$ DBVoteQuill SVar:DBVoteQuill:DB$ Draw | NumCards$ VoteNumQuill | SubAbility$ DBDiscard | RememberDrawn$ True SVar:DBDiscard:DB$ Discard | Defined$ You | NumCards$ X | Mode$ TgtChoose | SubAbility$ DBCleanup diff --git a/forge-gui/res/cardsfolder/m/mossbridge_troll.txt b/forge-gui/res/cardsfolder/m/mossbridge_troll.txt index e9630978644..aa3de29b59a 100644 --- a/forge-gui/res/cardsfolder/m/mossbridge_troll.txt +++ b/forge-gui/res/cardsfolder/m/mossbridge_troll.txt @@ -2,6 +2,7 @@ Name:Mossbridge Troll ManaCost:5 G G Types:Creature Troll PT:5/5 -K:If CARDNAME would be destroyed, regenerate it. +R:Event$ Destroy | ActiveZones$ Battlefield | ValidCard$ Card.Self | Regeneration$ True | ReplaceWith$ DBRegeneration | Description$ If CARDNAME would be destroyed, regenerate it. +SVar:DBRegeneration:DB$ Regeneration | Defined$ ReplacedCard A:AB$ Pump | Cost$ tapXType | CostDesc$ Tap any number of untapped creatures you control other than CARDNAME with total power 10 or greater: | Defined$ Self | NumAtt$ +20 | NumDef$ +20 | SpellDescription$ CARDNAME gets +20/+20 until end of turn. Oracle:If Mossbridge Troll would be destroyed, regenerate it.\nTap any number of untapped creatures you control other than Mossbridge Troll with total power 10 or greater: Mossbridge Troll gets +20/+20 until end of turn. diff --git a/forge-gui/res/cardsfolder/n/nefarious_lich.txt b/forge-gui/res/cardsfolder/n/nefarious_lich.txt index a97c4aa87ec..5f5f7ee413c 100644 --- a/forge-gui/res/cardsfolder/n/nefarious_lich.txt +++ b/forge-gui/res/cardsfolder/n/nefarious_lich.txt @@ -8,7 +8,7 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:CheckYard:Count$ValidGraveyard Card.YouOwn SVar:CheckExile:Count$ValidExile Card.IsRemembered SVar:X:ReplaceCount$DamageAmount -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | AiLogic$ LichDraw | ReplaceWith$ Draw | Description$ If you would gain life, draw that many cards instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | AILogic$ LichDraw | ReplaceWith$ Draw | Description$ If you would gain life, draw that many cards instead. SVar:Draw:DB$ Draw | Defined$ You | NumCards$ Y SVar:Y:ReplaceCount$LifeGained T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigLose | TriggerDescription$ When CARDNAME leaves the battlefield, you lose the game. diff --git a/forge-gui/res/cardsfolder/n/nexus_of_fate.txt b/forge-gui/res/cardsfolder/n/nexus_of_fate.txt index 1e6bb99cc58..b348eb121e2 100644 --- a/forge-gui/res/cardsfolder/n/nexus_of_fate.txt +++ b/forge-gui/res/cardsfolder/n/nexus_of_fate.txt @@ -2,5 +2,6 @@ Name:Nexus of Fate ManaCost:5 U U Types:Instant A:SP$ AddTurn | Cost$ 5 U U | NumTurns$ 1 | SpellDescription$ Take an extra turn after this one. -K:If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +R:Event$ Moved | Destination$ Graveyard | ValidCard$ Card.Self | ReplaceWith$ DBShuffle | Description$ If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +SVar:DBShuffle:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Library | Defined$ ReplacedCard | Reveal$ True | Shuffle$ True Oracle:Take an extra turn after this one.\nIf Nexus of Fate would be put into a graveyard from anywhere, reveal Nexus of Fate and shuffle it into its owner's library instead. diff --git a/forge-gui/res/cardsfolder/o/orchard_elemental.txt b/forge-gui/res/cardsfolder/o/orchard_elemental.txt index 35cea2217c2..d9b0f4cdcbd 100644 --- a/forge-gui/res/cardsfolder/o/orchard_elemental.txt +++ b/forge-gui/res/cardsfolder/o/orchard_elemental.txt @@ -3,7 +3,7 @@ ManaCost:5 G Types:Creature Elemental PT:2/2 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ Council's dilemma — When CARDNAME enters the battlefield, starting with you, each player votes for sprout or harvest. Put two +1/+1 counters on CARDNAME for each sprout vote. You gain 3 life for each harvest vote. -SVar:TrigChangeZone:DB$ Vote | Defined$ Player | StoreVoteNum$ True | VoteType$ Sprout,Harvest | SubAbility$ DBVoteSprout | AiLogic$ SproutOrHarvest +SVar:TrigChangeZone:DB$ Vote | Defined$ Player | StoreVoteNum$ True | VoteType$ Sprout,Harvest | SubAbility$ DBVoteSprout | AILogic$ SproutOrHarvest SVar:DBVoteSprout:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ Counters | SubAbility$ DBVoteHarvest SVar:DBVoteHarvest:DB$ GainLife | LifeAmount$ Life | Defined$ You SVar:Counters:SVar$VoteNumSprout/Times.2 diff --git a/forge-gui/res/cardsfolder/o/orcish_healer.txt b/forge-gui/res/cardsfolder/o/orcish_healer.txt index 5117e077539..30d69154a29 100644 --- a/forge-gui/res/cardsfolder/o/orcish_healer.txt +++ b/forge-gui/res/cardsfolder/o/orcish_healer.txt @@ -2,7 +2,8 @@ Name:Orcish Healer ManaCost:R R Types:Creature Orc Cleric PT:1/1 -A:AB$ Pump | Cost$ R R T | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME can't be regenerated. | IsCurse$ True | SpellDescription$ Target creature can't be regenerated this turn. +A:AB$ Effect | Cost$ R R T | ValidTgts$ Creature | TgtPrompt$ Select target creature | RememberObjects$ Targeted | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | AILogic$ CantRegenerate | SpellDescription$ Target creature can't be regenerated this turn. +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. A:AB$ Regenerate | Cost$ B B R T | ValidTgts$ Creature.Black,Creature.Green | TgtPrompt$ Select target black or green creature | SpellDescription$ Regenerate target black or green creature. A:AB$ Regenerate | Cost$ R G G T | ValidTgts$ Creature.Black,Creature.Green | TgtPrompt$ Select target black or green creature | SpellDescription$ Regenerate target black or green creature. AI:RemoveDeck:Random diff --git a/forge-gui/res/cardsfolder/p/plague_drone.txt b/forge-gui/res/cardsfolder/p/plague_drone.txt index bab946188d9..0db7dabb2a9 100644 --- a/forge-gui/res/cardsfolder/p/plague_drone.txt +++ b/forge-gui/res/cardsfolder/p/plague_drone.txt @@ -3,7 +3,7 @@ ManaCost:3 B Types:Creature Demon PT:3/3 K:Flying -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ Opponent | ReplaceWith$ RLoseLife | AiLogic$ LoseLife | Description$ Rot Fly — If an opponent would gain life, that player loses that much life instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ Opponent | ReplaceWith$ RLoseLife | AILogic$ LoseLife | Description$ Rot Fly — If an opponent would gain life, that player loses that much life instead. SVar:RLoseLife:DB$ LoseLife | LifeAmount$ X | Defined$ ReplacedPlayer SVar:X:ReplaceCount$LifeGained SVar:NonStackingEffect:True diff --git a/forge-gui/res/cardsfolder/p/progenitus.txt b/forge-gui/res/cardsfolder/p/progenitus.txt index 3fbbe876a22..857502e443c 100644 --- a/forge-gui/res/cardsfolder/p/progenitus.txt +++ b/forge-gui/res/cardsfolder/p/progenitus.txt @@ -3,5 +3,6 @@ ManaCost:W W U U B B R R G G Types:Legendary Creature Hydra Avatar PT:10/10 K:Protection from everything -K:If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +R:Event$ Moved | Destination$ Graveyard | ValidCard$ Card.Self | ReplaceWith$ DBShuffle | Description$ If CARDNAME would be put into a graveyard from anywhere, reveal CARDNAME and shuffle it into its owner's library instead. +SVar:DBShuffle:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Library | Defined$ ReplacedCard | Reveal$ True | Shuffle$ True Oracle:Protection from everything\nIf Progenitus would be put into a graveyard from anywhere, reveal Progenitus and shuffle it into its owner's library instead. diff --git a/forge-gui/res/cardsfolder/r/rage_of_purphoros.txt b/forge-gui/res/cardsfolder/r/rage_of_purphoros.txt index 2791c09bac8..570689f6df5 100644 --- a/forge-gui/res/cardsfolder/r/rage_of_purphoros.txt +++ b/forge-gui/res/cardsfolder/r/rage_of_purphoros.txt @@ -2,6 +2,7 @@ Name:Rage of Purphoros ManaCost:4 R Types:Sorcery A:SP$ DealDamage | Cost$ 4 R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 4 | SubAbility$ DBPump | SpellDescription$ CARDNAME deals 4 damage to target creature. It can't be regenerated this turn. Scry 1. -SVar:DBPump:DB$ Pump | Defined$ ParentTarget | KW$ HIDDEN CARDNAME can't be regenerated. | SubAbility$ DBScry +SVar:DBPump:DB$ Effect | RememberObjects$ ParentTarget | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | SubAbility$ DBScry | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. SVar:DBScry:DB$ Scry | ScryNum$ 1 Oracle:Rage of Purphoros deals 4 damage to target creature. It can't be regenerated this turn. Scry 1. (Look at the top card of your library. You may put that card on the bottom of your library.) diff --git a/forge-gui/res/cardsfolder/r/rain_of_gore.txt b/forge-gui/res/cardsfolder/r/rain_of_gore.txt index caf532c2b4b..839788bb8e7 100644 --- a/forge-gui/res/cardsfolder/r/rain_of_gore.txt +++ b/forge-gui/res/cardsfolder/r/rain_of_gore.txt @@ -1,7 +1,7 @@ Name:Rain of Gore ManaCost:B R Types:Enchantment -R:Event$ GainLife | ActiveZones$ Battlefield | ValidSource$ SpellAbility | SourceController$ True | AiLogic$ LoseLife | ReplaceWith$ RLoseLife | Description$ If a spell or ability would cause its controller to gain life, that player loses that much life instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidSource$ SpellAbility | SourceController$ True | AILogic$ LoseLife | ReplaceWith$ RLoseLife | Description$ If a spell or ability would cause its controller to gain life, that player loses that much life instead. SVar:RLoseLife:DB$ LoseLife | LifeAmount$ X | Defined$ ReplacedPlayer SVar:X:ReplaceCount$LifeGained SVar:NonStackingEffect:True diff --git a/forge-gui/res/cardsfolder/r/rhox_faithmender.txt b/forge-gui/res/cardsfolder/r/rhox_faithmender.txt index 70ac981a36b..ac4635c72b5 100644 --- a/forge-gui/res/cardsfolder/r/rhox_faithmender.txt +++ b/forge-gui/res/cardsfolder/r/rhox_faithmender.txt @@ -3,7 +3,7 @@ ManaCost:3 W Types:Creature Rhino Monk PT:1/5 K:Lifelink -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainDouble | AiLogic$ DoubleLife | Description$ If you would gain life, you gain twice that much life instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainDouble | AILogic$ DoubleLife | Description$ If you would gain life, you gain twice that much life instead. SVar:GainDouble:DB$ ReplaceEffect | VarName$ LifeGained | VarValue$ X SVar:X:ReplaceCount$LifeGained/Twice SVar:PlayMain1:True diff --git a/forge-gui/res/cardsfolder/r/runesword.txt b/forge-gui/res/cardsfolder/r/runesword.txt index 35605f6f057..0efd016f3d2 100644 --- a/forge-gui/res/cardsfolder/r/runesword.txt +++ b/forge-gui/res/cardsfolder/r/runesword.txt @@ -1,12 +1,11 @@ Name:Runesword ManaCost:6 Types:Artifact -A:AB$ Pump | Cost$ 3 T | NumAtt$ +2 | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | SubAbility$ RuneswordEffect | SpellDescription$ Target attacking creature gets +2/+0 until end of turn. When that creature leaves the battlefield this turn, sacrifice CARDNAME. If the creature deals damage to a creature this turn, the creature dealt damage can't be regenerated this turn. If a creature dealt damage by the targeted creature would die this turn, exile that creature instead. -SVar:RuneswordEffect:DB$ Effect | Name$ Runesword Effect | Triggers$ TrigSacRunesword,TrigNoregen | ReplacementEffects$ RuneswordRep | RememberObjects$ Targeted | ImprintCards$ Self -SVar:TrigSacRunesword:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Battlefield | OneOff$ True | Destination$ Any | Execute$ RuneswordSac | TriggerDescription$ When the targeted creature leaves the battlefield this turn, sacrifice Runesword. -SVar:RuneswordSac:DB$ SacrificeAll | Defined$ ImprintedLKI -SVar:TrigNoregen:Mode$ DamageDone | ValidSource$ Card.IsRemembered | ValidTarget$ Creature | Execute$ PumpNogen | Static$ True | TriggerDescription$ If the creature deals damage to a creature this turn, the creature dealt damage can't be regenerated this turn. -SVar:PumpNogen:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ TriggeredTarget +A:AB$ Pump | Cost$ 3 T | NumAtt$ +2 | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | SubAbility$ RuneDelay | SpellDescription$ Target attacking creature gets +2/+0 until end of turn. When that creature leaves the battlefield this turn, sacrifice CARDNAME. If the creature deals damage to a creature this turn, the creature dealt damage can't be regenerated this turn. If a creature dealt damage by the targeted creature would die this turn, exile that creature instead. +SVar:RuneDelay:DB$ DelayedTrigger | Mode$ ChangesZone | RememberObjects$ Targeted | Origin$ Battlefield | ValidCard$ Card.IsTriggerRemembered | ThisTurn$ True | SubAbility$ RuneswordEffect | Execute$ RuneswordSac | TriggerDescription$ When the targeted creature leaves the battlefield this turn, sacrifice CARDNAME. +SVar:RuneswordSac:DB$ SacrificeAll | Defined$ Self +SVar:RuneswordEffect:DB$ Effect | Name$ Runesword Effect | ReplacementEffects$ RuneswordRep | StaticAbilities$ NoRegen | RememberObjects$ Targeted | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Creature.DamagedBy Remembered | Description$ If the creature deals damage to a creature this turn, the creature dealt damage can't be regenerated this turn. SVar:RuneswordRep:Event$ Moved | ValidLKI$ Creature.DamagedBy Remembered | Destination$ Graveyard | ReplaceWith$ RuneswordExile | Description$ If a creature dealt damage by CARDNAME this turn would die, exile it instead. SVar:RuneswordExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ Exile DeckHas:Ability$Sacrifice diff --git a/forge-gui/res/cardsfolder/s/scorching_lava.txt b/forge-gui/res/cardsfolder/s/scorching_lava.txt index 40563aa9aee..6f7c86ff8b7 100644 --- a/forge-gui/res/cardsfolder/s/scorching_lava.txt +++ b/forge-gui/res/cardsfolder/s/scorching_lava.txt @@ -3,5 +3,6 @@ ManaCost:1 R Types:Instant K:Kicker:R A:SP$ DealDamage | Cost$ 1 R | ValidTgts$ Any | NumDmg$ 2 | ReplaceDyingDefined$ ThisTargetedCard.Creature | ReplaceDyingCondition$ Kicked | SubAbility$ KickingLava | SpellDescription$ CARDNAME deals 2 damage to any target. If this spell was kicked, that creature can't be regenerated this turn and if it would die this turn, exile it instead. -SVar:KickingLava:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ ParentTarget | ConditionDefined$ ParentTarget | ConditionPresent$ Creature | Condition$ Kicked +SVar:KickingLava:DB$ Effect | RememberObjects$ ParentTarget | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen | IsCurse$ True | ConditionDefined$ ParentTarget | ConditionPresent$ Creature | Condition$ Kicked | StackDescription$ None | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. Oracle:Kicker {R} (You may pay an additional {R} as you cast this spell.)\nScorching Lava deals 2 damage to any target. If this spell was kicked, that creature can't be regenerated this turn and if it would die this turn, exile it instead. diff --git a/forge-gui/res/cardsfolder/s/skeleton_scavengers.txt b/forge-gui/res/cardsfolder/s/skeleton_scavengers.txt index 301e7f5f8f8..0e1133cbe02 100644 --- a/forge-gui/res/cardsfolder/s/skeleton_scavengers.txt +++ b/forge-gui/res/cardsfolder/s/skeleton_scavengers.txt @@ -3,8 +3,9 @@ ManaCost:2 B Types:Creature Skeleton PT:0/0 K:etbCounter:P1P1:1 -A:AB$ Regenerate | Cost$ X | CostDesc$ Pay {1} for each +1/+1 counter on CARDNAME: | RegenerationTrigger$ TrigPutCounter | SpellDescription$ Regenerate CARDNAME. When it regenerates this way, put a +1/+1 counter on it. -SVar:TrigPutCounter:DB$ PutCounter | Defined$ TriggeredCardLKICopy | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ When it regenerates this way, put a +1/+1 counter on it. +A:AB$ Regenerate | Cost$ X | CostDesc$ Pay {1} for each +1/+1 counter on CARDNAME: | RegenerationAbility$ DBImmediateTrigger | StackDescription$ SpellDescription | SpellDescription$ Regenerate CARDNAME. When it regenerates this way, put a +1/+1 counter on it. +SVar:DBImmediateTrigger:DB$ ImmediateTrigger | Execute$ TrigPutCounter | TriggerDescription$ When it regenerates this way, put a +1/+1 counter on it. +SVar:TrigPutCounter:DB$ PutCounter | Defined$ EffectSource | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ When it regenerates this way, put a +1/+1 counter on it. SVar:X:Count$CardCounters.P1P1 DeckHas:Ability$Counters Oracle:Skeleton Scavengers enters the battlefield with a +1/+1 counter on it.\nPay {1} for each +1/+1 counter on Skeleton Scavengers: Regenerate Skeleton Scavengers. When it regenerates this way, put a +1/+1 counter on it. diff --git a/forge-gui/res/cardsfolder/s/soldevi_sentry.txt b/forge-gui/res/cardsfolder/s/soldevi_sentry.txt index bfe9f2051fe..11ea49de6b6 100644 --- a/forge-gui/res/cardsfolder/s/soldevi_sentry.txt +++ b/forge-gui/res/cardsfolder/s/soldevi_sentry.txt @@ -2,6 +2,7 @@ Name:Soldevi Sentry ManaCost:1 Types:Artifact Creature Soldier PT:1/1 -A:AB$ Regenerate | Cost$ 1 | ValidTgts$ Opponent | Defined$ Self | RegenerationTrigger$ TrigDraw | RememberObjects$ TargetedPlayer | SpellDescription$ Choose target opponent. Regenerate CARDNAME. When it regenerates this way, that player may draw a card. -SVar:TrigDraw:DB$ Draw | Defined$ Remembered | NumCards$ 1 | OptionalDecider$ True | SpellDescription$ When it regenerates this way, that player may draw a card. +A:AB$ Regenerate | Cost$ 1 | ValidTgts$ Opponent | Defined$ Self | RegenerationAbility$ DBImmediateTrigger | RememberObjects$ TargetedPlayer | StackDescription$ SpellDescription | SpellDescription$ Choose target opponent. Regenerate CARDNAME. When it regenerates this way, that player may draw a card. +SVar:DBImmediateTrigger:DB$ ImmediateTrigger | RememberObjects$ Remembered | Execute$ TrigDraw | TriggerDescription$ When it regenerates this way, that player may draw a card. +SVar:TrigDraw:DB$ Draw | Defined$ DelayTriggerRemembered | NumCards$ 1 | OptionalDecider$ True | SpellDescription$ When it regenerates this way, that player may draw a card. Oracle:{1}: Choose target opponent. Regenerate Soldevi Sentry. When it regenerates this way, that player may draw a card. diff --git a/forge-gui/res/cardsfolder/s/sulfuric_vortex.txt b/forge-gui/res/cardsfolder/s/sulfuric_vortex.txt index 1633479fca3..b084b4e5236 100644 --- a/forge-gui/res/cardsfolder/s/sulfuric_vortex.txt +++ b/forge-gui/res/cardsfolder/s/sulfuric_vortex.txt @@ -3,5 +3,5 @@ ManaCost:1 R R Types:Enchantment T:Mode$ Phase | Phase$ Upkeep | TriggerZones$ Battlefield | Execute$ TrigDmg | TriggerDescription$ At the beginning of each player's upkeep, CARDNAME deals 2 damage to that player. SVar:TrigDmg:DB$ DealDamage | Defined$ TriggeredPlayer | NumDmg$ 2 -R:Event$ GainLife | ActiveZones$ Battlefield | Prevent$ True | AiLogic$ NoLife | Description$ If a player would gain life, that player gains no life instead. +R:Event$ GainLife | ActiveZones$ Battlefield | Prevent$ True | AILogic$ NoLife | Description$ If a player would gain life, that player gains no life instead. Oracle:At the beginning of each player's upkeep, Sulfuric Vortex deals 2 damage to that player.\nIf a player would gain life, that player gains no life instead. diff --git a/forge-gui/res/cardsfolder/t/tainted_remedy.txt b/forge-gui/res/cardsfolder/t/tainted_remedy.txt index 51d0efc43b3..c5ac9c91f29 100644 --- a/forge-gui/res/cardsfolder/t/tainted_remedy.txt +++ b/forge-gui/res/cardsfolder/t/tainted_remedy.txt @@ -1,7 +1,7 @@ Name:Tainted Remedy ManaCost:2 B Types:Enchantment -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ Opponent | ReplaceWith$ RLoseLife | AiLogic$ LoseLife | Description$ If an opponent would gain life, that player loses that much life instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ Opponent | ReplaceWith$ RLoseLife | AILogic$ LoseLife | Description$ If an opponent would gain life, that player loses that much life instead. SVar:RLoseLife:DB$ LoseLife | LifeAmount$ X | Defined$ ReplacedPlayer SVar:X:ReplaceCount$LifeGained SVar:NonStackingEffect:True diff --git a/forge-gui/res/cardsfolder/t/tekuthal_inquiry_dominus.txt b/forge-gui/res/cardsfolder/t/tekuthal_inquiry_dominus.txt index 55bf45c7077..7e60ba3439e 100644 --- a/forge-gui/res/cardsfolder/t/tekuthal_inquiry_dominus.txt +++ b/forge-gui/res/cardsfolder/t/tekuthal_inquiry_dominus.txt @@ -3,7 +3,7 @@ ManaCost:2 U U Types:Legendary Creature Phyrexian Horror PT:3/5 K:Flying -R:Event$ Proliferate | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ ProlifTwice | AiLogic$ DoubleLife | Description$ If you would proliferate, proliferate twice instead. +R:Event$ Proliferate | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ ProlifTwice | AILogic$ DoubleLife | Description$ If you would proliferate, proliferate twice instead. SVar:ProlifTwice:DB$ ReplaceEffect | VarName$ Num | VarValue$ ReplaceCount$Num/Twice A:AB$ PutCounter | Cost$ 1 UP UP RemoveAnyCounter<3/Any/Artifact.Other;Creature.Other;Planeswalker.Other/among other artifacts, creatures, and planeswalkers> | CounterType$ Indestructible | SpellDescription$ Put an indestructible counter on CARDNAME. ({U/P} can be paid with either {U} or 2 life.) DeckHints:Type$Artifact|Planeswalker & Ability$Proliferate diff --git a/forge-gui/res/cardsfolder/upcoming/bilbo_birthday_celebrant.txt b/forge-gui/res/cardsfolder/upcoming/bilbo_birthday_celebrant.txt index c77bddbf8f6..f8fcea72e81 100644 --- a/forge-gui/res/cardsfolder/upcoming/bilbo_birthday_celebrant.txt +++ b/forge-gui/res/cardsfolder/upcoming/bilbo_birthday_celebrant.txt @@ -2,7 +2,7 @@ Name:Bilbo, Birthday Celebrant ManaCost:W B G Types:Legendary Creature Halfling Rogue PT:2/3 -R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AiLogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. +R:Event$ GainLife | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GainLife | AILogic$ DoubleLife | Description$ If you would gain life, you gain that much life plus 1 instead. SVar:GainLife:DB$ ReplaceEffect | VarName$ LifeGained | VarValue$ X SVar:X:ReplaceCount$LifeGained/Plus.1 A:AB$ ChangeZone | Cost$ 2 W B G T Exile<1/CARDNAME> | Origin$ Library | Destination$ Battlefield | ChangeType$ Creature | ChangeNum$ Y | Shuffle$ True | CheckSVar$ Z | SVarCompare$ GE111 | SpellDescription$ Search your library for any number of creature cards, put them onto the battlefield, then shuffle. Activate only if you have 111 or more life. diff --git a/forge-gui/res/cardsfolder/upcoming/phial_of_galadriel.txt b/forge-gui/res/cardsfolder/upcoming/phial_of_galadriel.txt index 3d6d43dc0f2..99ecbe2f7c8 100644 --- a/forge-gui/res/cardsfolder/upcoming/phial_of_galadriel.txt +++ b/forge-gui/res/cardsfolder/upcoming/phial_of_galadriel.txt @@ -3,7 +3,7 @@ ManaCost:3 Types:Legendary Artifact R:Event$ Draw | ActiveZones$ Battlefield | ValidPlayer$ You | Hellbent$ True | ReplaceWith$ DrawTwo | Description$ If you would draw a card while you have no cards in hand, draw two cards instead. SVar:DrawTwo:DB$ Draw | NumCards$ 2 -R:Event$ GainLife | ActiveZones$ Battlefield | CheckSVar$ Y | SVarCompare$ LE5 | ValidPlayer$ You | ReplaceWith$ GainDouble | AiLogic$ DoubleLife | Description$ If you would gain life while you have 5 or less life, you gain twice that much life instead. +R:Event$ GainLife | ActiveZones$ Battlefield | CheckSVar$ Y | SVarCompare$ LE5 | ValidPlayer$ You | ReplaceWith$ GainDouble | AILogic$ DoubleLife | Description$ If you would gain life while you have 5 or less life, you gain twice that much life instead. SVar:GainDouble:DB$ ReplaceEffect | VarName$ LifeGained | VarValue$ X SVar:X:ReplaceCount$LifeGained/Twice SVar:Y:Count$YourLifeTotal diff --git a/forge-gui/res/cardsfolder/w/whippoorwill.txt b/forge-gui/res/cardsfolder/w/whippoorwill.txt index e4501430aca..b5729d7d8fd 100644 --- a/forge-gui/res/cardsfolder/w/whippoorwill.txt +++ b/forge-gui/res/cardsfolder/w/whippoorwill.txt @@ -2,9 +2,10 @@ Name:Whippoorwill ManaCost:G Types:Creature Bird PT:1/1 -A:AB$ Pump | Cost$ G G T | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Curse | KW$ HIDDEN CARDNAME can't be regenerated. & HIDDEN Damage that would be dealt to CARDNAME can't be redirected. | SubAbility$ DBEffect | StackDescription$ {c:Targeted} can't be regenerated this turn. Damage that would be dealt to that card this turn can't be prevented or dealt instead to another permanent or player. | SpellDescription$ Target creature can't be regenerated this turn. Damage that would be dealt to that creature this turn can't be prevented or dealt instead to another permanent or player. When the creature dies this turn, exile the creature. -SVar:DBEffect:DB$ Effect | Name$ Whippoorwill Effect | EffectOwner$ TargetedOwner | RememberObjects$ Targeted | StaticAbilities$ NoPrevent | SubAbility$ DBDelayedTrigger -SVar:NoPrevent:Mode$ CantPreventDamage | Affected$ Creature.IsRemembered | EffectZone$ Command | Description$ Damage that would be dealt to that creature this turn can't be prevented. +A:AB$ Pump | Cost$ G G T | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Curse | KW$ HIDDEN Damage that would be dealt to CARDNAME can't be redirected. | SubAbility$ DBEffect | StackDescription$ {c:Targeted} can't be regenerated this turn. Damage that would be dealt to that card this turn can't be prevented or dealt instead to another permanent or player. | SpellDescription$ Target creature can't be regenerated this turn. Damage that would be dealt to that creature this turn can't be prevented or dealt instead to another permanent or player. When the creature dies this turn, exile the creature. +SVar:DBEffect:DB$ Effect | Name$ Whippoorwill Effect | EffectOwner$ TargetedOwner | RememberObjects$ Targeted | ForgetOnMoved$ Battlefield | StaticAbilities$ NoRegen,NoPrevent | SubAbility$ DBDelayedTrigger | AILogic$ CantRegenerate +SVar:NoRegen:Mode$ CantRegenerate | ValidCard$ Card.IsRemembered | Description$ Creature can't be regenerated this turn. +SVar:NoPrevent:Mode$ CantPreventDamage | Affected$ Creature.IsRemembered | Description$ Damage that would be dealt to that creature this turn can't be prevented. SVar:DBDelayedTrigger:DB$ DelayedTrigger | Mode$ ChangesZone | RememberObjects$ Targeted | ValidCard$ Card.IsTriggerRemembered | Origin$ Battlefield | Destination$ Graveyard | ThisTurn$ True | Execute$ TrigExile | TriggerDescription$ When the creature dies this turn, exile the creature. SVar:TrigExile:DB$ ChangeZone | Defined$ TriggeredCard | Origin$ Graveyard | Destination$ Exile Oracle:{G}{G},{T}: Target creature can't be regenerated this turn. Damage that would be dealt to that creature this turn can't be prevented or dealt instead to another permanent or player. When the creature dies this turn, exile the creature. \ No newline at end of file diff --git a/forge-gui/res/lists/NonStackingKWList.txt b/forge-gui/res/lists/NonStackingKWList.txt index 19778734af7..724d42bbccd 100644 --- a/forge-gui/res/lists/NonStackingKWList.txt +++ b/forge-gui/res/lists/NonStackingKWList.txt @@ -1,7 +1,6 @@ All creatures able to block CARDNAME do so. Banding CARDNAME's activated abilities can't be activated. -CARDNAME can't be regenerated. CARDNAME must be blocked if able. CARDNAME doesn't untap during your untap step. Changeling