Merge pull request #617 from tool4ever/thefallen

Fix The Fallen ignoring planeswalkers
This commit is contained in:
Agetian
2022-06-04 15:43:54 +03:00
committed by GitHub
8 changed files with 62 additions and 37 deletions

View File

@@ -752,14 +752,16 @@ public class CountersPutAi extends CountersAi {
final int amount = AbilityUtils.calculateAmount(source, amountStr, sa); final int amount = AbilityUtils.calculateAmount(source, amountStr, sa);
int left = amount; int left = amount;
final String[] types; final String[] types;
String type = "";
if (sa.hasParam("CounterType")) { if (sa.hasParam("CounterType")) {
// TODO some cards let you choose types, should check each // TODO some cards let you choose types, should check each
types = sa.getParam("CounterType").split(","); types = sa.getParam("CounterType").split(",");
} else { type = types[0];
} else if (sa.hasParam("CounterTypes")) {
// all types will be added // all types will be added
types = sa.getParam("CounterTypes").split(","); types = sa.getParam("CounterTypes").split(",");
type = types[0];
} }
final String type = types[0];
if (!sa.usesTargeting()) { if (!sa.usesTargeting()) {
// No target. So must be defined // No target. So must be defined

View File

@@ -94,10 +94,12 @@ public class GameEntityCounterTable extends ForwardingTable<Optional<Player>, Ga
for (Map<CounterType, Integer> cm : gm.getValue().values()) { for (Map<CounterType, Integer> cm : gm.getValue().values()) {
Integer old = ObjectUtils.firstNonNull(result.get(gm.getKey()), 0); Integer old = ObjectUtils.firstNonNull(result.get(gm.getKey()), 0);
Integer v = ObjectUtils.firstNonNull(cm.get(type), 0); Integer v = ObjectUtils.firstNonNull(cm.get(type), 0);
if (old + v > 0) {
result.put(gm.getKey(), old + v); result.put(gm.getKey(), old + v);
} }
} }
} }
}
return result; return result;
} }

View File

