From 0750ae52bb86091177e2ede8fe9992a534715ca1 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Sat, 4 Jun 2022 14:11:42 +0200 Subject: [PATCH 1/4] Fix The Fallen ignoring planeswalkers --- .../forge/game/card/CardDamageHistory.java | 68 +++++++++++-------- .../java/forge/game/card/CardProperty.java | 11 ++- .../forge/game/player/PlayerProperty.java | 4 +- forge-gui/res/cardsfolder/t/the_fallen.txt | 2 +- 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/forge-game/src/main/java/forge/game/card/CardDamageHistory.java b/forge-game/src/main/java/forge/game/card/CardDamageHistory.java index ef53f011c6e..9337293bedc 100644 --- a/forge-game/src/main/java/forge/game/card/CardDamageHistory.java +++ b/forge-game/src/main/java/forge/game/card/CardDamageHistory.java @@ -9,6 +9,8 @@ import com.google.common.collect.Maps; import forge.game.GameEntity; import forge.game.player.Player; +import forge.game.zone.ZoneType; +import forge.util.collect.FCollection; /** * TODO: Write javadoc for this type. @@ -19,7 +21,8 @@ public class CardDamageHistory { private boolean creatureAttackedThisCombat = false; private boolean creatureBlockedThisCombat = false; private boolean creatureGotBlockedThisCombat = false; - private boolean receivedNonCombatDamageThisTurn = false; + + boolean hasdealtDamagetoAny = false; private List attackedThisTurn = Lists.newArrayList(); private final List creatureAttackedLastTurnOf = Lists.newArrayList(); @@ -27,13 +30,17 @@ public class CardDamageHistory { private final List NotBlockedSinceLastUpkeepOf = Lists.newArrayList(); private final List NotBeenBlockedSinceLastUpkeepOf = Lists.newArrayList(); - private final Map damagedThisCombat = Maps.newHashMap(); + // only needed for Glen Elendra (Plane) + private final List damagedThisCombat = Lists.newArrayList(); + // only needed for The Fallen + private final FCollection damagedThisGame = new FCollection<>(); + private final Map damagedThisTurn = Maps.newHashMap(); private final Map damagedThisTurnInCombat = Maps.newHashMap(); - private final Map damagedThisGame = Maps.newHashMap(); + private boolean receivedNonCombatDamageThisTurn = false; public final boolean getHasdealtDamagetoAny() { - return !damagedThisGame.isEmpty(); + return hasdealtDamagetoAny; } // used to see if an attacking creature with a triggering attack ability @@ -241,7 +248,7 @@ public class CardDamageHistory { this.receivedNonCombatDamageThisTurn = b; } - public final Map getThisCombatDamaged() { + public final List getThisCombatDamaged() { return damagedThisCombat; } public final Map getThisTurnDamaged() { @@ -250,7 +257,7 @@ public class CardDamageHistory { public final Map getThisTurnCombatDamaged() { return damagedThisTurnInCombat; } - public final Map getThisGameDamaged() { + public final FCollection getThisGameDamaged() { return damagedThisGame; } /** @@ -259,29 +266,15 @@ public class CardDamageHistory { */ public void registerCombatDamage(GameEntity entity, int amount) { int old = 0; - if (damagedThisCombat.containsKey(entity)) { - old = damagedThisCombat.get(entity); + if (entity instanceof Player) { + damagedThisCombat.add((Player) entity); } - damagedThisCombat.put(entity, old + amount); old = 0; if (damagedThisTurnInCombat.containsKey(entity)) { old = damagedThisTurnInCombat.get(entity); } damagedThisTurnInCombat.put(entity, old + amount); - } - /** - * TODO: Write javadoc for this method. - */ - public void newTurn() { - damagedThisCombat.clear(); - damagedThisTurnInCombat.clear(); - damagedThisTurn.clear(); - attackedThisTurn.clear(); - setHasBeenDealtNonCombatDamageThisTurn(false); - } - - public void endCombat() { - damagedThisCombat.clear(); + hasdealtDamagetoAny = true; } /** @@ -294,11 +287,30 @@ public class CardDamageHistory { old = damagedThisTurn.get(entity); } damagedThisTurn.put(entity, old + amount); - old = 0; - if (damagedThisGame.containsKey(entity)) { - old = damagedThisGame.get(entity); - } - damagedThisGame.put(entity, old + amount); + damagedThisGame.add(entity); + hasdealtDamagetoAny = true; } + public void newTurn() { + damagedThisCombat.clear(); + damagedThisTurnInCombat.clear(); + damagedThisTurn.clear(); + attackedThisTurn.clear(); + + // if card already LTB we can safely dereference (allows quite a few objects to be cleaned up earlier for bigger boardstates) + CardCollection toRemove = new CardCollection(); + for (GameEntity e : damagedThisGame) { + if (e instanceof Card) { + if (((Card) e).getZone().getZoneType() != ZoneType.Battlefield) { + toRemove.add((Card)e); + } + } + } + damagedThisGame.removeAll(toRemove); + setHasBeenDealtNonCombatDamageThisTurn(false); + } + + public void endCombat() { + damagedThisCombat.clear(); + } } diff --git a/forge-game/src/main/java/forge/game/card/CardProperty.java b/forge-game/src/main/java/forge/game/card/CardProperty.java index 3adf5aba1fb..562c4bf0fa2 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -1160,7 +1160,7 @@ public class CardProperty { } else if (property.startsWith("dealtCombatDamage") || property.startsWith("notDealtCombatDamage")) { final String[] v = property.split(" ")[1].split(","); final Iterable list = property.contains("ThisCombat") ? - card.getDamageHistory().getThisCombatDamaged().keySet() : + Lists.newArrayList(card.getDamageHistory().getThisCombatDamaged()) : card.getDamageHistory().getThisTurnCombatDamaged().keySet(); boolean found = Iterables.any(list, GameObjectPredicates.restriction(v, sourceController, source, spellAbility)); if (found == property.startsWith("not")) { @@ -1182,6 +1182,15 @@ public class CardProperty { if (!card.getDamageHistory().hasBeenDealtNonCombatDamageThisTurn()) { return false; } + } else if (property.startsWith("wasDealtDamageByThisGame")) { + int idx = source.getDamageHistory().getThisGameDamaged().indexOf(card); + if (idx == -1) { + return false; + } + Card c = (Card) source.getDamageHistory().getThisGameDamaged().get(idx); + if (!c.equalsWithTimestamp(game.getCardState(card))) { + return false; + } } else if (property.startsWith("dealtDamageThisTurn")) { if (card.getTotalDamageDoneBy() == 0) { return false; diff --git a/forge-game/src/main/java/forge/game/player/PlayerProperty.java b/forge-game/src/main/java/forge/game/player/PlayerProperty.java index c483b869f75..2ac16407d3f 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerProperty.java +++ b/forge-game/src/main/java/forge/game/player/PlayerProperty.java @@ -94,7 +94,7 @@ public class PlayerProperty { final List cards = AbilityUtils.getDefinedCards(source, v, spellAbility); int found = 0; for (final Card card : cards) { - if (card.getDamageHistory().getThisCombatDamaged().containsKey(player)) { + if (card.getDamageHistory().getThisCombatDamaged().contains(player)) { found++; } } @@ -113,7 +113,7 @@ public class PlayerProperty { final List cards = AbilityUtils.getDefinedCards(source, v, spellAbility); int found = 0; for (final Card card : cards) { - if (card.getDamageHistory().getThisGameDamaged().containsKey(player)) { + if (card.getDamageHistory().getThisGameDamaged().contains(player)) { found++; } } diff --git a/forge-gui/res/cardsfolder/t/the_fallen.txt b/forge-gui/res/cardsfolder/t/the_fallen.txt index dff72dd1ee7..b86edbeb9ce 100644 --- a/forge-gui/res/cardsfolder/t/the_fallen.txt +++ b/forge-gui/res/cardsfolder/t/the_fallen.txt @@ -3,5 +3,5 @@ ManaCost:1 B B B Types:Creature Zombie PT:2/3 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigDamage | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, CARDNAME deals 1 damage to each opponent and planeswalker it has dealt damage to this game. -SVar:TrigDamage:DB$ DealDamage | Defined$ Player.Opponent+wasDealtDamageThisGameBy Self | NumDmg$ 1 +SVar:TrigDamage:DB$ DamageAll | ValidPlayers$ Player.Opponent+wasDealtDamageThisGameBy Self | ValidCards$ Planeswalker.wasDealtDamageByThisGame | NumDmg$ 1 Oracle:At the beginning of your upkeep, The Fallen deals 1 damage to each opponent and planeswalker it has dealt damage to this game. From aa40b9c64a40a18c2153c2737f4057ecfcf32bca Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Sat, 4 Jun 2022 14:12:15 +0200 Subject: [PATCH 2/4] Card fix --- forge-gui/res/cardsfolder/a/ancient_brass_dragon.txt | 2 +- forge-gui/res/cardsfolder/b/bess_soul_nourisher.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-gui/res/cardsfolder/a/ancient_brass_dragon.txt b/forge-gui/res/cardsfolder/a/ancient_brass_dragon.txt index 8867dcc7baf..956806b6c70 100644 --- a/forge-gui/res/cardsfolder/a/ancient_brass_dragon.txt +++ b/forge-gui/res/cardsfolder/a/ancient_brass_dragon.txt @@ -6,7 +6,7 @@ K:Flying T:Mode$ DamageDone | ValidSource$ Card.Self | Execute$ TrigRoll | CombatDamage$ True | ValidTarget$ Player | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, roll a d20. When you do, put any number of target creature cards with total mana value X or less from graveyards onto the battlefield under your control, where X is the result. SVar:TrigRoll:DB$ RollDice | ResultSVar$ Result | Sides$ 20 | SubAbility$ DBImmediateTrigger SVar:DBImmediateTrigger:DB$ ImmediateTrigger | Execute$ TrigChangeZone | RememberSVarAmount$ Result | TriggerDescription$ When you do, put any number of target creature cards with total mana value X or less from graveyards onto the battlefield under your control, where X is the result. -SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | TargetMin$ 0 | TargetMax$ Y | ValidTgts$ Creature | TgtPrompt$ Select any number of target creature cards with total mana value X or less from graveyards | WithTotalCMC$ X | GainControl$ True +SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | TargetMin$ 0 | TargetMax$ Y | ValidTgts$ Creature | TgtPrompt$ Select any number of target creature cards with total mana value X or less from graveyards | MaxTotalTargetCMC$ X | GainControl$ True SVar:X:Count$TriggerRememberAmount SVar:Y:Count$TypeInAllYards.Creature DeckHas:Ability$Graveyard diff --git a/forge-gui/res/cardsfolder/b/bess_soul_nourisher.txt b/forge-gui/res/cardsfolder/b/bess_soul_nourisher.txt index d040f0220ab..4ca83ed68a8 100644 --- a/forge-gui/res/cardsfolder/b/bess_soul_nourisher.txt +++ b/forge-gui/res/cardsfolder/b/bess_soul_nourisher.txt @@ -2,7 +2,7 @@ Name:Bess, Soul Nourisher ManaCost:1 G W Types:Legendary Creature Human Citizen PT:1/1 -T:Mode$ ChangesZoneAll | ValidCards$ Creature.basePowerEQ1+baseToughnessEQ1+Other | Destination$ Battlefield | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever one or more other creatures with base power and toughness 1/1 enter the battlefield under your control, put a +1/+1 counter on CARDNAME. +T:Mode$ ChangesZoneAll | ValidCards$ Creature.basePowerEQ1+baseToughnessEQ1+Other+YouCtrl | Destination$ Battlefield | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever one or more other creatures with base power and toughness 1/1 enter the battlefield under your control, put a +1/+1 counter on CARDNAME. SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPumpAll | TriggerDescription$ Whenever NICKNAME attacks, each other creature you control with base power and toughness 1/1 gets +X/+X until end of turn, where X is the number of +1/+1 counters on NICKNAME. SVar:TrigPumpAll:DB$ PumpAll | ValidCards$ Creature.basePowerEQ1+baseToughnessEQ1+Other | NumAtt$ +X | NumDef$ +X From 185598ab9cbe3cb64a33b4a3b947c583919b080e Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Sat, 4 Jun 2022 14:12:45 +0200 Subject: [PATCH 3/4] Fix NPE --- forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java index 29f5b555995..7c90cf65fd1 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java @@ -752,14 +752,16 @@ public class CountersPutAi extends CountersAi { final int amount = AbilityUtils.calculateAmount(source, amountStr, sa); int left = amount; final String[] types; + String type = ""; if (sa.hasParam("CounterType")) { // TODO some cards let you choose types, should check each types = sa.getParam("CounterType").split(","); - } else { + type = types[0]; + } else if (sa.hasParam("CounterTypes")) { // all types will be added types = sa.getParam("CounterTypes").split(","); + type = types[0]; } - final String type = types[0]; if (!sa.usesTargeting()) { // No target. So must be defined From 2b3522205d3e2287cf593fafbef192b70bd0ab80 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Sat, 4 Jun 2022 14:13:28 +0200 Subject: [PATCH 4/4] Fix counting when type didn't match --- .../src/main/java/forge/game/GameEntityCounterTable.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/forge-game/src/main/java/forge/game/GameEntityCounterTable.java b/forge-game/src/main/java/forge/game/GameEntityCounterTable.java index 831573e6627..2f42eb4db4b 100644 --- a/forge-game/src/main/java/forge/game/GameEntityCounterTable.java +++ b/forge-game/src/main/java/forge/game/GameEntityCounterTable.java @@ -94,7 +94,9 @@ public class GameEntityCounterTable extends ForwardingTable, Ga for (Map cm : gm.getValue().values()) { Integer old = ObjectUtils.firstNonNull(result.get(gm.getKey()), 0); Integer v = ObjectUtils.firstNonNull(cm.get(type), 0); - result.put(gm.getKey(), old + v); + if (old + v > 0) { + result.put(gm.getKey(), old + v); + } } } }