From 9cdc7a27c18dc882d7da03977cf0af216fc42911 Mon Sep 17 00:00:00 2001 From: tool4ever Date: Sat, 29 Apr 2023 06:34:43 +0200 Subject: [PATCH] Fix CounterAdded triggers (#3030) * Fix CounterAdded triggers * Fix invalid param * Fix NPE --------- Co-authored-by: TRT <> --- .../main/java/forge/ai/ability/CountersPutAllAi.java | 2 +- .../game/trigger/TriggerCounterPlayerAddedAll.java | 10 +++++++--- .../src/main/java/forge/view/arcane/CardPanel.java | 3 ++- forge-gui/res/cardsfolder/a/all_will_be_one.txt | 2 +- forge-gui/res/cardsfolder/g/generous_patron.txt | 2 +- .../res/cardsfolder/k/kethek_crucible_goliath.txt | 2 +- .../res/cardsfolder/k/kros_defense_contractor.txt | 2 +- .../res/cardsfolder/l/lukka_coppercoat_outcast.txt | 2 +- .../res/cardsfolder/upcoming/shalai_and_hallar.txt | 2 +- 9 files changed, 16 insertions(+), 11 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java index 9e824bc14ee..99bbd790199 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java @@ -32,7 +32,7 @@ public class CountersPutAllAi extends SpellAbilityAi { List hList; List cList; final String type = sa.getParam("CounterType"); - final String amountStr = sa.getParam("CounterNum"); + final String amountStr = sa.getParamOrDefault("CounterNum", "1"); final String valid = sa.getParam("ValidCards"); final String logic = sa.getParamOrDefault("AILogic", ""); final boolean curse = sa.isCurse(); diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCounterPlayerAddedAll.java b/forge-game/src/main/java/forge/game/trigger/TriggerCounterPlayerAddedAll.java index 60674ad0c55..b8891816b9e 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCounterPlayerAddedAll.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCounterPlayerAddedAll.java @@ -2,10 +2,14 @@ package forge.game.trigger; import java.util.Map; +import com.google.common.base.Functions; + import forge.game.ability.AbilityKey; import forge.game.card.Card; +import forge.game.card.CounterType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.util.Aggregates; import forge.util.Localizer; public class TriggerCounterPlayerAddedAll extends Trigger { @@ -33,15 +37,15 @@ public class TriggerCounterPlayerAddedAll extends Trigger { @Override public void setTriggeringObjects(SpellAbility sa, Map runParams) { - sa.setTriggeringObjectsFrom(runParams, AbilityKey.Source, AbilityKey.Player, AbilityKey.Object, AbilityKey.CounterMap); - + sa.setTriggeringObjectsFrom(runParams, AbilityKey.Source, AbilityKey.Object, AbilityKey.CounterMap); + sa.setTriggeringObject(AbilityKey.Amount, Aggregates.sum(((Map) runParams.get(AbilityKey.CounterMap)).values(), Functions.identity())); } @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); sb.append(Localizer.getInstance().getMessage("lblAddedOnce")).append(": "); - sb.append(sa.getTriggeringObject(AbilityKey.Player)).append(": "); + sb.append(sa.getTriggeringObject(AbilityKey.Source)).append(": "); sb.append(sa.getTriggeringObject(AbilityKey.Object)); return sb.toString(); } diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java index f20b4da3b7e..5e8b770ce38 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java @@ -38,6 +38,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -781,7 +782,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } - for (Map.Entry counterEntry : card.getCounters().entrySet()) { + for (Map.Entry counterEntry : new HashSet<>(card.getCounters().entrySet())) { final CounterType counter = counterEntry.getKey(); final int numberOfCounters = counterEntry.getValue(); final int counterBoxRealWidth = counterBoxBaseWidth + largeFontMetrics.stringWidth(String.valueOf(numberOfCounters)); diff --git a/forge-gui/res/cardsfolder/a/all_will_be_one.txt b/forge-gui/res/cardsfolder/a/all_will_be_one.txt index aa5eba81852..3173b0026e6 100644 --- a/forge-gui/res/cardsfolder/a/all_will_be_one.txt +++ b/forge-gui/res/cardsfolder/a/all_will_be_one.txt @@ -1,7 +1,7 @@ Name:All Will Be One ManaCost:3 R R Types:Enchantment -T:Mode$ CounterAddedOnce | ValidEntity$ Permanent.inRealZoneBattlefield,Player | TriggerZones$ Battlefield | ValidSource$ You | Execute$ TrigDamage | TriggerDescription$ Whenever you put one or more counters on a permanent or player, CARDNAME deals that much damage to target opponent, creature an opponent controls, or planeswalker an opponent controls +T:Mode$ CounterPlayerAddedAll | ValidObject$ Permanent.inRealZoneBattlefield,Player | TriggerZones$ Battlefield | ValidSource$ You | Execute$ TrigDamage | TriggerDescription$ Whenever you put one or more counters on a permanent or player, CARDNAME deals that much damage to target opponent, creature an opponent controls, or planeswalker an opponent controls SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Creature.OppCtrl,Planeswalker.OppCtrl,Opponent | TgtPrompt$ Select target opponent, creature an opponent controls, or planeswalker an opponent controls.| NumDmg$ X SVar:X:TriggerCount$Amount DeckNeeds:Ability$Counters diff --git a/forge-gui/res/cardsfolder/g/generous_patron.txt b/forge-gui/res/cardsfolder/g/generous_patron.txt index 78bd078cfe6..4316e4587d9 100644 --- a/forge-gui/res/cardsfolder/g/generous_patron.txt +++ b/forge-gui/res/cardsfolder/g/generous_patron.txt @@ -4,7 +4,7 @@ Types:Creature Elf Advisor PT:1/4 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPut | TriggerDescription$ When CARDNAME enters the battlefield, support 2. (Put a +1/+1 counter on each of up to two other target creatures.) SVar:TrigPut:DB$ PutCounter | ValidTgts$ Creature.Other | TgtPrompt$ Select target creature other than CARDNAME | TargetMin$ 0 | TargetMax$ 2 | CounterType$ P1P1 | CounterNum$ 1 -T:Mode$ CounterAddedOnce | ValidCard$ Creature.YouDontCtrl+inRealZoneBattlefield | ValidSource$ You | TriggerZones$ Battlefield | Execute$ DBDraw | TriggerDescription$ Whenever you put one or more counters on a creature you don't control, draw a card. +T:Mode$ CounterPlayerAddedAll | ValidObject$ Creature.YouDontCtrl+inRealZoneBattlefield | ValidSource$ You | TriggerZones$ Battlefield | Execute$ DBDraw | TriggerDescription$ Whenever you put one or more counters on a creature you don't control, draw a card. SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 1 DeckHas:Ability$Counters DeckHints:Ability$Counters diff --git a/forge-gui/res/cardsfolder/k/kethek_crucible_goliath.txt b/forge-gui/res/cardsfolder/k/kethek_crucible_goliath.txt index ce0048c32a0..8c53ddc3667 100644 --- a/forge-gui/res/cardsfolder/k/kethek_crucible_goliath.txt +++ b/forge-gui/res/cardsfolder/k/kethek_crucible_goliath.txt @@ -3,7 +3,7 @@ ManaCost:2 R B Types:Legendary Creature Phyrexian Beast PT:4/4 T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigSac | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your end step, you may sacrifice another creature. If you do, reveal cards from the top of your library until you reveal a nonlegendary creature card with lesser mana value, put it onto the battlefield, then put the rest on the bottom of your library in a random order. -SVar:TrigSac:AB$ DigUntil | Cost$ Sac<1/Creature.Other/another creature> | Defined$ You | Valid$ Card.Creature+nonLegendary+cmcLTX | FoundDestination$ Battlefield | RevealedDestination$ Library | RestRandomOrder$ True +SVar:TrigSac:AB$ DigUntil | Cost$ Sac<1/Creature.Other/another creature> | Defined$ You | Valid$ Card.Creature+nonLegendary+cmcLTX | FoundDestination$ Battlefield | RevealedDestination$ Library | RevealRandomOrder$ True SVar:X:Sacrificed$CardManaCost DeckHas:Ability$Sacrifice Oracle:At the beginning of your end step, you may sacrifice another creature. If you do, reveal cards from the top of your library until you reveal a nonlegendary creature card with lesser mana value, put it onto the battlefield, then put the rest on the bottom of your library in a random order. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/k/kros_defense_contractor.txt b/forge-gui/res/cardsfolder/k/kros_defense_contractor.txt index 5bc2e976dad..ef58573c7a5 100644 --- a/forge-gui/res/cardsfolder/k/kros_defense_contractor.txt +++ b/forge-gui/res/cardsfolder/k/kros_defense_contractor.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Cat Advisor PT:2/4 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ At the beginning of your upkeep, put a shield counter on target creature an opponent controls. SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | CounterType$ SHIELD | AILogic$ Curse -T:Mode$ CounterAddedOnce | ValidCard$ Creature.YouDontCtrl+inRealZoneBattlefield | ValidSource$ You | TriggerZones$ Battlefield | Execute$ TrigTap | TriggerDescription$ Whenever you put one or more counters on a creature you don't control, tap that creature and goad it. It gains trample until your next turn. (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.) +T:Mode$ CounterPlayerAddedAll | ValidObject$ Creature.YouDontCtrl+inRealZoneBattlefield | ValidSource$ You | TriggerZones$ Battlefield | Execute$ TrigTap | TriggerDescription$ Whenever you put one or more counters on a creature you don't control, tap that creature and goad it. It gains trample until your next turn. (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.) SVar:TrigTap:DB$ Tap | Defined$ TriggeredCardLKICopy | SubAbility$ DBGoad SVar:DBGoad:DB$ Goad | Defined$ TriggeredCardLKICopy | SubAbility$ DBPump SVar:DBPump:DB$ Pump | Defined$ TriggeredCardLKICopy | KW$ Trample | Duration$ UntilYourNextTurn diff --git a/forge-gui/res/cardsfolder/l/lukka_coppercoat_outcast.txt b/forge-gui/res/cardsfolder/l/lukka_coppercoat_outcast.txt index a92ca38e16c..01ce628555d 100644 --- a/forge-gui/res/cardsfolder/l/lukka_coppercoat_outcast.txt +++ b/forge-gui/res/cardsfolder/l/lukka_coppercoat_outcast.txt @@ -7,7 +7,7 @@ SVar:DBRepeat:DB$ RepeatEach | UseImprinted$ True | RepeatSubAbility$ DBAnimate SVar:DBAnimate:DB$ Animate | Defined$ Imprinted | staticAbilities$ STMayPlay | Duration$ Permanent SVar:STMayPlay:Mode$ Continuous | Affected$ Card.Self | AffectedZone$ Exile | EffectZone$ Exile | MayPlay$ True | IsPresent$ Planeswalker.Lukka+YouCtrl | Description$ You may cast this card from exile as long as you control a Lukka planeswalker. A:AB$ ChangeZone | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | Origin$ Battlefield | Destination$ Exile | SubAbility$ DBDigUntil | RememberChanged$ True | StackDescription$ SpellDescription | SpellDescription$ Exile target creature you control, then reveal cards from the top of your library until you reveal a creature card with higher mana value. Put that card onto the battlefield and the rest on the bottom of your library in a random order. -SVar:DBDigUntil:DB$ DigUntil | Valid$ Creature.cmcGEX | ValidDescription$ creature card with higher mana value | FoundDestination$ Battlefield | RevealedDestination$ Library | RevealedLibraryPosition$ -1 | RestRandomOrder$ True | SubAbility$ DBCleanup | StackDescription$ None +SVar:DBDigUntil:DB$ DigUntil | Valid$ Creature.cmcGEX | ValidDescription$ creature card with higher mana value | FoundDestination$ Battlefield | RevealedDestination$ Library | RevealedLibraryPosition$ -1 | RevealRandomOrder$ True | SubAbility$ DBCleanup | StackDescription$ None SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True A:AB$ RepeatEach | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | RepeatCards$ Creature.YouCtrl | RepeatSubAbility$ DBDamage | DamageMap$ True | SpellDescription$ Each creature you control deals damage equal to its power to each opponent. SVar:DBDamage:DB$ DealDamage | Defined$ Player.Opponent | DamageSource$ Remembered | NumDmg$ Y diff --git a/forge-gui/res/cardsfolder/upcoming/shalai_and_hallar.txt b/forge-gui/res/cardsfolder/upcoming/shalai_and_hallar.txt index af96edd5b01..f0fe88a5847 100644 --- a/forge-gui/res/cardsfolder/upcoming/shalai_and_hallar.txt +++ b/forge-gui/res/cardsfolder/upcoming/shalai_and_hallar.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Angel Elf PT:3/3 K:Flying K:Vigilance -T:Mode$ CounterAddedOnce | TriggerZones$ Battlefield | ValidCard$ Creature.YouCtrl+inZoneBattlefield | Execute$ TrigDealDamage | ValidCounterType$ P1P1 | TriggerDescription$ Whenever one or more +1/+1 counters are put on a creature you control, CARDNAME deals that much damage to target opponent. +T:Mode$ CounterAddedOnce | TriggerZones$ Battlefield | ValidCard$ Creature.YouCtrl+inZoneBattlefield | Execute$ TrigDealDamage | CounterType$ P1P1 | TriggerDescription$ Whenever one or more +1/+1 counters are put on a creature you control, CARDNAME deals that much damage to target opponent. SVar:TrigDealDamage:DB$ DealDamage | ValidTgts$ Opponent | NumDmg$ X SVar:X:TriggerCount$Amount DeckNeeds:Ability$Counters