From 2025487c34add1368ce3aea21491609d2a2f5a43 Mon Sep 17 00:00:00 2001 From: tool4ever Date: Wed, 23 Aug 2023 10:34:50 +0200 Subject: [PATCH] Fix getTotalPreventionShieldAmount (#3654) * Fix scripts * Fix damage prevention display * Optimize attachment tracking for netplay * Phasing fix * Fix NPE * Tweak logic order * Clean up * Fix scripts * Clean up * Fix FailedToTarget --------- Co-authored-by: TRT <> --- .../main/java/forge/ai/ComputerUtilCost.java | 6 ++-- .../forge/ai/ability/DamagePreventAi.java | 2 +- .../main/java/forge/ai/ability/EffectAi.java | 1 + .../java/forge/ai/ability/ManaEffectAi.java | 5 ++-- .../main/java/forge/game/GameEntityView.java | 28 +++++++++---------- .../java/forge/game/ability/AbilityUtils.java | 15 +++++----- .../effects/DamagePreventEffectBase.java | 18 +++++++++--- .../src/main/java/forge/game/card/Card.java | 2 +- .../java/forge/game/card/CardDamageMap.java | 6 ++++ .../forge/game/combat/AttackConstraints.java | 2 +- .../src/main/java/forge/game/phase/Untap.java | 5 ++-- .../game/replacement/ReplacementEffect.java | 1 - .../game/replacement/ReplacementHandler.java | 3 +- .../forge/trackable/TrackableProperty.java | 1 - .../main/java/forge/view/arcane/PlayArea.java | 17 ++++++----- forge-gui/res/cardsfolder/b/break_of_day.txt | 3 +- forge-gui/res/cardsfolder/o/ogre_slumlord.txt | 2 +- .../o/omarthis_ghostfire_initiate.txt | 2 +- .../res/cardsfolder/o/one_with_the_kami.txt | 2 +- .../res/cardsfolder/t/treasure_nabber.txt | 2 +- .../res/cardsfolder/u/unexpected_allies.txt | 2 +- .../gamemodes/match/input/InputAttack.java | 5 ++-- 22 files changed, 74 insertions(+), 56 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java index ab5f6ee1406..bb79e11f123 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java @@ -398,10 +398,8 @@ public class ComputerUtilCost { return false; } for (final CostPart part : cost.getCostParts()) { - if (part instanceof CostSacrifice) { - if ("CARDNAME".equals(part.getType())) { - return true; - } + if (part instanceof CostSacrifice && part.payCostFromSource()) { + return true; } } return false; diff --git a/forge-ai/src/main/java/forge/ai/ability/DamagePreventAi.java b/forge-ai/src/main/java/forge/ai/ability/DamagePreventAi.java index 1980ba91303..b8ecd9b6f96 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamagePreventAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamagePreventAi.java @@ -85,7 +85,7 @@ public class DamagePreventAi extends SpellAbilityAi { // check stack for something on the stack will kill anything i control final List objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa); - if (objects.contains(ai)) { + if (objects.contains(ai) && sa.canTarget(ai)) { tcs.add(ai); chance = true; } 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 b0fe07d4dcf..c5c81824b52 100644 --- a/forge-ai/src/main/java/forge/ai/ability/EffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/EffectAi.java @@ -216,6 +216,7 @@ public class EffectAi extends SpellAbilityAi { } else if (logic.equals("Fight")) { return FightAi.canFightAi(ai, sa, 0, 0); } else if (logic.equals("Pump")) { + sa.resetTargets(); List options = CardUtil.getValidCardsToTarget(sa); options = CardLists.filterControlledBy(options, ai); if (sa.getPayCosts().hasTapCost()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java b/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java index 17cc2f8ed75..371cbca3a1d 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ManaEffectAi.java @@ -89,7 +89,7 @@ public class ManaEffectAi extends SpellAbilityAi { if (logic.startsWith("ManaRitual")) { return ph.is(PhaseType.MAIN2, ai) || ph.is(PhaseType.MAIN1, ai); } else if ("AtOppEOT".equals(logic)) { - return !ai.getManaPool().hasBurn() && ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai; + return (!ai.getManaPool().hasBurn() || !ai.canLoseLife() || ai.cantLoseForZeroOrLessLife()) && ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai; } return super.checkPhaseRestrictions(ai, sa, ph, logic); } @@ -261,7 +261,8 @@ public class ManaEffectAi extends SpellAbilityAi { } private boolean improvesPosition(Player ai, SpellAbility sa) { - boolean activateForTrigger = Iterables.any(Iterables.filter(sa.getHostCard().getTriggers(), CardTraitPredicates.hasParam("AILogic", "ActivateOnce")), + boolean activateForTrigger = (!ai.getManaPool().hasBurn() || !ai.canLoseLife() || ai.cantLoseForZeroOrLessLife()) && + Iterables.any(Iterables.filter(sa.getHostCard().getTriggers(), CardTraitPredicates.hasParam("AILogic", "ActivateOnce")), t -> sa.getHostCard().getAbilityActivatedThisTurn(t.getOverridingAbility()) == 0); PhaseHandler ph = ai.getGame().getPhaseHandler(); diff --git a/forge-game/src/main/java/forge/game/GameEntityView.java b/forge-game/src/main/java/forge/game/GameEntityView.java index 282d28c8a1b..81b02a64c33 100644 --- a/forge-game/src/main/java/forge/game/GameEntityView.java +++ b/forge-game/src/main/java/forge/game/GameEntityView.java @@ -1,6 +1,7 @@ package forge.game; -import forge.game.card.CardCollectionView; +import com.google.common.collect.Iterables; + import forge.game.card.CardView; import forge.trackable.TrackableCollection; import forge.trackable.TrackableObject; @@ -45,35 +46,34 @@ public abstract class GameEntityView extends TrackableObject { public int getPreventNextDamage() { return get(TrackableProperty.PreventNextDamage); } - protected void updatePreventNextDamage(GameEntity e) { + public void updatePreventNextDamage(GameEntity e) { set(TrackableProperty.PreventNextDamage, e.getPreventNextDamageTotalShields()); } public Iterable getAttachedCards() { - return get(TrackableProperty.AttachedCards); + if (hasAnyCardAttachments()) { + Iterable active = Iterables.filter(get(TrackableProperty.AttachedCards), c -> !c.isPhasedOut()); + if (!Iterables.isEmpty(active)) { + return active; + } + } + return null; } public boolean hasCardAttachments() { return getAttachedCards() != null; } public Iterable getAllAttachedCards() { - return get(TrackableProperty.AllAttachedCards); + return get(TrackableProperty.AttachedCards); } public boolean hasAnyCardAttachments() { return getAllAttachedCards() != null; } protected void updateAttachedCards(GameEntity e) { - if (e.hasCardAttachments()) { - set(TrackableProperty.AttachedCards, CardView.getCollection(e.getAttachedCards())); - } - else { - set(TrackableProperty.AttachedCards, null); - } - CardCollectionView all = e.getAllAttachedCards(); - if (all.isEmpty()) { - set(TrackableProperty.AllAttachedCards, null); + if (!e.getAllAttachedCards().isEmpty()) { + set(TrackableProperty.AttachedCards, CardView.getCollection(e.getAllAttachedCards())); } else { - set(TrackableProperty.AllAttachedCards, CardView.getCollection(all)); + set(TrackableProperty.AttachedCards, null); } } } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index c02a7fb0bd0..aa50861ceb3 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -1999,13 +1999,6 @@ public class AbilityUtils { return doXMath(calculateAmount(c, sq[c.isOptionalCostPaid(OptionalCost.Generic) ? 1 : 2], ctb), expr, c, ctb); } - if (sq[0].equals("TotalDamageDoneByThisTurn")) { - return doXMath(c.getTotalDamageDoneBy(), expr, c, ctb); - } - if (sq[0].equals("TotalDamageReceivedThisTurn")) { - return doXMath(c.getAssignedDamage(), expr, c, ctb); - } - if (sq[0].contains("CardPower")) { return doXMath(c.getNetPower(), expr, c, ctb); } @@ -2335,6 +2328,13 @@ public class AbilityUtils { return doXMath(player.getOpponentsTotalPoisonCounters(), expr, c, ctb); } + if (sq[0].equals("TotalDamageDoneByThisTurn")) { + return doXMath(c.getTotalDamageDoneBy(), expr, c, ctb); + } + if (sq[0].equals("TotalDamageReceivedThisTurn")) { + return doXMath(c.getAssignedDamage(), expr, c, ctb); + } + if (sq[0].equals("MaxOppDamageThisTurn")) { return doXMath(player.getMaxOpponentAssignedDamage(), expr, c, ctb); } @@ -3493,6 +3493,7 @@ public class AbilityUtils { if (value.equals("RingTemptedYou")) { return doXMath(player.getNumRingTemptedYou(), m, source, ctb); } + if (value.startsWith("DungeonCompletedNamed")) { String [] full = value.split("_"); String name = full[1]; diff --git a/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffectBase.java index 4b47945ebf0..c7b1e2c5aaf 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DamagePreventEffectBase.java @@ -4,12 +4,13 @@ import java.util.List; import forge.GameCommand; import forge.game.Game; -import forge.game.GameObject; +import forge.game.GameEntity; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; +import forge.game.event.GameEventPlayerStatsChanged; import forge.game.player.Player; import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementHandler; @@ -20,7 +21,7 @@ import forge.game.zone.ZoneType; import forge.util.TextUtil; public abstract class DamagePreventEffectBase extends SpellAbilityEffect { - public static void addPreventNextDamage(SpellAbility sa, GameObject o, int numDam) { + public static void addPreventNextDamage(SpellAbility sa, GameEntity o, int numDam) { final Card hostCard = sa.getHostCard(); final Game game = hostCard.getGame(); final Player player = hostCard.getController(); @@ -40,9 +41,9 @@ public abstract class DamagePreventEffectBase extends SpellAbilityEffect { if (sa.hasParam("PreventionSubAbility")) { String subAbString = sa.getSVar(sa.getParam("PreventionSubAbility")); if (sa.hasParam("ShieldEffectTarget")) { - List effTgts = AbilityUtils.getDefinedObjects(hostCard, sa.getParam("ShieldEffectTarget"), sa); + List effTgts = AbilityUtils.getDefinedEntities(hostCard, sa.getParam("ShieldEffectTarget"), sa); String effTgtString = ""; - for (final GameObject effTgt : effTgts) { + for (final GameEntity effTgt : effTgts) { if (effTgt instanceof Card) { effTgtString = "CardUID_" + String.valueOf(((Card) effTgt).getId()); } else if (effTgt instanceof Player) { @@ -70,12 +71,21 @@ public abstract class DamagePreventEffectBase extends SpellAbilityEffect { eff.updateStateForView(); game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone); + o.getView().updatePreventNextDamage(o); + if (o instanceof Player) { + game.fireEvent(new GameEventPlayerStatsChanged((Player) o, false)); + } + game.getEndOfTurn().addUntil(new GameCommand() { private static final long serialVersionUID = 1L; @Override public void run() { game.getAction().exile(eff, null); + o.getView().updatePreventNextDamage(o); + if (o instanceof Player) { + game.fireEvent(new GameEventPlayerStatsChanged((Player) o, false)); + } } }); } 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 55a82d9840c..38af7234849 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -5636,7 +5636,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { /** * Gets the total damage done by card this turn (after prevention and redirects). * - * @return the damage done to player p this turn + * @return the damage done by the card this turn */ public final int getTotalDamageDoneBy() { return getDamageHistory().getDamageDoneThisTurn(null, false, null, null, this, getController(), null); diff --git a/forge-game/src/main/java/forge/game/card/CardDamageMap.java b/forge-game/src/main/java/forge/game/card/CardDamageMap.java index 128ef62066f..f48113215e4 100644 --- a/forge-game/src/main/java/forge/game/card/CardDamageMap.java +++ b/forge-game/src/main/java/forge/game/card/CardDamageMap.java @@ -19,6 +19,7 @@ import forge.game.Game; import forge.game.GameEntity; import forge.game.GameObjectPredicates; import forge.game.ability.AbilityKey; +import forge.game.event.GameEventPlayerStatsChanged; import forge.game.player.Player; import forge.game.player.PlayerCollection; import forge.game.spellability.SpellAbility; @@ -48,6 +49,11 @@ public class CardDamageMap extends ForwardingTable { runParams.put(AbilityKey.IsCombatDamage, isCombat); ge.getGame().getTriggerHandler().runTrigger(TriggerType.DamagePreventedOnce, runParams, false); + + ge.getView().updatePreventNextDamage(ge); + if (ge instanceof Player) { + ge.getGame().fireEvent(new GameEventPlayerStatsChanged((Player) ge, false)); + } } } } diff --git a/forge-game/src/main/java/forge/game/combat/AttackConstraints.java b/forge-game/src/main/java/forge/game/combat/AttackConstraints.java index 5d54f22ffd3..44208b937c7 100644 --- a/forge-game/src/main/java/forge/game/combat/AttackConstraints.java +++ b/forge-game/src/main/java/forge/game/combat/AttackConstraints.java @@ -362,7 +362,6 @@ public class AttackConstraints { MapToAmount sortedPlayerReqs = new LinkedHashMapToAmount<>(); sortedPlayerReqs.addAll(Iterables.concat(playerReqs)); while (!sortedPlayerReqs.isEmpty()) { - sortedPlayerReqs.keySet().removeAll(excludedDefenders); Pair playerReq = MapToAmountUtil.max(sortedPlayerReqs); // find best attack to also fulfill the additional requirements Attack bestMatch = Iterables.getLast(Iterables.filter(result, att -> !usedAttackers.contains(att.attacker) && att.defender.equals(playerReq.getLeft())), null); @@ -376,6 +375,7 @@ public class AttackConstraints { } else { excludedDefenders.add(playerReq.getLeft()); } + sortedPlayerReqs.keySet().removeAll(excludedDefenders); } if (!usedAttackers.isEmpty()) { // order could have changed diff --git a/forge-game/src/main/java/forge/game/phase/Untap.java b/forge-game/src/main/java/forge/game/phase/Untap.java index b93ae6cf318..0a0d165a38a 100644 --- a/forge-game/src/main/java/forge/game/phase/Untap.java +++ b/forge-game/src/main/java/forge/game/phase/Untap.java @@ -42,6 +42,7 @@ import forge.game.keyword.KeywordInterface; import forge.game.player.Player; import forge.game.player.PlayerController.BinaryChoiceType; import forge.game.spellability.SpellAbility; +import forge.game.staticability.StaticAbilityCantPhaseOut; import forge.game.zone.ZoneType; /** @@ -266,14 +267,14 @@ public class Untap extends Phase { // If c is attached to something, it will phase out on its own, and try // to attach back to that thing when it comes back for (final Card c : list) { - if (c.isPhasedOut()) { + if (c.isPhasedOut() && c.isDirectlyPhasedOut()) { c.phase(true); } else if (c.hasKeyword(Keyword.PHASING)) { // CR 702.26h If an object would simultaneously phase out directly // and indirectly, it just phases out indirectly. if (c.isAttachment()) { final Card ent = c.getAttachedTo(); - if (ent != null && list.contains(ent)) { + if (ent != null && list.contains(ent) && !StaticAbilityCantPhaseOut.cantPhaseOut(ent)) { continue; } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java b/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java index 7b6448d9990..5909b7bdb9e 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java @@ -145,7 +145,6 @@ public abstract class ReplacementEffect extends TriggerReplacementBase { public boolean requirementsCheck(Game game) { return this.requirementsCheck(game, this.getMapParams()); } - public boolean requirementsCheck(Game game, Map params) { if (this.isSuppressed()) { return false; // Effect removed by effect diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java index 2d2d322951a..72b823a035d 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java @@ -911,7 +911,8 @@ public class ReplacementHandler { && re.hasParam("PreventionEffect") && re.zonesCheck(game.getZoneOf(c)) && re.getOverridingAbility() != null - && re.getOverridingAbility().getApi() == ApiType.ReplaceDamage) { + && re.getOverridingAbility().getApi() == ApiType.ReplaceDamage + && re.matchesValidParam("ValidTarget", o)) { list.add(re); } } diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index c573634a63b..2922e342836 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -14,7 +14,6 @@ public enum TrackableProperty { Text(TrackableTypes.StringType), PreventNextDamage(TrackableTypes.IntegerType), AttachedCards(TrackableTypes.CardViewCollectionType), - AllAttachedCards(TrackableTypes.CardViewCollectionType), Counters(TrackableTypes.CounterMapType), CurrentPlane(TrackableTypes.StringType), PlanarPlayer(TrackableTypes.PlayerViewType), diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java b/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java index b1c864eff14..67ca4f6680c 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java @@ -595,8 +595,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen Iterable cards = model.getCards(zone); if (cards != null) { modelCopy = Lists.newArrayList(cards); - } - else { + } else { modelCopy = Lists.newArrayList(); } } @@ -648,17 +647,17 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen doLayout(); } - invalidate(); //pfps do the extra invalidate before any scrolling + invalidate(); //pfps do the extra invalidate before any scrolling if (!newPanels.isEmpty()) { - int i = newPanels.size(); + int i = newPanels.size(); for (final CardPanel toPanel : newPanels) { - if ( --i == 0 ) { // only scroll to last panel to be added - scrollRectToVisible(new Rectangle(toPanel.getCardX(), toPanel.getCardY(), toPanel.getCardWidth(), toPanel.getCardHeight())); - } + if ( --i == 0 ) { // only scroll to last panel to be added + scrollRectToVisible(new Rectangle(toPanel.getCardX(), toPanel.getCardY(), toPanel.getCardWidth(), toPanel.getCardHeight())); + } Animation.moveCard(toPanel); } - } - repaint(); + } + repaint(); } public boolean updateCard(final CardView card, boolean fromRefresh) { diff --git a/forge-gui/res/cardsfolder/b/break_of_day.txt b/forge-gui/res/cardsfolder/b/break_of_day.txt index a641c786fb3..23b72c9210a 100644 --- a/forge-gui/res/cardsfolder/b/break_of_day.txt +++ b/forge-gui/res/cardsfolder/b/break_of_day.txt @@ -2,5 +2,6 @@ Name:Break of Day ManaCost:1 W Types:Instant A:SP$ PumpAll | Cost$ 1 W | ValidCards$ Creature.YouCtrl | NumAtt$ +1 | NumDef$ +1 | SubAbility$ FatefulHourPump | SpellDescription$ Creatures you control get +1/+1 until end of turn. -SVar:FatefulHourPump:DB$ PumpAll | ValidCards$ Creature.YouCtrl | KW$ Indestructible | FatefulHour$ True | SpellDescription$ Fateful hour — If you have 5 or less life, those creatures gain indestructible until end of turn. +SVar:FatefulHourPump:DB$ PumpAll | ValidCards$ Creature.YouCtrl | KW$ Indestructible | ConditionCheckSVar$ FatefulHour | ConditionSVarCompare$ LE5 | SpellDescription$ Fateful hour — If you have 5 or less life, those creatures gain indestructible until end of turn. +SVar:FatefulHour:Count$YourLifeTotal Oracle:Creatures you control get +1/+1 until end of turn.\nFateful hour — If you have 5 or less life, those creatures gain indestructible until end of turn. (Damage and effects that say "destroy" don't destroy them.) diff --git a/forge-gui/res/cardsfolder/o/ogre_slumlord.txt b/forge-gui/res/cardsfolder/o/ogre_slumlord.txt index db136ccd62d..59feeeeabc6 100644 --- a/forge-gui/res/cardsfolder/o/ogre_slumlord.txt +++ b/forge-gui/res/cardsfolder/o/ogre_slumlord.txt @@ -2,7 +2,7 @@ Name:Ogre Slumlord ManaCost:3 B B Types:Creature Ogre Rogue PT:3/3 -T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.nonToken+Other | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever another nontoken creature dies, you may create a 1/1 black Rat creature token. +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.nonToken+Other | OptionalDecider$ You | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever another nontoken creature dies, you may create a 1/1 black Rat creature token. SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ b_1_1_rat | TokenOwner$ You S:Mode$ Continuous | Affected$ Creature.Rat+YouCtrl | AddKeyword$ Deathtouch | Description$ Rats you control have deathtouch. DeckHas:Ability$Token diff --git a/forge-gui/res/cardsfolder/o/omarthis_ghostfire_initiate.txt b/forge-gui/res/cardsfolder/o/omarthis_ghostfire_initiate.txt index 2c2d5c47dca..da377b588ec 100644 --- a/forge-gui/res/cardsfolder/o/omarthis_ghostfire_initiate.txt +++ b/forge-gui/res/cardsfolder/o/omarthis_ghostfire_initiate.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Spirit Naga PT:0/0 K:etbCounter:P1P1:X SVar:X:Count$xPaid -T:Mode$ CounterAddedOnce | ValidCard$ Creature.Other+inZoneBattlefield+Colorless | OptionalDecider$ You | TriggerZones$ Battlefield | CounterType$ P1P1 | Execute$ TrigPutCounter | TriggerDescription$ Whenever you put one or more +1/+1 counters on another colorless creature, you may put a +1/+1 counter on NICKNAME. +T:Mode$ CounterAddedOnce | ValidCard$ Creature.Other+inZoneBattlefield+Colorless | ValidPlayer$ You | OptionalDecider$ You | TriggerZones$ Battlefield | CounterType$ P1P1 | Execute$ TrigPutCounter | TriggerDescription$ Whenever you put one or more +1/+1 counters on another colorless creature, you may put a +1/+1 counter on NICKNAME. SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigManifest | TriggerDescription$ When NICKNAME dies, manifest a number of cards from the top of your library equal to the number of counters on it. SVar:TrigManifest:DB$ Manifest | Amount$ Y | Defined$ TopOfLibrary diff --git a/forge-gui/res/cardsfolder/o/one_with_the_kami.txt b/forge-gui/res/cardsfolder/o/one_with_the_kami.txt index 3d290b62edc..946bf58da49 100644 --- a/forge-gui/res/cardsfolder/o/one_with_the_kami.txt +++ b/forge-gui/res/cardsfolder/o/one_with_the_kami.txt @@ -4,7 +4,7 @@ Types:Enchantment Aura K:Flash K:Enchant creature you control A:SP$ Attach | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | AILogic$ Pump -T:Mode$ ChangesZone | ValidCard$ Creature.EnchantedBy,Creature.modified+NotEnchantedBy | Origin$ Battlefield | Destination$ Graveyard | Execute$ TrigToken | TriggerDescription$ Whenever enchanted creature or another modified creature you control dies, create X 1/1 colorless Spirit creature tokens, where X is that creature's power. (Equipment, Auras you control, and counters are modifications.) +T:Mode$ ChangesZone | ValidCard$ Creature.EnchantedBy,Creature.YouCtrl+modified+NotEnchantedBy | Origin$ Battlefield | Destination$ Graveyard | Execute$ TrigToken | TriggerDescription$ Whenever enchanted creature or another modified creature you control dies, create X 1/1 colorless Spirit creature tokens, where X is that creature's power. (Equipment, Auras you control, and counters are modifications.) SVar:TrigToken:DB$ Token | TokenScript$ c_1_1_spirit | TokenAmount$ X SVar:X:TriggeredCard$CardPower DeckHas:Ability$Token & Type$Spirit diff --git a/forge-gui/res/cardsfolder/t/treasure_nabber.txt b/forge-gui/res/cardsfolder/t/treasure_nabber.txt index 47ea0f05c72..1a4a4f012e1 100644 --- a/forge-gui/res/cardsfolder/t/treasure_nabber.txt +++ b/forge-gui/res/cardsfolder/t/treasure_nabber.txt @@ -3,5 +3,5 @@ ManaCost:2 R Types:Creature Goblin Rogue PT:3/2 T:Mode$ TapsForMana | ValidCard$ Artifact | Activator$ Opponent | TriggerZones$ Battlefield | Execute$ TrigControl | TriggerDescription$ Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn. -SVar:TrigControl:DB$ GainControl | Defined$ TriggeredCard | LoseControl$ UntilTheEndOfYourNextTurn +SVar:TrigControl:DB$ GainControl | Defined$ TriggeredCardLKICopy | LoseControl$ UntilTheEndOfYourNextTurn Oracle:Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn. diff --git a/forge-gui/res/cardsfolder/u/unexpected_allies.txt b/forge-gui/res/cardsfolder/u/unexpected_allies.txt index fe8d450f87c..ed9b76f13a5 100644 --- a/forge-gui/res/cardsfolder/u/unexpected_allies.txt +++ b/forge-gui/res/cardsfolder/u/unexpected_allies.txt @@ -2,7 +2,7 @@ Name:Unexpected Allies ManaCost:1 R Types:Sorcery A:SP$ Pump | ValidTgts$ Creature.YouCtrl+nonToken | TgtPrompt$ Select target nontoken creature you control | KW$ Double team | NumAtt$ 2 | SubAbility$ TrigEffect | SpellDescription$ Target nontoken creature you control gets +2/+0 and gains double team until end of turn. It also gains first strike until end of turn if it has the same name as another creature you control or a creature card in your graveyard. -SVar:TrigEffect:DB$ Pump | ConditionCheckSVar$ X | Defined$ Targeted | KW$ First strike +SVar:TrigEffect:DB$ Pump | ConditionCheckSVar$ X | Defined$ Targeted | KW$ First Strike SVar:X:Count$Valid Creature.NotDefinedTargeted+YouCtrl+sharesNameWith Targeted/Plus.Y SVar:Y:Count$ValidGraveyard Creature.YouOwn+sharesNameWith Targeted DeckHas:Keyword$Double Team|First Strike diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputAttack.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputAttack.java index 54f5bb2d0db..9aa6ec454f5 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputAttack.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputAttack.java @@ -69,7 +69,6 @@ public class InputAttack extends InputSyncronizedBase { @Override public final void showMessage() { - // TODO still seems to have some issues with multiple planeswalkers setCurrentDefender(defenders.getFirst()); if (currentDefender == null) { @@ -295,7 +294,9 @@ public class InputAttack extends InputSyncronizedBase { getController().getGui().setHighlighted(PlayerView.get((Player) ge), ge == def); } } - potentialBanding = isBandingPossible(); + if (def != null) { + potentialBanding = isBandingPossible(); + } updateMessage(); }