@@ -9,6 +9,8 @@ import com.google.common.collect.Maps;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.util.collect.FCollection;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
@@ -19,7 +21,8 @@ public class CardDamageHistory {
private boolean creatureAttackedThisCombat = false; private boolean creatureAttackedThisCombat = false;
private boolean creatureBlockedThisCombat = false; private boolean creatureBlockedThisCombat = false;
private boolean creatureGotBlockedThisCombat = false; private boolean creatureGotBlockedThisCombat = false;
private boolean receivedNonCombatDamageThisTurn = false;
boolean hasdealtDamagetoAny = false;
private List<GameEntity> attackedThisTurn = Lists.newArrayList(); private List<GameEntity> attackedThisTurn = Lists.newArrayList();
private final List<Player> creatureAttackedLastTurnOf = Lists.newArrayList(); private final List<Player> creatureAttackedLastTurnOf = Lists.newArrayList();
@@ -27,13 +30,17 @@ public class CardDamageHistory {
private final List<Player> NotBlockedSinceLastUpkeepOf = Lists.newArrayList(); private final List<Player> NotBlockedSinceLastUpkeepOf = Lists.newArrayList();
private final List<Player> NotBeenBlockedSinceLastUpkeepOf = Lists.newArrayList(); private final List<Player> NotBeenBlockedSinceLastUpkeepOf = Lists.newArrayList();
private final Map<GameEntity, Integer> damagedThisCombat = Maps.newHashMap(); // only needed for Glen Elendra (Plane)
private final List<Player> damagedThisCombat = Lists.newArrayList();
// only needed for The Fallen
private final FCollection<GameEntity> damagedThisGame = new FCollection<>();
private final Map<GameEntity, Integer> damagedThisTurn = Maps.newHashMap(); private final Map<GameEntity, Integer> damagedThisTurn = Maps.newHashMap();
private final Map<GameEntity, Integer> damagedThisTurnInCombat = Maps.newHashMap(); private final Map<GameEntity, Integer> damagedThisTurnInCombat = Maps.newHashMap();
private final Map<GameEntity, Integer> damagedThisGame = Maps.newHashMap(); private boolean receivedNonCombatDamageThisTurn = false;
public final boolean getHasdealtDamagetoAny() { public final boolean getHasdealtDamagetoAny() {
return !damagedThisGame.isEmpty(); return hasdealtDamagetoAny;
} }
// used to see if an attacking creature with a triggering attack ability // used to see if an attacking creature with a triggering attack ability
@@ -241,7 +248,7 @@ public class CardDamageHistory {
this.receivedNonCombatDamageThisTurn = b; this.receivedNonCombatDamageThisTurn = b;
} }
public final Map<GameEntity, Integer> getThisCombatDamaged() { public final List<Player> getThisCombatDamaged() {
return damagedThisCombat; return damagedThisCombat;
} }
public final Map<GameEntity, Integer> getThisTurnDamaged() { public final Map<GameEntity, Integer> getThisTurnDamaged() {
@@ -250,7 +257,7 @@ public class CardDamageHistory {
public final Map<GameEntity, Integer> getThisTurnCombatDamaged() { public final Map<GameEntity, Integer> getThisTurnCombatDamaged() {
return damagedThisTurnInCombat; return damagedThisTurnInCombat;
} }
public final Map<GameEntity, Integer> getThisGameDamaged() { public final FCollection<GameEntity> getThisGameDamaged() {
return damagedThisGame; return damagedThisGame;
} }
/** /**
@@ -259,29 +266,15 @@ public class CardDamageHistory {
*/ */
public void registerCombatDamage(GameEntity entity, int amount) { public void registerCombatDamage(GameEntity entity, int amount) {
int old = 0; int old = 0;
if (damagedThisCombat.containsKey(entity)) { if (entity instanceof Player) {
old = damagedThisCombat.get(entity); damagedThisCombat.add((Player) entity);
} }
damagedThisCombat.put(entity, old + amount);
old = 0; old = 0;
if (damagedThisTurnInCombat.containsKey(entity)) { if (damagedThisTurnInCombat.containsKey(entity)) {
old = damagedThisTurnInCombat.get(entity); old = damagedThisTurnInCombat.get(entity);
} }
damagedThisTurnInCombat.put(entity, old + amount); damagedThisTurnInCombat.put(entity, old + amount);
} hasdealtDamagetoAny = true;
/**
* TODO: Write javadoc for this method.
*/
public void newTurn() {
damagedThisCombat.clear();
damagedThisTurnInCombat.clear();
damagedThisTurn.clear();
attackedThisTurn.clear();
setHasBeenDealtNonCombatDamageThisTurn(false);
}
public void endCombat() {
damagedThisCombat.clear();
} }
/** /**
@@ -294,11 +287,30 @@ public class CardDamageHistory {
old = damagedThisTurn.get(entity); old = damagedThisTurn.get(entity);
} }
damagedThisTurn.put(entity, old + amount); damagedThisTurn.put(entity, old + amount);
old = 0; damagedThisGame.add(entity);
if (damagedThisGame.containsKey(entity)) { hasdealtDamagetoAny = true;
old = damagedThisGame.get(entity);
}
damagedThisGame.put(entity, old + amount);
} }
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();
}
} }

View File

@@ -1160,7 +1160,7 @@ public class CardProperty {
} else if (property.startsWith("dealtCombatDamage") || property.startsWith("notDealtCombatDamage")) { } else if (property.startsWith("dealtCombatDamage") || property.startsWith("notDealtCombatDamage")) {
final String[] v = property.split(" ")[1].split(","); final String[] v = property.split(" ")[1].split(",");
final Iterable<GameEntity> list = property.contains("ThisCombat") ? final Iterable<GameEntity> list = property.contains("ThisCombat") ?
card.getDamageHistory().getThisCombatDamaged().keySet() : Lists.newArrayList(card.getDamageHistory().getThisCombatDamaged()) :
card.getDamageHistory().getThisTurnCombatDamaged().keySet(); card.getDamageHistory().getThisTurnCombatDamaged().keySet();
boolean found = Iterables.any(list, GameObjectPredicates.restriction(v, sourceController, source, spellAbility)); boolean found = Iterables.any(list, GameObjectPredicates.restriction(v, sourceController, source, spellAbility));
if (found == property.startsWith("not")) { if (found == property.startsWith("not")) {
@@ -1182,6 +1182,15 @@ public class CardProperty {
if (!card.getDamageHistory().hasBeenDealtNonCombatDamageThisTurn()) { if (!card.getDamageHistory().hasBeenDealtNonCombatDamageThisTurn()) {
return false; 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")) { } else if (property.startsWith("dealtDamageThisTurn")) {
if (card.getTotalDamageDoneBy() == 0) { if (card.getTotalDamageDoneBy() == 0) {
return false; return false;

View File

@@ -94,7 +94,7 @@ public class PlayerProperty {
final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility); final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility);
int found = 0; int found = 0;
for (final Card card : cards) { for (final Card card : cards) {
if (card.getDamageHistory().getThisCombatDamaged().containsKey(player)) { if (card.getDamageHistory().getThisCombatDamaged().contains(player)) {
found++; found++;
} }
} }
@@ -113,7 +113,7 @@ public class PlayerProperty {
final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility); final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility);
int found = 0; int found = 0;
for (final Card card : cards) { for (final Card card : cards) {
if (card.getDamageHistory().getThisGameDamaged().containsKey(player)) { if (card.getDamageHistory().getThisGameDamaged().contains(player)) {
found++; found++;
} }
} }

View File

@@ -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. 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: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: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:X:Count$TriggerRememberAmount
SVar:Y:Count$TypeInAllYards.Creature SVar:Y:Count$TypeInAllYards.Creature
DeckHas:Ability$Graveyard DeckHas:Ability$Graveyard

View File

@@ -2,7 +2,7 @@ Name:Bess, Soul Nourisher
ManaCost:1 G W ManaCost:1 G W
Types:Legendary Creature Human Citizen Types:Legendary Creature Human Citizen
PT:1/1 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 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. 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 SVar:TrigPumpAll:DB$ PumpAll | ValidCards$ Creature.basePowerEQ1+baseToughnessEQ1+Other | NumAtt$ +X | NumDef$ +X

View File

@@ -3,5 +3,5 @@ ManaCost:1 B B B
Types:Creature Zombie Types:Creature Zombie
PT:2/3 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. 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. Oracle:At the beginning of your upkeep, The Fallen deals 1 damage to each opponent and planeswalker it has dealt damage to this game.