mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 20:58:03 +00:00
Global DamageHistory (#622)
* Global DamageHistory * Add new cards * Improve Ogre Enforcer * Clean up * Minor fixes
This commit is contained in:
@@ -206,7 +206,7 @@ public abstract class GameState {
|
|||||||
cardsReferencedByID.add(card.getExiledWith());
|
cardsReferencedByID.add(card.getExiledWith());
|
||||||
}
|
}
|
||||||
if (zone == ZoneType.Battlefield) {
|
if (zone == ZoneType.Battlefield) {
|
||||||
if (!card.getAttachedCards().isEmpty()) {
|
if (card.hasCardAttachments()) {
|
||||||
// Remember the ID of cards that have attachments
|
// Remember the ID of cards that have attachments
|
||||||
cardsReferencedByID.add(card);
|
cardsReferencedByID.add(card);
|
||||||
}
|
}
|
||||||
@@ -375,7 +375,7 @@ public abstract class GameState {
|
|||||||
newText.append("|Imprinting:").append(TextUtil.join(imprintedCardIds, ","));
|
newText.append("|Imprinting:").append(TextUtil.join(imprintedCardIds, ","));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c.getMergedCards().isEmpty()) {
|
if (c.hasMergedCard()) {
|
||||||
List<String> mergedCardNames = new ArrayList<>();
|
List<String> mergedCardNames = new ArrayList<>();
|
||||||
for (Card merged : c.getMergedCards()) {
|
for (Card merged : c.getMergedCards()) {
|
||||||
if (c.getTopMergedCard() == merged) {
|
if (c.getTopMergedCard() == merged) {
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ public class GameCopier {
|
|||||||
newPlayer.setLifeLostLastTurn(origPlayer.getLifeLostLastTurn());
|
newPlayer.setLifeLostLastTurn(origPlayer.getLifeLostLastTurn());
|
||||||
newPlayer.setLifeLostThisTurn(origPlayer.getLifeLostThisTurn());
|
newPlayer.setLifeLostThisTurn(origPlayer.getLifeLostThisTurn());
|
||||||
newPlayer.setLifeGainedThisTurn(origPlayer.getLifeGainedThisTurn());
|
newPlayer.setLifeGainedThisTurn(origPlayer.getLifeGainedThisTurn());
|
||||||
|
// TODO creatureAttackedThisTurn
|
||||||
for (Mana m : origPlayer.getManaPool()) {
|
for (Mana m : origPlayer.getManaPool()) {
|
||||||
newPlayer.getManaPool().addMana(m, false);
|
newPlayer.getManaPool().addMana(m, false);
|
||||||
}
|
}
|
||||||
@@ -207,6 +208,13 @@ public class GameCopier {
|
|||||||
|
|
||||||
private void copyGameState(Game newGame) {
|
private void copyGameState(Game newGame) {
|
||||||
newGame.setAge(origGame.getAge());
|
newGame.setAge(origGame.getAge());
|
||||||
|
|
||||||
|
// TODO countersAddedThisTurn
|
||||||
|
|
||||||
|
if (origGame.getMonarch() != null) {
|
||||||
|
newGame.setMonarch(playerMap.get(origGame.getMonarch()));
|
||||||
|
}
|
||||||
|
|
||||||
for (ZoneType zone : ZONES) {
|
for (ZoneType zone : ZONES) {
|
||||||
for (Card card : origGame.getCardsIn(zone)) {
|
for (Card card : origGame.getCardsIn(zone)) {
|
||||||
addCard(newGame, zone, card);
|
addCard(newGame, zone, card);
|
||||||
@@ -300,6 +308,7 @@ public class GameCopier {
|
|||||||
newCard.setPTCharacterDefiningTable(c.getSetPTCharacterDefiningTable());
|
newCard.setPTCharacterDefiningTable(c.getSetPTCharacterDefiningTable());
|
||||||
|
|
||||||
newCard.setPTBoost(c.getPTBoostTable());
|
newCard.setPTBoost(c.getPTBoostTable());
|
||||||
|
// TODO copy by map
|
||||||
newCard.setDamage(c.getDamage());
|
newCard.setDamage(c.getDamage());
|
||||||
|
|
||||||
newCard.setChangedCardColors(c.getChangedCardColorsTable());
|
newCard.setChangedCardColors(c.getChangedCardColorsTable());
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -47,6 +48,7 @@ import forge.game.ability.AbilityKey;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
|
import forge.game.card.CardDamageHistory;
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.card.CardPredicates;
|
import forge.game.card.CardPredicates;
|
||||||
import forge.game.card.CardUtil;
|
import forge.game.card.CardUtil;
|
||||||
@@ -78,6 +80,7 @@ import forge.trackable.Tracker;
|
|||||||
import forge.util.Aggregates;
|
import forge.util.Aggregates;
|
||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
import forge.util.Visitor;
|
import forge.util.Visitor;
|
||||||
|
import forge.util.collect.FCollection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the state of a <i>single game</i>, a new instance is created for each game.
|
* Represents the state of a <i>single game</i>, a new instance is created for each game.
|
||||||
@@ -119,6 +122,9 @@ public class Game {
|
|||||||
|
|
||||||
private Table<CounterType, Player, List<Pair<Card, Integer>>> countersAddedThisTurn = HashBasedTable.create();
|
private Table<CounterType, Player, List<Pair<Card, Integer>>> countersAddedThisTurn = HashBasedTable.create();
|
||||||
|
|
||||||
|
private FCollection<CardDamageHistory> globalDamageHistory = new FCollection<>();
|
||||||
|
private IdentityHashMap<Pair<Integer, Boolean>, Pair<Card, GameEntity>> damageThisTurnLKI = new IdentityHashMap<>();
|
||||||
|
|
||||||
private Map<Player, Card> topLibsCast = Maps.newHashMap();
|
private Map<Player, Card> topLibsCast = Maps.newHashMap();
|
||||||
private Map<Card, Integer> facedownWhileCasting = Maps.newHashMap();
|
private Map<Card, Integer> facedownWhileCasting = Maps.newHashMap();
|
||||||
|
|
||||||
@@ -251,7 +257,7 @@ public class Game {
|
|||||||
if (c == null) {
|
if (c == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return changeZoneLKIInfo.containsKey(c.getId()) ? changeZoneLKIInfo.get(c.getId()) : c;
|
return changeZoneLKIInfo.getOrDefault(c.getId(), c);
|
||||||
}
|
}
|
||||||
public final void clearChangeZoneLKIInfo() {
|
public final void clearChangeZoneLKIInfo() {
|
||||||
changeZoneLKIInfo.clear();
|
changeZoneLKIInfo.clear();
|
||||||
@@ -1088,6 +1094,7 @@ public class Game {
|
|||||||
|
|
||||||
public void onCleanupPhase() {
|
public void onCleanupPhase() {
|
||||||
clearCounterAddedThisTurn();
|
clearCounterAddedThisTurn();
|
||||||
|
clearGlobalDamageHistory();
|
||||||
// some cards need this info updated even after a player lost, so don't skip them
|
// some cards need this info updated even after a player lost, so don't skip them
|
||||||
for (Player player : getRegisteredPlayers()) {
|
for (Player player : getRegisteredPlayers()) {
|
||||||
player.onCleanupPhase();
|
player.onCleanupPhase();
|
||||||
@@ -1129,6 +1136,48 @@ public class Game {
|
|||||||
countersAddedThisTurn.clear();
|
countersAddedThisTurn.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the damage instances done this turn.
|
||||||
|
* @param isCombat if true only combat damage matters, pass null for both
|
||||||
|
* @param anyIsEnough if true returns early once result has an entry
|
||||||
|
* @param validSourceCard
|
||||||
|
* @param validTargetEntity
|
||||||
|
* @param source
|
||||||
|
* @param sourceController
|
||||||
|
* @param ctb
|
||||||
|
* @return List<Integer> for each source
|
||||||
|
*/
|
||||||
|
public List<Integer> getDamageDoneThisTurn(Boolean isCombat, boolean anyIsEnough, String validSourceCard, String validTargetEntity, Card source, Player sourceController, CardTraitBase ctb) {
|
||||||
|
final List<Integer> dmgList = Lists.newArrayList();
|
||||||
|
for (CardDamageHistory cdh : globalDamageHistory) {
|
||||||
|
int dmg = cdh.getDamageDoneThisTurn(isCombat, anyIsEnough, validSourceCard, validTargetEntity, source, sourceController, ctb);
|
||||||
|
if (dmg == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmgList.add(dmg);
|
||||||
|
|
||||||
|
if (anyIsEnough) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dmgList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addGlobalDamageHistory(CardDamageHistory cdh, Pair<Integer, Boolean> dmg, Card source, GameEntity target) {
|
||||||
|
globalDamageHistory.add(cdh);
|
||||||
|
damageThisTurnLKI.put(dmg, Pair.of(source, target));
|
||||||
|
}
|
||||||
|
public void clearGlobalDamageHistory() {
|
||||||
|
globalDamageHistory.clear();
|
||||||
|
damageThisTurnLKI.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pair<Card, GameEntity> getDamageLKI(Pair<Integer, Boolean> dmg) {
|
||||||
|
return damageThisTurnLKI.get(dmg);
|
||||||
|
}
|
||||||
|
|
||||||
public Card getTopLibForPlayer(Player P) {
|
public Card getTopLibForPlayer(Player P) {
|
||||||
return topLibsCast.get(P);
|
return topLibsCast.get(P);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import java.util.Set;
|
|||||||
import forge.util.*;
|
import forge.util.*;
|
||||||
|
|
||||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.ComparisonChain;
|
import com.google.common.collect.ComparisonChain;
|
||||||
@@ -1323,33 +1322,13 @@ public class GameAction {
|
|||||||
noRegCreats.add(c);
|
noRegCreats.add(c);
|
||||||
checkAgain = true;
|
checkAgain = true;
|
||||||
} else if (c.hasKeyword("CARDNAME can't be destroyed by lethal damage unless lethal damage dealt by a single source is marked on it.")) {
|
} else if (c.hasKeyword("CARDNAME can't be destroyed by lethal damage unless lethal damage dealt by a single source is marked on it.")) {
|
||||||
// merge entries with same source
|
if (c.getLethal() <= c.getMaxDamageFromSource() || c.hasBeenDealtDeathtouchDamage()) {
|
||||||
List<Integer> dmgList = Lists.newArrayList();
|
if (desCreats == null) {
|
||||||
List<Pair<Card, Integer>> remainingDamaged = Lists.newArrayList(c.getReceivedDamageFromThisTurn());
|
desCreats = new CardCollection();
|
||||||
while (!remainingDamaged.isEmpty()) {
|
|
||||||
Pair <Card, Integer> damaged = remainingDamaged.get(0);
|
|
||||||
int sum = damaged.getRight();
|
|
||||||
remainingDamaged.remove(damaged);
|
|
||||||
for (Pair<Card, Integer> other : Lists.newArrayList(remainingDamaged)) {
|
|
||||||
if (other.getLeft().equalsWithTimestamp(damaged.getLeft())) {
|
|
||||||
sum += other.getRight();
|
|
||||||
// once it got counted keep it out
|
|
||||||
remainingDamaged.remove(other);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dmgList.add(sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final Integer dmg : dmgList) {
|
|
||||||
if (c.getLethal() <= dmg.intValue() || c.hasBeenDealtDeathtouchDamage()) {
|
|
||||||
if (desCreats == null) {
|
|
||||||
desCreats = new CardCollection();
|
|
||||||
}
|
|
||||||
desCreats.add(c);
|
|
||||||
c.setHasBeenDealtDeathtouchDamage(false);
|
|
||||||
checkAgain = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
desCreats.add(c);
|
||||||
|
c.setHasBeenDealtDeathtouchDamage(false);
|
||||||
|
checkAgain = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Rule 704.5g - Destroy due to lethal damage
|
// Rule 704.5g - Destroy due to lethal damage
|
||||||
@@ -2364,6 +2343,7 @@ public class GameAction {
|
|||||||
game.getReplacementHandler().runReplaceDamage(isCombat, damageMap, preventMap, counterTable, cause);
|
game.getReplacementHandler().runReplaceDamage(isCombat, damageMap, preventMap, counterTable, cause);
|
||||||
|
|
||||||
Map<Card, Integer> lethalDamage = Maps.newHashMap();
|
Map<Card, Integer> lethalDamage = Maps.newHashMap();
|
||||||
|
Map<Integer, Card> lkiCache = Maps.newHashMap();
|
||||||
|
|
||||||
// Actually deal damage according to replaced damage map
|
// Actually deal damage according to replaced damage map
|
||||||
for (Map.Entry<Card, Map<GameEntity, Integer>> et : damageMap.rowMap().entrySet()) {
|
for (Map.Entry<Card, Map<GameEntity, Integer>> et : damageMap.rowMap().entrySet()) {
|
||||||
@@ -2390,6 +2370,8 @@ public class GameAction {
|
|||||||
|
|
||||||
e.setValue(Integer.valueOf(e.getKey().addDamageAfterPrevention(e.getValue(), sourceLKI, isCombat, counterTable)));
|
e.setValue(Integer.valueOf(e.getKey().addDamageAfterPrevention(e.getValue(), sourceLKI, isCombat, counterTable)));
|
||||||
sum += e.getValue();
|
sum += e.getValue();
|
||||||
|
|
||||||
|
sourceLKI.getDamageHistory().registerDamage(e.getValue(), isCombat, sourceLKI, e.getKey(), lkiCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sum > 0 && sourceLKI.hasKeyword(Keyword.LIFELINK)) {
|
if (sum > 0 && sourceLKI.hasKeyword(Keyword.LIFELINK)) {
|
||||||
|
|||||||
@@ -210,7 +210,6 @@ public final class GameActionUtil {
|
|||||||
final Cost escapeCost = new Cost(k[1], true);
|
final Cost escapeCost = new Cost(k[1], true);
|
||||||
|
|
||||||
final SpellAbility newSA = sa.copyWithManaCostReplaced(activator, escapeCost);
|
final SpellAbility newSA = sa.copyWithManaCostReplaced(activator, escapeCost);
|
||||||
newSA.setActivatingPlayer(activator);
|
|
||||||
|
|
||||||
newSA.putParam("PrecostDesc", "Escape—");
|
newSA.putParam("PrecostDesc", "Escape—");
|
||||||
newSA.putParam("CostDesc", escapeCost.toString());
|
newSA.putParam("CostDesc", escapeCost.toString());
|
||||||
|
|||||||
@@ -17,9 +17,13 @@
|
|||||||
*/
|
*/
|
||||||
package forge.game;
|
package forge.game;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
@@ -46,6 +50,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
|||||||
private String name = "";
|
private String name = "";
|
||||||
protected CardCollection attachedCards = new CardCollection();
|
protected CardCollection attachedCards = new CardCollection();
|
||||||
protected Map<CounterType, Integer> counters = Maps.newHashMap();
|
protected Map<CounterType, Integer> counters = Maps.newHashMap();
|
||||||
|
protected List<Pair<Integer, Boolean>> damageReceivedThisTurn = Lists.newArrayList();
|
||||||
|
|
||||||
protected GameEntity(int id0) {
|
protected GameEntity(int id0) {
|
||||||
id = id0;
|
id = id0;
|
||||||
@@ -330,6 +335,30 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
|||||||
addCounterInternal(CounterType.get(counterType), n, source, fireEvents, table);
|
addCounterInternal(CounterType.get(counterType), n, source, fireEvents, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void receiveDamage(Pair<Integer, Boolean> dmg) {
|
||||||
|
damageReceivedThisTurn.add(dmg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getAssignedDamage() {
|
||||||
|
return getAssignedDamage(null, null);
|
||||||
|
}
|
||||||
|
public final int getAssignedCombatDamage() {
|
||||||
|
return getAssignedDamage(true, null);
|
||||||
|
}
|
||||||
|
public final int getAssignedDamage(Boolean isCombat, final Card source) {
|
||||||
|
int num = 0;
|
||||||
|
for (Pair<Integer, Boolean> dmg : damageReceivedThisTurn) {
|
||||||
|
if (isCombat != null && dmg.getRight() != isCombat) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (source != null && !getGame().getDamageLKI(dmg).getLeft().equalsWithTimestamp(source)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
num += dmg.getLeft();
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean equals(Object o) {
|
public final boolean equals(Object o) {
|
||||||
if (o == null) { return false; }
|
if (o == null) { return false; }
|
||||||
|
|||||||
@@ -327,8 +327,8 @@ public final class AbilityFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final TargetRestrictions readTarget(Map<String, String> mapParams) {
|
private static final TargetRestrictions readTarget(Map<String, String> mapParams) {
|
||||||
final String min = mapParams.containsKey("TargetMin") ? mapParams.get("TargetMin") : "1";
|
final String min = mapParams.getOrDefault("TargetMin", "1");
|
||||||
final String max = mapParams.containsKey("TargetMax") ? mapParams.get("TargetMax") : "1";
|
final String max = mapParams.getOrDefault("TargetMax", "1");
|
||||||
|
|
||||||
// TgtPrompt should only be needed for more complicated ValidTgts
|
// TgtPrompt should only be needed for more complicated ValidTgts
|
||||||
String tgtWhat = mapParams.get("ValidTgts");
|
String tgtWhat = mapParams.get("ValidTgts");
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
@@ -2030,7 +2031,7 @@ public class AbilityUtils {
|
|||||||
return doXMath(c.getTotalDamageDoneBy(), expr, c, ctb);
|
return doXMath(c.getTotalDamageDoneBy(), expr, c, ctb);
|
||||||
}
|
}
|
||||||
if (sq[0].equals("TotalDamageReceivedThisTurn")) {
|
if (sq[0].equals("TotalDamageReceivedThisTurn")) {
|
||||||
return doXMath(c.getTotalDamageReceivedThisTurn(), expr, c, ctb);
|
return doXMath(c.getAssignedDamage(), expr, c, ctb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sq[0].contains("CardPower")) {
|
if (sq[0].contains("CardPower")) {
|
||||||
@@ -2091,13 +2092,6 @@ public class AbilityUtils {
|
|||||||
return doXMath(c.getTimesMutated(), expr, c, ctb);
|
return doXMath(c.getTimesMutated(), expr, c, ctb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sq[0].startsWith("DamageDoneByPlayerThisTurn")) {
|
|
||||||
int sum = 0;
|
|
||||||
for (Player p : getDefinedPlayers(c, sq[1], ctb)) {
|
|
||||||
sum += c.getReceivedDamageByPlayerThisTurn(p);
|
|
||||||
}
|
|
||||||
return doXMath(sum, expr, c, ctb);
|
|
||||||
}
|
|
||||||
if (sq[0].equals("RegeneratedThisTurn")) {
|
if (sq[0].equals("RegeneratedThisTurn")) {
|
||||||
return doXMath(c.getRegeneratedThisTurn(), expr, c, ctb);
|
return doXMath(c.getRegeneratedThisTurn(), expr, c, ctb);
|
||||||
}
|
}
|
||||||
@@ -2359,20 +2353,28 @@ public class AbilityUtils {
|
|||||||
return doXMath(player.getOpponentsTotalPoisonCounters(), expr, c, ctb);
|
return doXMath(player.getOpponentsTotalPoisonCounters(), expr, c, ctb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sq[0].equals("YourDamageThisTurn")) {
|
|
||||||
return doXMath(player.getAssignedDamage(), expr, c, ctb);
|
|
||||||
}
|
|
||||||
if (sq[0].equals("TotalOppDamageThisTurn")) {
|
|
||||||
return doXMath(player.getOpponentsAssignedDamage(), expr, c, ctb);
|
|
||||||
}
|
|
||||||
if (sq[0].equals("MaxOppDamageThisTurn")) {
|
if (sq[0].equals("MaxOppDamageThisTurn")) {
|
||||||
return doXMath(player.getMaxOpponentAssignedDamage(), expr, c, ctb);
|
return doXMath(player.getMaxOpponentAssignedDamage(), expr, c, ctb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sq[0].startsWith("YourDamageSourcesThisTurn")) {
|
if (sq[0].contains("TotalDamageThisTurn")) {
|
||||||
Iterable<Card> allSrc = player.getAssignedDamageSources();
|
String[] props = l[0].split(" ");
|
||||||
String restriction = sq[0].split(" ")[1];
|
int sum = 0;
|
||||||
return doXMath(CardLists.getValidCardCount(allSrc, restriction, player, c, ctb), expr, c, ctb);
|
for (Pair<Integer, Boolean> p : c.getDamageReceivedThisTurn()) {
|
||||||
|
if (game.getDamageLKI(p).getLeft().isValid(props[1], player, c, ctb)) {
|
||||||
|
sum += p.getLeft();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return doXMath(sum, expr, c, ctb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sq[0].contains("DamageThisTurn")) {
|
||||||
|
String[] props = l[0].split(" ");
|
||||||
|
Boolean isCombat = null;
|
||||||
|
if (sq[0].contains("CombatDamage")) {
|
||||||
|
isCombat = true;
|
||||||
|
}
|
||||||
|
return doXMath(game.getDamageDoneThisTurn(isCombat, false, props[1], props[2], c, player, ctb).size(), expr, c, ctb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sq[0].equals("YourTurns")) {
|
if (sq[0].equals("YourTurns")) {
|
||||||
@@ -3325,12 +3327,6 @@ public class AbilityUtils {
|
|||||||
totDmg += p.getAssignedDamage();
|
totDmg += p.getAssignedDamage();
|
||||||
}
|
}
|
||||||
return doXMath(totDmg, m, source, ctb);
|
return doXMath(totDmg, m, source, ctb);
|
||||||
} else if (sq[0].contains("LifeLostThisTurn")) {
|
|
||||||
int totDmg = 0;
|
|
||||||
for (Player p : players) {
|
|
||||||
totDmg += p.getLifeLostThisTurn();
|
|
||||||
}
|
|
||||||
return doXMath(totDmg, m, source, ctb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (players.size() > 0) {
|
if (players.size() > 0) {
|
||||||
@@ -3387,7 +3383,7 @@ public class AbilityUtils {
|
|||||||
|
|
||||||
if (value.contains("DomainPlayer")) {
|
if (value.contains("DomainPlayer")) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
final CardCollectionView someCards = player.getCardsIn(ZoneType.Battlefield);
|
final CardCollectionView someCards = player.getLandsInPlay();
|
||||||
final List<String> basic = MagicColor.Constant.BASIC_LANDS;
|
final List<String> basic = MagicColor.Constant.BASIC_LANDS;
|
||||||
|
|
||||||
for (int i = 0; i < basic.size(); i++) {
|
for (int i = 0; i < basic.size(); i++) {
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ public class CounterEffect extends SpellAbilityEffect {
|
|||||||
for (final SpellAbility tgtSA : sas) {
|
for (final SpellAbility tgtSA : sas) {
|
||||||
final Card tgtSACard = tgtSA.getHostCard();
|
final Card tgtSACard = tgtSA.getHostCard();
|
||||||
// should remember even that spell cannot be countered, e.g. Dovescape
|
// should remember even that spell cannot be countered, e.g. Dovescape
|
||||||
|
// TODO use LKI in case the spell gets countered before (else X amounts would be missing)
|
||||||
if (sa.hasParam("RememberCounteredCMC")) {
|
if (sa.hasParam("RememberCounteredCMC")) {
|
||||||
sa.getHostCard().addRemembered(Integer.valueOf(tgtSACard.getCMC()));
|
sa.getHostCard().addRemembered(Integer.valueOf(tgtSACard.getCMC()));
|
||||||
}
|
}
|
||||||
@@ -152,9 +153,7 @@ public class CounterEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sa.hasParam("RememberCountered")) {
|
if (sa.hasParam("RememberCountered")) {
|
||||||
if (sa.getParam("RememberCountered").equals("True")) {
|
sa.getHostCard().addRemembered(tgtSACard);
|
||||||
sa.getHostCard().addRemembered(tgtSACard);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sa.hasParam("RememberSplicedOntoCounteredSpell")) {
|
if (sa.hasParam("RememberSplicedOntoCounteredSpell")) {
|
||||||
|
|||||||
@@ -285,6 +285,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO if cost isn't replaced should include alternative ones
|
||||||
// get basic spells (no flashback, etc.)
|
// get basic spells (no flashback, etc.)
|
||||||
List<SpellAbility> sas = AbilityUtils.getBasicSpellsFromPlayEffect(tgtCard, controller);
|
List<SpellAbility> sas = AbilityUtils.getBasicSpellsFromPlayEffect(tgtCard, controller);
|
||||||
if (sa.hasParam("ValidSA")) {
|
if (sa.hasParam("ValidSA")) {
|
||||||
|
|||||||
@@ -180,9 +180,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
private final Set<Object> rememberedObjects = Sets.newLinkedHashSet();
|
private final Set<Object> rememberedObjects = Sets.newLinkedHashSet();
|
||||||
private Map<Player, String> flipResult;
|
private Map<Player, String> flipResult;
|
||||||
|
|
||||||
private List<Pair<Card, Integer>> receivedDamageFromThisTurn = Lists.newArrayList();
|
|
||||||
private Map<Player, Integer> receivedDamageFromPlayerThisTurn = Maps.newHashMap();
|
|
||||||
|
|
||||||
private final Map<Card, Integer> assignedDamageMap = Maps.newTreeMap();
|
private final Map<Card, Integer> assignedDamageMap = Maps.newTreeMap();
|
||||||
|
|
||||||
private boolean isCommander = false;
|
private boolean isCommander = false;
|
||||||
@@ -257,7 +254,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
|
|
||||||
private String oracleText = "";
|
private String oracleText = "";
|
||||||
|
|
||||||
private int damage;
|
private Map<Integer, Integer> damage = Maps.newHashMap();
|
||||||
private boolean hasBeenDealtDeathtouchDamage;
|
private boolean hasBeenDealtDeathtouchDamage;
|
||||||
|
|
||||||
// regeneration
|
// regeneration
|
||||||
@@ -951,7 +948,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
}
|
}
|
||||||
devouredCards.add(c);
|
devouredCards.add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void clearDevoured() {
|
public final void clearDevoured() {
|
||||||
devouredCards = null;
|
devouredCards = null;
|
||||||
}
|
}
|
||||||
@@ -982,7 +978,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
delvedCards = null;
|
delvedCards = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public final CardCollectionView getConvoked() {
|
public final CardCollectionView getConvoked() {
|
||||||
return CardCollection.getView(convokedCards);
|
return CardCollection.getView(convokedCards);
|
||||||
}
|
}
|
||||||
@@ -5292,62 +5287,15 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
damageHistory = history;
|
damageHistory = history;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final List<Pair<Card, Integer>> getReceivedDamageFromThisTurn() {
|
public List<Pair<Integer, Boolean>> getDamageReceivedThisTurn() {
|
||||||
return receivedDamageFromThisTurn;
|
return damageReceivedThisTurn;
|
||||||
}
|
}
|
||||||
public final void setReceivedDamageFromThisTurn(final List<Pair<Card, Integer>> receivedDamageList) {
|
public void setDamageReceivedThisTurn(List<Pair<Integer, Boolean>> dmg) {
|
||||||
receivedDamageFromThisTurn = Lists.newArrayList(receivedDamageList);
|
damageReceivedThisTurn.addAll(dmg);
|
||||||
}
|
|
||||||
public final Map<Player, Integer> getReceivedDamageFromPlayerThisTurn() {
|
|
||||||
return receivedDamageFromPlayerThisTurn;
|
|
||||||
}
|
|
||||||
public final void setReceivedDamageFromPlayerThisTurn(final Map<Player, Integer> receivedDamageMap) {
|
|
||||||
receivedDamageFromPlayerThisTurn = Maps.newHashMap(receivedDamageMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getReceivedDamageByPlayerThisTurn(final Player p) {
|
|
||||||
if (receivedDamageFromPlayerThisTurn.containsKey(p)) {
|
|
||||||
return receivedDamageFromPlayerThisTurn.get(p);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void addReceivedDamageFromThisTurn(Card c, final int damage) {
|
|
||||||
int currentDamage = 0;
|
|
||||||
// because Aegar cares about the past state we need to keep all LKI instances
|
|
||||||
receivedDamageFromThisTurn.add(Pair.of(c.isLKI() ? c : CardUtil.getLKICopy(c), damage));
|
|
||||||
|
|
||||||
Player p = c.getController();
|
|
||||||
if (p != null) {
|
|
||||||
if (receivedDamageFromPlayerThisTurn.containsKey(p)) {
|
|
||||||
currentDamage = receivedDamageFromPlayerThisTurn.get(p);
|
|
||||||
}
|
|
||||||
receivedDamageFromPlayerThisTurn.put(p, damage+currentDamage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public final void resetReceivedDamageFromThisTurn() {
|
|
||||||
receivedDamageFromThisTurn.clear();
|
|
||||||
receivedDamageFromPlayerThisTurn.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getTotalDamageReceivedThisTurn() {
|
|
||||||
int total = 0;
|
|
||||||
for (Integer i : receivedDamageFromPlayerThisTurn.values()) {
|
|
||||||
total += i;
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasDealtDamageToOpponentThisTurn() {
|
public final boolean hasDealtDamageToOpponentThisTurn() {
|
||||||
for (final GameEntity e : getDamageHistory().getThisTurnDamaged().keySet()) {
|
return getDamageHistory().getDamageDoneThisTurn(null, true, null, "Player.Opponent", this, getController(), null) > 0;
|
||||||
if (e instanceof Player) {
|
|
||||||
final Player p = (Player) e;
|
|
||||||
if (getController().isOpponentOf(p)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5356,11 +5304,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
* @return the damage done to player p this turn
|
* @return the damage done to player p this turn
|
||||||
*/
|
*/
|
||||||
public final int getTotalDamageDoneBy() {
|
public final int getTotalDamageDoneBy() {
|
||||||
int sum = 0;
|
return getDamageHistory().getDamageDoneThisTurn(null, false, null, null, this, getController(), null);
|
||||||
for (final GameEntity e : getDamageHistory().getThisTurnDamaged().keySet()) {
|
|
||||||
sum += getDamageHistory().getThisTurnDamaged().get(e);
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is the amount of damage a creature needs to receive before it dies
|
// this is the amount of damage a creature needs to receive before it dies
|
||||||
@@ -5383,15 +5327,26 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final int getDamage() {
|
public final int getDamage() {
|
||||||
return damage;
|
int sum = 0;
|
||||||
|
for (int i : damage.values()) {
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
}
|
}
|
||||||
public final void setDamage(int damage0) {
|
public final void setDamage(int damage0) {
|
||||||
if (damage == damage0) { return; }
|
if (getDamage() == damage0) { return; }
|
||||||
damage = damage0;
|
damage.clear();
|
||||||
|
if (damage0 != 0) {
|
||||||
|
damage.put(0, damage0);
|
||||||
|
}
|
||||||
view.updateDamage(this);
|
view.updateDamage(this);
|
||||||
getGame().fireEvent(new GameEventCardStatsChanged(this));
|
getGame().fireEvent(new GameEventCardStatsChanged(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMaxDamageFromSource() {
|
||||||
|
return damage.isEmpty() ? 0 : Collections.max(damage.values());
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean hasBeenDealtDeathtouchDamage() {
|
public final boolean hasBeenDealtDeathtouchDamage() {
|
||||||
return hasBeenDealtDeathtouchDamage;
|
return hasBeenDealtDeathtouchDamage;
|
||||||
}
|
}
|
||||||
@@ -5542,14 +5497,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
// Run replacement effects
|
// Run replacement effects
|
||||||
getGame().getReplacementHandler().run(ReplacementType.DealtDamage, AbilityKey.mapFromAffected(this));
|
getGame().getReplacementHandler().run(ReplacementType.DealtDamage, AbilityKey.mapFromAffected(this));
|
||||||
|
|
||||||
addReceivedDamageFromThisTurn(source, damageIn);
|
|
||||||
source.getDamageHistory().registerDamage(this, damageIn);
|
|
||||||
if (isCombat) {
|
|
||||||
source.getDamageHistory().registerCombatDamage(this, damageIn);
|
|
||||||
} else {
|
|
||||||
getDamageHistory().setHasBeenDealtNonCombatDamageThisTurn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run triggers
|
// Run triggers
|
||||||
Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||||
runParams.put(AbilityKey.DamageSource, source);
|
runParams.put(AbilityKey.DamageSource, source);
|
||||||
@@ -5576,7 +5523,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
damageType = DamageType.M1M1Counters;
|
damageType = DamageType.M1M1Counters;
|
||||||
}
|
}
|
||||||
else { // 120.3e
|
else { // 120.3e
|
||||||
damage += damageIn;
|
int old = damage.getOrDefault(Objects.hash(source.getId(), source.getTimestamp()), 0);
|
||||||
|
damage.put(Objects.hash(source.getId(), source.getTimestamp()), old + damageIn);
|
||||||
view.updateDamage(this);
|
view.updateDamage(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5714,7 +5662,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setForetold(final boolean foretold) {
|
public final void setForetold(final boolean foretold) {
|
||||||
this.foretold = foretold;
|
this.foretold = foretold;
|
||||||
}
|
}
|
||||||
@@ -5732,7 +5679,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
public final void setForetoldThisTurn(final boolean foretoldThisTurn) {
|
public final void setForetoldThisTurn(final boolean foretoldThisTurn) {
|
||||||
this.foretoldThisTurn = foretoldThisTurn;
|
this.foretoldThisTurn = foretoldThisTurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetForetoldThisTurn() {
|
public void resetForetoldThisTurn() {
|
||||||
foretoldThisTurn = false;
|
foretoldThisTurn = false;
|
||||||
}
|
}
|
||||||
@@ -5803,7 +5749,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
public final long getBestowTimestamp() {
|
public final long getBestowTimestamp() {
|
||||||
return bestowTimestamp;
|
return bestowTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setBestowTimestamp(final long t) {
|
public final void setBestowTimestamp(final long t) {
|
||||||
bestowTimestamp = t;
|
bestowTimestamp = t;
|
||||||
}
|
}
|
||||||
@@ -6206,7 +6151,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
setDamage(0);
|
setDamage(0);
|
||||||
}
|
}
|
||||||
setHasBeenDealtDeathtouchDamage(false);
|
setHasBeenDealtDeathtouchDamage(false);
|
||||||
resetReceivedDamageFromThisTurn();
|
|
||||||
setRegeneratedThisTurn(0);
|
setRegeneratedThisTurn(0);
|
||||||
resetShield();
|
resetShield();
|
||||||
setBecameTargetThisTurn(false);
|
setBecameTargetThisTurn(false);
|
||||||
@@ -6214,6 +6158,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
clearMustBlockCards();
|
clearMustBlockCards();
|
||||||
getDamageHistory().setCreatureAttackedLastTurnOf(turn, getDamageHistory().getCreatureAttacksThisTurn() > 0);
|
getDamageHistory().setCreatureAttackedLastTurnOf(turn, getDamageHistory().getCreatureAttacksThisTurn() > 0);
|
||||||
getDamageHistory().newTurn();
|
getDamageHistory().newTurn();
|
||||||
|
damageReceivedThisTurn.clear();
|
||||||
clearBlockedByThisTurn();
|
clearBlockedByThisTurn();
|
||||||
clearBlockedThisTurn();
|
clearBlockedThisTurn();
|
||||||
resetMayPlayTurn();
|
resetMayPlayTurn();
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ package forge.game.card;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import forge.game.CardTraitBase;
|
||||||
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.game.zone.ZoneType;
|
||||||
@@ -22,7 +24,6 @@ public class CardDamageHistory {
|
|||||||
private boolean creatureBlockedThisCombat = false;
|
private boolean creatureBlockedThisCombat = false;
|
||||||
private boolean creatureGotBlockedThisCombat = false;
|
private boolean creatureGotBlockedThisCombat = 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();
|
||||||
@@ -30,14 +31,13 @@ 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 List<Pair<Integer, Boolean>> damageDoneThisTurn = Lists.newArrayList();
|
||||||
|
|
||||||
// only needed for Glen Elendra (Plane)
|
// only needed for Glen Elendra (Plane)
|
||||||
private final List<Player> damagedThisCombat = Lists.newArrayList();
|
private final List<Player> damagedThisCombat = Lists.newArrayList();
|
||||||
// only needed for The Fallen
|
// only needed for The Fallen
|
||||||
private final FCollection<GameEntity> damagedThisGame = new FCollection<>();
|
private final FCollection<GameEntity> damagedThisGame = new FCollection<>();
|
||||||
|
boolean hasdealtDamagetoAny = false;
|
||||||
private final Map<GameEntity, Integer> damagedThisTurn = Maps.newHashMap();
|
|
||||||
private final Map<GameEntity, Integer> damagedThisTurnInCombat = Maps.newHashMap();
|
|
||||||
private boolean receivedNonCombatDamageThisTurn = false;
|
|
||||||
|
|
||||||
public final boolean getHasdealtDamagetoAny() {
|
public final boolean getHasdealtDamagetoAny() {
|
||||||
return hasdealtDamagetoAny;
|
return hasdealtDamagetoAny;
|
||||||
@@ -225,38 +225,9 @@ public class CardDamageHistory {
|
|||||||
return this.creatureGotBlockedThisCombat;
|
return this.creatureGotBlockedThisCombat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Getter for the field <code>receivedNonCombatDamageThisTurn</code>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a boolean.
|
|
||||||
*/
|
|
||||||
public boolean hasBeenDealtNonCombatDamageThisTurn() {
|
|
||||||
return this.receivedNonCombatDamageThisTurn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Setter for the field <code>receivedNonCombatDamageThisTurn</code>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param b
|
|
||||||
* a boolean.
|
|
||||||
*/
|
|
||||||
public void setHasBeenDealtNonCombatDamageThisTurn(boolean b) {
|
|
||||||
this.receivedNonCombatDamageThisTurn = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final List<Player> getThisCombatDamaged() {
|
public final List<Player> getThisCombatDamaged() {
|
||||||
return damagedThisCombat;
|
return damagedThisCombat;
|
||||||
}
|
}
|
||||||
public final Map<GameEntity, Integer> getThisTurnDamaged() {
|
|
||||||
return damagedThisTurn;
|
|
||||||
}
|
|
||||||
public final Map<GameEntity, Integer> getThisTurnCombatDamaged() {
|
|
||||||
return damagedThisTurnInCombat;
|
|
||||||
}
|
|
||||||
public final FCollection<GameEntity> getThisGameDamaged() {
|
public final FCollection<GameEntity> getThisGameDamaged() {
|
||||||
return damagedThisGame;
|
return damagedThisGame;
|
||||||
}
|
}
|
||||||
@@ -264,38 +235,44 @@ public class CardDamageHistory {
|
|||||||
* TODO: Write javadoc for this method.
|
* TODO: Write javadoc for this method.
|
||||||
* @param player
|
* @param player
|
||||||
*/
|
*/
|
||||||
public void registerCombatDamage(GameEntity entity, int amount) {
|
public void registerDamage(int damage, boolean isCombat, Card sourceLKI, GameEntity target, Map<Integer, Card> lkiCache) {
|
||||||
int old = 0;
|
damagedThisGame.add(target);
|
||||||
if (entity instanceof Player) {
|
|
||||||
damagedThisCombat.add((Player) entity);
|
|
||||||
}
|
|
||||||
old = 0;
|
|
||||||
if (damagedThisTurnInCombat.containsKey(entity)) {
|
|
||||||
old = damagedThisTurnInCombat.get(entity);
|
|
||||||
}
|
|
||||||
damagedThisTurnInCombat.put(entity, old + amount);
|
|
||||||
hasdealtDamagetoAny = true;
|
hasdealtDamagetoAny = true;
|
||||||
|
if (isCombat && target instanceof Player) {
|
||||||
|
damagedThisCombat.add((Player) target);
|
||||||
|
}
|
||||||
|
Pair<Integer, Boolean> dmg = Pair.of(damage, isCombat);
|
||||||
|
damageDoneThisTurn.add(dmg);
|
||||||
|
target.receiveDamage(dmg);
|
||||||
|
sourceLKI.getGame().addGlobalDamageHistory(this, dmg, sourceLKI.isLKI() ? sourceLKI : CardUtil.getLKICopy(sourceLKI, lkiCache), CardUtil.getLKICopy(target, lkiCache));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public int getDamageDoneThisTurn(Boolean isCombat, boolean anyIsEnough, String validSourceCard, String validTargetEntity, Card source, Player sourceController, CardTraitBase ctb) {
|
||||||
* TODO: Write javadoc for this method.
|
int sum = 0;
|
||||||
* @param player
|
for (Pair<Integer, Boolean> damage : damageDoneThisTurn) {
|
||||||
*/
|
Pair<Card, GameEntity> sourceToTarget = sourceController.getGame().getDamageLKI(damage);
|
||||||
public void registerDamage(GameEntity entity, int amount) {
|
|
||||||
int old = 0;
|
if (isCombat != null && damage.getRight() != isCombat) {
|
||||||
if (damagedThisTurn.containsKey(entity)) {
|
continue;
|
||||||
old = damagedThisTurn.get(entity);
|
}
|
||||||
|
if (validSourceCard != null && !sourceToTarget.getLeft().isValid(validSourceCard.split(","), sourceController, source == null ? sourceToTarget.getLeft() : source, ctb)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (validTargetEntity != null && !sourceToTarget.getRight().isValid(validTargetEntity.split(","), sourceController, source, ctb)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sum += damage.getLeft();
|
||||||
|
if (anyIsEnough) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
damagedThisTurn.put(entity, old + amount);
|
return sum;
|
||||||
damagedThisGame.add(entity);
|
|
||||||
hasdealtDamagetoAny = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void newTurn() {
|
public void newTurn() {
|
||||||
damagedThisCombat.clear();
|
|
||||||
damagedThisTurnInCombat.clear();
|
|
||||||
damagedThisTurn.clear();
|
|
||||||
attackedThisTurn.clear();
|
attackedThisTurn.clear();
|
||||||
|
damagedThisCombat.clear();
|
||||||
|
damageDoneThisTurn.clear();
|
||||||
|
|
||||||
// if card already LTB we can safely dereference (allows quite a few objects to be cleaned up earlier for bigger boardstates)
|
// 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();
|
CardCollection toRemove = new CardCollection();
|
||||||
@@ -307,7 +284,6 @@ public class CardDamageHistory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
damagedThisGame.removeAll(toRemove);
|
damagedThisGame.removeAll(toRemove);
|
||||||
setHasBeenDealtNonCombatDamageThisTurn(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endCombat() {
|
public void endCombat() {
|
||||||
|
|||||||
@@ -608,35 +608,6 @@ public class CardProperty {
|
|||||||
if ((card.getCloneOrigin() == null) || !card.getCloneOrigin().equals(source)) {
|
if ((card.getCloneOrigin() == null) || !card.getCloneOrigin().equals(source)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("DamagedBy")) {
|
|
||||||
List<Card> damaged = Lists.newArrayList();
|
|
||||||
for (Pair<Card, Integer> pair : card.getReceivedDamageFromThisTurn()) {
|
|
||||||
damaged.add(pair.getLeft());
|
|
||||||
}
|
|
||||||
if (property.endsWith("Source") || property.equals("DamagedBy")) {
|
|
||||||
if (!damaged.contains(source)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
String prop = property.substring("DamagedBy".length());
|
|
||||||
boolean found = Iterables.any(damaged, CardPredicates.restriction(prop, sourceController, source, spellAbility));
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
for (Card d : AbilityUtils.getDefinedCards(source, prop, spellAbility)) {
|
|
||||||
if (damaged.contains(d)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (property.startsWith("Damaged")) {
|
|
||||||
if (!card.getDamageHistory().getThisTurnDamaged().containsKey(source)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (property.startsWith("SharesCMCWith")) {
|
} else if (property.startsWith("SharesCMCWith")) {
|
||||||
if (property.equals("SharesCMCWith")) {
|
if (property.equals("SharesCMCWith")) {
|
||||||
if (!card.sharesCMCWith(source)) {
|
if (!card.sharesCMCWith(source)) {
|
||||||
@@ -1133,38 +1104,78 @@ public class CardProperty {
|
|||||||
&& !card.getDamageHistory().hasBlockedSinceLastUpkeepOf(sourceController)) {
|
&& !card.getDamageHistory().hasBlockedSinceLastUpkeepOf(sourceController)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else if (property.startsWith("DamagedBy")) {
|
||||||
|
String prop = property.substring("DamagedBy".length());
|
||||||
|
CardCollection def = null;
|
||||||
|
if (prop.startsWith(" ")) {
|
||||||
|
def = AbilityUtils.getDefinedCards(source, prop.substring(1), spellAbility);
|
||||||
|
}
|
||||||
|
boolean found = false;
|
||||||
|
for (Pair<Integer, Boolean> p : card.getDamageReceivedThisTurn()) {
|
||||||
|
Card dmgSource = game.getDamageLKI(p).getLeft();
|
||||||
|
if (def != null) {
|
||||||
|
for (Card c : def) {
|
||||||
|
if (dmgSource.equalsWithTimestamp(c)) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (prop.isEmpty() && dmgSource.equalsWithTimestamp(source)) {
|
||||||
|
found = true;
|
||||||
|
} else if (dmgSource.isValid(prop.split(","), sourceController, source, spellAbility)) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (property.startsWith("Damaged")) {
|
||||||
|
for (Pair<Integer, Boolean> p : source.getDamageReceivedThisTurn()) {
|
||||||
|
boolean found = false;
|
||||||
|
if (game.getDamageLKI(p).getLeft().equalsWithTimestamp(card)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (property.startsWith("dealtCombatDamageThisCombat")) {
|
||||||
|
if (card.getDamageHistory().getThisCombatDamaged().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else if (property.startsWith("dealtDamageToYouThisTurn")) {
|
} else if (property.startsWith("dealtDamageToYouThisTurn")) {
|
||||||
if (!card.getDamageHistory().getThisTurnDamaged().containsKey(sourceController)) {
|
if (card.getDamageHistory().getDamageDoneThisTurn(null, true, null, "You", card, sourceController, spellAbility) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("dealtDamageToOppThisTurn")) {
|
} else if (property.startsWith("dealtDamageToOppThisTurn")) {
|
||||||
if (!card.hasDealtDamageToOpponentThisTurn()) {
|
if (!card.hasDealtDamageToOpponentThisTurn()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//dealtCombatDamageThisCombat <valid>, dealtCombatDamageThisTurn <valid>, and notDealt versions
|
|
||||||
} 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];
|
||||||
final Iterable<GameEntity> list = property.contains("ThisCombat") ?
|
boolean found = card.getDamageHistory().getDamageDoneThisTurn(true, true, null, v, card, sourceController, spellAbility) > 0;
|
||||||
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")) {
|
if (found == property.startsWith("not")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("controllerWasDealtCombatDamageByThisTurn")) {
|
} else if (property.startsWith("controllerWasDealtCombatDamageByThisTurn")) {
|
||||||
if (!source.getDamageHistory().getThisTurnCombatDamaged().containsKey(controller)) {
|
if (source.getDamageHistory().getDamageDoneThisTurn(true, true, null, "You", card, controller, spellAbility) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("controllerWasDealtDamageByThisTurn")) {
|
} else if (property.startsWith("controllerWasDealtDamageByThisTurn")) {
|
||||||
if (!source.getDamageHistory().getThisTurnDamaged().containsKey(controller)) {
|
if (source.getDamageHistory().getDamageDoneThisTurn(null, true, null, "You", card, controller, spellAbility) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("wasDealtDamageThisTurn")) {
|
} else if (property.startsWith("wasDealtDamageThisTurn")) {
|
||||||
if (card.getReceivedDamageFromPlayerThisTurn().isEmpty()) {
|
if (card.getAssignedDamage() == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.equals("wasDealtNonCombatDamageThisTurn")) {
|
} else if (property.equals("wasDealtNonCombatDamageThisTurn")) {
|
||||||
if (!card.getDamageHistory().hasBeenDealtNonCombatDamageThisTurn()) {
|
if (card.getAssignedDamage(false, null) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("wasDealtDamageByThisGame")) {
|
} else if (property.startsWith("wasDealtDamageByThisGame")) {
|
||||||
|
|||||||
@@ -250,9 +250,8 @@ public final class CardUtil {
|
|||||||
newCopy.setColor(in.getColor().getColor());
|
newCopy.setColor(in.getColor().getColor());
|
||||||
newCopy.setPhasedOut(in.isPhasedOut());
|
newCopy.setPhasedOut(in.isPhasedOut());
|
||||||
|
|
||||||
newCopy.setReceivedDamageFromThisTurn(in.getReceivedDamageFromThisTurn());
|
|
||||||
newCopy.setReceivedDamageFromPlayerThisTurn(in.getReceivedDamageFromPlayerThisTurn());
|
|
||||||
newCopy.setDamageHistory(in.getDamageHistory());
|
newCopy.setDamageHistory(in.getDamageHistory());
|
||||||
|
newCopy.setDamageReceivedThisTurn(in.getDamageReceivedThisTurn());
|
||||||
for (Card c : in.getBlockedThisTurn()) {
|
for (Card c : in.getBlockedThisTurn()) {
|
||||||
newCopy.addBlockedThisTurn(c);
|
newCopy.addBlockedThisTurn(c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,8 +147,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
private int life = 20;
|
private int life = 20;
|
||||||
private int startingLife = 20;
|
private int startingLife = 20;
|
||||||
private int lifeStartedThisTurnWith = startingLife;
|
private int lifeStartedThisTurnWith = startingLife;
|
||||||
private final Map<Card, Integer> assignedDamage = Maps.newHashMap();
|
|
||||||
private final Map<Card, Integer> assignedCombatDamage = Maps.newHashMap();
|
|
||||||
private int spellsCastThisTurn;
|
private int spellsCastThisTurn;
|
||||||
private int spellsCastThisGame;
|
private int spellsCastThisGame;
|
||||||
private int spellsCastLastTurn;
|
private int spellsCastLastTurn;
|
||||||
@@ -219,7 +217,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
private Map<Card, Card> maingameCardsMap = Maps.newHashMap();
|
private Map<Card, Card> maingameCardsMap = Maps.newHashMap();
|
||||||
|
|
||||||
private CardCollection currentPlanes = new CardCollection();
|
private CardCollection currentPlanes = new CardCollection();
|
||||||
private Set<String> prowl = Sets.newHashSet();
|
|
||||||
|
|
||||||
private PlayerStatistics stats = new PlayerStatistics();
|
private PlayerStatistics stats = new PlayerStatistics();
|
||||||
private PlayerController controller;
|
private PlayerController controller;
|
||||||
@@ -704,19 +701,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int old = assignedDamage.containsKey(source) ? assignedDamage.get(source) : 0;
|
|
||||||
assignedDamage.put(source, old + amount);
|
|
||||||
source.getDamageHistory().registerDamage(this, amount);
|
|
||||||
|
|
||||||
if (isCombat) {
|
|
||||||
old = assignedCombatDamage.containsKey(source) ? assignedCombatDamage.get(source) : 0;
|
|
||||||
assignedCombatDamage.put(source, old + amount);
|
|
||||||
for (final String type : source.getType().getCreatureTypes()) {
|
|
||||||
source.getController().addProwlType(type);
|
|
||||||
}
|
|
||||||
source.getDamageHistory().registerCombatDamage(this, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run triggers
|
// Run triggers
|
||||||
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||||
runParams.put(AbilityKey.DamageSource, source);
|
runParams.put(AbilityKey.DamageSource, source);
|
||||||
@@ -830,49 +814,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
simultaneousDamage = 0;
|
simultaneousDamage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void clearAssignedDamage() {
|
|
||||||
assignedDamage.clear();
|
|
||||||
assignedCombatDamage.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getAssignedDamage() {
|
|
||||||
int num = 0;
|
|
||||||
for (final Integer value : assignedDamage.values()) {
|
|
||||||
num += value;
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getAssignedCombatDamage() {
|
|
||||||
int num = 0;
|
|
||||||
for (final Integer value : assignedCombatDamage.values()) {
|
|
||||||
num += value;
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Iterable<Card> getAssignedDamageSources() {
|
|
||||||
return assignedDamage.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getAssignedDamage(final Card c) {
|
|
||||||
return assignedDamage.get(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getAssignedDamage(final String type) {
|
|
||||||
final Map<Card, Integer> valueMap = Maps.newHashMap();
|
|
||||||
for (final Card c : assignedDamage.keySet()) {
|
|
||||||
if (c.getType().hasStringType(type)) {
|
|
||||||
valueMap.put(c, assignedDamage.get(c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int num = 0;
|
|
||||||
for (final Integer value : valueMap.values()) {
|
|
||||||
num += value;
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the total damage assigned to this player's opponents this turn.
|
* Get the total damage assigned to this player's opponents this turn.
|
||||||
*/
|
*/
|
||||||
@@ -2082,8 +2023,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasBloodthirst() {
|
public final boolean hasBloodthirst() {
|
||||||
for (Player p : game.getRegisteredPlayers()) {
|
for (Player p : getRegisteredOpponents()) {
|
||||||
if (p.isOpponentOf(this) && p.getAssignedDamage() > 0) {
|
if (p.getAssignedDamage() > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2102,14 +2043,12 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return lost;
|
return lost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasProwl(final String type) {
|
public final boolean hasProwl(final Set<String> types) {
|
||||||
return prowl.contains(type);
|
StringBuilder sb = new StringBuilder();
|
||||||
}
|
for (String type : types) {
|
||||||
public final void addProwlType(final String type) {
|
sb.append("Card.YouCtrl+").append(type).append(",");
|
||||||
prowl.add(type);
|
}
|
||||||
}
|
return !game.getDamageDoneThisTurn(true, true, sb.toString(), "Player", null, this, null).isEmpty();
|
||||||
public final void resetProwl() {
|
|
||||||
prowl.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setLibrarySearched(final int l) {
|
public final void setLibrarySearched(final int l) {
|
||||||
@@ -2150,7 +2089,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
} else if (incR[0].equals("EnchantedController")) {
|
} else if (incR[0].equals("EnchantedController")) {
|
||||||
final GameEntity enchanted = source.getEntityAttachedTo();
|
final GameEntity enchanted = source.getEntityAttachedTo();
|
||||||
if ((enchanted == null) || !(enchanted instanceof Card)) {
|
if (enchanted == null || !(enchanted instanceof Card)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final Card enchantedCard = (Card) enchanted;
|
final Card enchantedCard = (Card) enchanted;
|
||||||
@@ -2239,10 +2178,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
investigatedThisTurn = 0;
|
investigatedThisTurn = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final List<Card> getSacrificedThisTurn() {
|
|
||||||
return sacrificedThisTurn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void addSacrificedThisTurn(final Card c, final SpellAbility source) {
|
public final void addSacrificedThisTurn(final Card c, final SpellAbility source) {
|
||||||
// Play the Sacrifice sound
|
// Play the Sacrifice sound
|
||||||
game.fireEvent(new GameEventCardSacrificed());
|
game.fireEvent(new GameEventCardSacrificed());
|
||||||
@@ -2260,6 +2195,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
game.getTriggerHandler().runTrigger(TriggerType.Sacrificed, runParams, false);
|
game.getTriggerHandler().runTrigger(TriggerType.Sacrificed, runParams, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final List<Card> getSacrificedThisTurn() {
|
||||||
|
return sacrificedThisTurn;
|
||||||
|
}
|
||||||
public final void resetSacrificedThisTurn() {
|
public final void resetSacrificedThisTurn() {
|
||||||
sacrificedThisTurn.clear();
|
sacrificedThisTurn.clear();
|
||||||
}
|
}
|
||||||
@@ -2452,10 +2390,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
resetCycledThisTurn();
|
resetCycledThisTurn();
|
||||||
resetEquippedThisTurn();
|
resetEquippedThisTurn();
|
||||||
resetSacrificedThisTurn();
|
resetSacrificedThisTurn();
|
||||||
clearAssignedDamage();
|
|
||||||
resetVenturedThisTurn();
|
resetVenturedThisTurn();
|
||||||
setRevolt(false);
|
setRevolt(false);
|
||||||
resetProwl();
|
|
||||||
setSpellsCastLastTurn(getSpellsCastThisTurn());
|
setSpellsCastLastTurn(getSpellsCastThisTurn());
|
||||||
resetSpellsCastThisTurn();
|
resetSpellsCastThisTurn();
|
||||||
setLifeLostLastTurn(getLifeLostThisTurn());
|
setLifeLostLastTurn(getLifeLostThisTurn());
|
||||||
@@ -2467,6 +2403,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
setLibrarySearched(0);
|
setLibrarySearched(0);
|
||||||
setNumManaConversion(0);
|
setNumManaConversion(0);
|
||||||
|
|
||||||
|
damageReceivedThisTurn.clear();
|
||||||
|
|
||||||
// set last turn nr
|
// set last turn nr
|
||||||
if (game.getPhaseHandler().isPlayerTurn(this)) {
|
if (game.getPhaseHandler().isPlayerTurn(this)) {
|
||||||
setAttackedPlayersMyLastTurn(attackedPlayersThisTurn);
|
setAttackedPlayersMyLastTurn(attackedPlayersThisTurn);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package forge.game.player;
|
package forge.game.player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import forge.game.CardTraitBase;
|
import forge.game.CardTraitBase;
|
||||||
@@ -86,81 +87,66 @@ public class PlayerProperty {
|
|||||||
if (!player.hasBlessing()) {
|
if (!player.hasBlessing()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else if (property.startsWith("damageDoneSingleSource")) {
|
||||||
|
String props = property.split(" ")[1];
|
||||||
|
List<Integer> sourceDmg = game.getDamageDoneThisTurn(null, false, "Card.YouCtrl", null, source, sourceController, spellAbility);
|
||||||
|
int maxDmg = sourceDmg.isEmpty() ? 0 : Collections.max(sourceDmg);
|
||||||
|
if (!Expressions.compare(maxDmg, props.substring(0, 2), AbilityUtils.calculateAmount(source, props.substring(2), spellAbility))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else if (property.startsWith("wasDealtCombatDamageThisCombatBy ")) {
|
} else if (property.startsWith("wasDealtCombatDamageThisCombatBy ")) {
|
||||||
String v = property.split(" ")[1];
|
String v = property.split(" ")[1];
|
||||||
|
boolean found = true;
|
||||||
int count = 1;
|
|
||||||
if (v.contains("_AtLeast")) {
|
|
||||||
count = Integer.parseInt(v.substring(v.indexOf("_AtLeast") + 8));
|
|
||||||
v = v.substring(0, v.indexOf("_AtLeast")).replace("Valid:", "Valid ");
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility);
|
final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility);
|
||||||
int found = 0;
|
|
||||||
for (final Card card : cards) {
|
for (final Card card : cards) {
|
||||||
if (card.getDamageHistory().getThisCombatDamaged().contains(player)) {
|
if (card.getDamageHistory().getThisCombatDamaged().contains(player)) {
|
||||||
found++;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found < count) {
|
if (!found) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("wasDealtDamageThisGameBy ")) {
|
} else if (property.startsWith("wasDealtDamageThisGameBy ")) {
|
||||||
String v = property.split(" ")[1];
|
String v = property.split(" ")[1];
|
||||||
|
boolean found = true;
|
||||||
int count = 1;
|
|
||||||
if (v.contains("_AtLeast")) {
|
|
||||||
count = Integer.parseInt(v.substring(v.indexOf("_AtLeast") + 8));
|
|
||||||
v = TextUtil.fastReplace(v.substring(0, v.indexOf("_AtLeast")), "Valid:", "Valid ");
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility);
|
final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility);
|
||||||
int found = 0;
|
|
||||||
for (final Card card : cards) {
|
for (final Card card : cards) {
|
||||||
if (card.getDamageHistory().getThisGameDamaged().contains(player)) {
|
if (card.getDamageHistory().getThisGameDamaged().contains(player)) {
|
||||||
found++;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found < count) {
|
if (!found) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("wasDealtDamageThisTurnBy ")) {
|
} else if (property.startsWith("wasDealt")) {
|
||||||
String v = property.split(" ")[1];
|
boolean found = false;
|
||||||
int count = 1;
|
String validCard = null;
|
||||||
|
Boolean combat = null;
|
||||||
if (v.contains("_AtLeast")) {
|
if (property.contains("CombatDamage")) {
|
||||||
count = Integer.parseInt(v.substring(v.indexOf("_AtLeast") + 8));
|
combat = true;
|
||||||
v = TextUtil.fastReplace(v.substring(0, v.indexOf("_AtLeast")), "Valid:", "Valid ");
|
|
||||||
}
|
}
|
||||||
|
if (property.contains("ThisTurnBySource")) {
|
||||||
|
found = source.getDamageHistory().getDamageDoneThisTurn(combat, validCard == null, validCard, "You", source, player, spellAbility) > 0;
|
||||||
|
} else {
|
||||||
|
String comp = "GE";
|
||||||
|
int right = 1;
|
||||||
|
int numValid = 0;
|
||||||
|
|
||||||
final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility);
|
if (property.contains("ThisTurnBy")) {
|
||||||
int found = 0;
|
String[] props = property.split(" ");
|
||||||
for (final Card card : cards) {
|
validCard = props[1];
|
||||||
if (card.getDamageHistory().getThisTurnDamaged().containsKey(player)) {
|
if (props.length > 2) {
|
||||||
found++;
|
comp = props[2].substring(0, 2);
|
||||||
|
right = AbilityUtils.calculateAmount(source, props[2].substring(2), spellAbility);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (found < count) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (property.startsWith("wasDealtCombatDamageThisTurnBy ")) {
|
|
||||||
String v = property.split(" ")[1];
|
|
||||||
|
|
||||||
int count = 1;
|
numValid = game.getDamageDoneThisTurn(combat, validCard == null, validCard, "You", source, player, spellAbility).size();
|
||||||
if (v.contains("_AtLeast")) {
|
found = Expressions.compare(numValid, comp, right);
|
||||||
count = Integer.parseInt(v.substring(v.indexOf("_AtLeast") + 8));
|
|
||||||
v = TextUtil.fastReplace(v.substring(0, v.indexOf("_AtLeast")), "Valid:", "Valid ");
|
|
||||||
}
|
}
|
||||||
|
if (!found) {
|
||||||
final List<Card> cards = AbilityUtils.getDefinedCards(source, v, spellAbility);
|
|
||||||
|
|
||||||
int found = 0;
|
|
||||||
for (final Card card : cards) {
|
|
||||||
if (card.getDamageHistory().getThisTurnCombatDamaged().containsKey(player)) {
|
|
||||||
found++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found < count) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.equals("attackedBySourceThisCombat")) {
|
} else if (property.equals("attackedBySourceThisCombat")) {
|
||||||
@@ -171,18 +157,10 @@ public class PlayerProperty {
|
|||||||
if (!source.getDamageHistory().hasAttackedThisTurn(player)) {
|
if (!source.getDamageHistory().hasAttackedThisTurn(player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.equals("wasDealtDamageThisTurn")) {
|
} else if (property.equals("Defending")) {
|
||||||
if (player.getAssignedDamage() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (property.equals("Defending")) {
|
|
||||||
if (!game.getCombat().getAttackersAndDefenders().values().contains(player)) {
|
if (!game.getCombat().getAttackersAndDefenders().values().contains(player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.equals("wasDealtCombatDamageThisTurn")) {
|
|
||||||
if (player.getAssignedCombatDamage() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (property.equals("LostLifeThisTurn")) {
|
} else if (property.equals("LostLifeThisTurn")) {
|
||||||
if (player.getLifeLostThisTurn() <= 0) {
|
if (player.getLifeLostThisTurn() <= 0) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
public AbilityManaPart(final Card sourceCard, final Map<String, String> params) {
|
public AbilityManaPart(final Card sourceCard, final Map<String, String> params) {
|
||||||
this.sourceCard = sourceCard;
|
this.sourceCard = sourceCard;
|
||||||
|
|
||||||
origProduced = params.containsKey("Produced") ? params.get("Produced") : "1";
|
origProduced = params.getOrDefault("Produced", "1");
|
||||||
this.manaRestrictions = params.containsKey("RestrictValid") ? params.get("RestrictValid") : "";
|
this.manaRestrictions = params.getOrDefault("RestrictValid", "");
|
||||||
this.cannotCounterSpell = params.get("AddsNoCounter");
|
this.cannotCounterSpell = params.get("AddsNoCounter");
|
||||||
this.addsKeywords = params.get("AddsKeywords");
|
this.addsKeywords = params.get("AddsKeywords");
|
||||||
this.addsKeywordsType = params.get("AddsKeywordsType");
|
this.addsKeywordsType = params.get("AddsKeywordsType");
|
||||||
|
|||||||
@@ -434,13 +434,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sa.isProwl()) {
|
if (sa.isProwl()) {
|
||||||
boolean prowlFlag = false;
|
if (!activator.hasProwl(c.getType().getCreatureTypes())) {
|
||||||
for (final String type : c.getType().getCreatureTypes()) {
|
|
||||||
if (activator.hasProwl(type)) {
|
|
||||||
prowlFlag = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!prowlFlag) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ public class TriggerChangesZone extends Trigger {
|
|||||||
// need to check the ChangeZone LKI copy for damage, otherwise it'll return 0 for a new object in the new zone
|
// need to check the ChangeZone LKI copy for damage, otherwise it'll return 0 for a new object in the new zone
|
||||||
Card lkiCard = card.getGame().getChangeZoneLKIInfo(card);
|
Card lkiCard = card.getGame().getChangeZoneLKIInfo(card);
|
||||||
|
|
||||||
final boolean expr = Expressions.compare(lkiCard.getTotalDamageReceivedThisTurn(), cond, rightSide);
|
final boolean expr = Expressions.compare(lkiCard.getAssignedDamage(), cond, rightSide);
|
||||||
if (!expr) {
|
if (!expr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public class TriggerDamageDone extends Trigger {
|
|||||||
|
|
||||||
if (target instanceof Player) {
|
if (target instanceof Player) {
|
||||||
final Player trigTgt = (Player) target;
|
final Player trigTgt = (Player) target;
|
||||||
if (!Expressions.compare(trigTgt.getAssignedDamage(source), operator, operand)) {
|
if (!Expressions.compare(trigTgt.getAssignedDamage(null, source), operator, operand)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ Types:Legendary Creature Human Pirate
|
|||||||
PT:3/3
|
PT:3/3
|
||||||
S:Mode$ Continuous | Affected$ Creature.Pirate+Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other Pirates you control get +1/+1.
|
S:Mode$ Continuous | Affected$ Creature.Pirate+Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other Pirates you control get +1/+1.
|
||||||
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigGainCtrl | TriggerDescription$ At the beginning of your end step, gain control of target nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn.
|
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigGainCtrl | TriggerDescription$ At the beginning of your end step, gain control of target nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn.
|
||||||
SVar:TrigGainCtrl:DB$ GainControl | ValidTgts$ Permanent.nonLand+ControlledBy Player.wasDealtCombatDamageThisTurnBy Valid:Creature.Pirate_AtLeast3 | TgtPrompt$ Select target creature controlled by a player who was dealt damage by three or more Pirates this turn | SpellDescription$ Gain control of target nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn.
|
SVar:TrigGainCtrl:DB$ GainControl | ValidTgts$ Permanent.nonLand+ControlledBy Player.wasDealtCombatDamageThisTurnBy Creature.Pirate GE3 | TgtPrompt$ Select target creature controlled by a player who was dealt damage by three or more Pirates this turn | SpellDescription$ Gain control of target nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn.
|
||||||
DeckHints:Type$Pirate
|
DeckHints:Type$Pirate
|
||||||
Oracle:Other Pirates you control get +1/+1.\nAt the beginning of your end step, gain control of target nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn.
|
Oracle:Other Pirates you control get +1/+1.\nAt the beginning of your end step, gain control of target nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Types:Artifact Equipment
|
|||||||
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ Y | Description$ Equipped creature gets +1/+0 for each opponent you have.
|
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ Y | Description$ Equipped creature gets +1/+0 for each opponent you have.
|
||||||
SVar:Y:PlayerCountOpponents$Amount
|
SVar:Y:PlayerCountOpponents$Amount
|
||||||
T:Mode$ DamageDoneOnce | Execute$ TrigDamage | ValidTarget$ Creature.EquippedBy | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature is dealt damage, it deals that much damage to any target.
|
T:Mode$ DamageDoneOnce | Execute$ TrigDamage | ValidTarget$ Creature.EquippedBy | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature is dealt damage, it deals that much damage to any target.
|
||||||
SVar:TrigDamage:DB$ DealDamage | NumDmg$ X | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target
|
SVar:TrigDamage:DB$ DealDamage | NumDmg$ X | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | DamageSource$ TriggeredTargetLKICopy
|
||||||
SVar:X:TriggerCount$DamageAmount
|
SVar:X:TriggerCount$DamageAmount
|
||||||
K:Equip:4
|
K:Equip:4
|
||||||
Oracle:Equipped creature gets +1/+0 for each opponent you have.\nWhenever equipped creature is dealt damage, it deals that much damage to any target.\nEquip {4}
|
Oracle:Equipped creature gets +1/+0 for each opponent you have.\nWhenever equipped creature is dealt damage, it deals that much damage to any target.\nEquip {4}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ K:Entwine:1
|
|||||||
A:SP$ Charm | Cost$ 2 W | Choices$ DBTap,DBEffect | CharmNum$ 1
|
A:SP$ Charm | Cost$ 2 W | Choices$ DBTap,DBEffect | CharmNum$ 1
|
||||||
SVar:DBTap:DB$ Tap | ValidTgts$ Creature | TargetMin$ 2 | TargetMax$ 2 | TgtPrompt$ Select two target creatures | SpellDescription$ Tap two target creatures.
|
SVar:DBTap:DB$ Tap | ValidTgts$ Creature | TargetMin$ 2 | TargetMax$ 2 | TgtPrompt$ Select two target creatures | SpellDescription$ Tap two target creatures.
|
||||||
SVar:DBEffect:DB$ Effect | ValidTgts$ Player | TgtPrompt$ Select target player | IsCurse$ True | StaticAbilities$ DontUntap | Triggers$ RestoreSight | RememberObjects$ Targeted | Duration$ Permanent | SpellDescription$ Creatures don't untap during target player's next untap step.
|
SVar:DBEffect:DB$ Effect | ValidTgts$ Player | TgtPrompt$ Select target player | IsCurse$ True | StaticAbilities$ DontUntap | Triggers$ RestoreSight | RememberObjects$ Targeted | Duration$ Permanent | SpellDescription$ Creatures don't untap during target player's next untap step.
|
||||||
SVar:DontUntap:Mode$ Continuous | ValidPlayer$ Player.IsRemembered | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature | AddHiddenKeyword$ This card doesn't untap.
|
SVar:DontUntap:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.RememberedPlayerCtrl | AddHiddenKeyword$ This card doesn't untap.
|
||||||
SVar:RestoreSight:Mode$ Phase | Phase$ Untap | ValidPlayer$ Player.IsRemembered | TriggerZones$ Command | Execute$ ExileEffect | Static$ True
|
SVar:RestoreSight:Mode$ Phase | Phase$ Untap | ValidPlayer$ Player.IsRemembered | TriggerZones$ Command | Execute$ ExileEffect | Static$ True
|
||||||
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
|
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ ManaCost:R
|
|||||||
Types:Creature Goblin Berserker
|
Types:Creature Goblin Berserker
|
||||||
PT:2/2
|
PT:2/2
|
||||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ CARDNAME can't attack. | CheckSVar$ X | SVarCompare$ LT1 | Description$ CARDNAME can't attack unless an opponent has been dealt damage this turn.
|
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ CARDNAME can't attack. | CheckSVar$ X | SVarCompare$ LT1 | Description$ CARDNAME can't attack unless an opponent has been dealt damage this turn.
|
||||||
SVar:X:Count$TotalOppDamageThisTurn
|
SVar:X:PlayerCountPropertyYou$DamageToOppsThisTurn
|
||||||
Oracle:Bloodcrazed Goblin can't attack unless an opponent has been dealt damage this turn.
|
Oracle:Bloodcrazed Goblin can't attack unless an opponent has been dealt damage this turn.
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ Player.Opponent | TriggerZones
|
|||||||
SVar:GhostCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X
|
SVar:GhostCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X
|
||||||
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ GhostClear | TriggerDescription$ At the beginning of your end step, remove all +1/+1 counters from CARDNAME.
|
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ GhostClear | TriggerDescription$ At the beginning of your end step, remove all +1/+1 counters from CARDNAME.
|
||||||
SVar:GhostClear:DB$ RemoveCounter | CounterType$ P1P1 | CounterNum$ All
|
SVar:GhostClear:DB$ RemoveCounter | CounterType$ P1P1 | CounterNum$ All
|
||||||
SVar:X:Count$YourDamageThisTurn
|
SVar:X:PlayerCountPropertyYou$DamageThisTurn
|
||||||
Oracle:At the beginning of each end step, if it's an opponent's turn, put a +1/+1 counter on Discordant Spirit for each 1 damage dealt to you this turn.\nAt the beginning of your end step, remove all +1/+1 counters from Discordant Spirit.
|
Oracle:At the beginning of each end step, if it's an opponent's turn, put a +1/+1 counter on Discordant Spirit for each 1 damage dealt to you this turn.\nAt the beginning of your end step, remove all +1/+1 counters from Discordant Spirit.
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ A:SP$ ChangeZone | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Fizzle$ Tr
|
|||||||
SVar:DBRoll:DB$ RollDice | Sides$ 20 | Modifier$ Y | ResultSubAbilities$ 1-14:DBMayPlay,Else:DBMayPlayWithoutCost | StackDescription$ SpellDescription | SpellDescription$ Roll a d20 and add that spell's mana value.
|
SVar:DBRoll:DB$ RollDice | Sides$ 20 | Modifier$ Y | ResultSubAbilities$ 1-14:DBMayPlay,Else:DBMayPlayWithoutCost | StackDescription$ SpellDescription | SpellDescription$ Roll a d20 and add that spell's mana value.
|
||||||
SVar:DBMayPlay:DB$ Effect | StaticAbilities$ STPlay | RememberObjects$ Remembered | Duration$ Permanent | ExileOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ 1—14 VERT You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast it.
|
SVar:DBMayPlay:DB$ Effect | StaticAbilities$ STPlay | RememberObjects$ Remembered | Duration$ Permanent | ExileOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ 1—14 VERT You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast it.
|
||||||
SVar:DBMayPlayWithoutCost:DB$ Effect | StaticAbilities$ STPlayWithoutCost | RememberObjects$ Remembered | Duration$ Permanent | ExileOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ 15+ VERT You may cast that card without paying its mana cost for as long as it remains exiled.
|
SVar:DBMayPlayWithoutCost:DB$ Effect | StaticAbilities$ STPlayWithoutCost | RememberObjects$ Remembered | Duration$ Permanent | ExileOnMoved$ Exile | SubAbility$ DBCleanup | SpellDescription$ 15+ VERT You may cast that card without paying its mana cost for as long as it remains exiled.
|
||||||
SVar:STPlay:Mode$ Continuous | MayPlay$ True | MayPlayIgnoreColor$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast it.
|
SVar:STPlay:Mode$ Continuous | MayPlay$ True | MayPlayIgnoreColor$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonLand | AffectedZone$ Exile | Description$ You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast it.
|
||||||
SVar:STPlayWithoutCost:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may cast that card without paying its mana cost for as long as it remains exiled.
|
SVar:STPlayWithoutCost:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonLand | AffectedZone$ Exile | Description$ You may cast that card without paying its mana cost for as long as it remains exiled.
|
||||||
SVar:Y:RememberedLKI$CardManaCost
|
SVar:Y:RememberedLKI$CardManaCost
|
||||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Glen Elendra
|
|||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Plane Lorwyn
|
Types:Plane Lorwyn
|
||||||
T:Mode$ Phase | Phase$ EndCombat | ValidPlayer$ You | TriggerZones$ Command | OptionalDecider$ You | Execute$ TrigExchange | TriggerDescription$ At end of combat, you may exchange control of target creature you control that dealt combat damage to a player this combat and target creature that player controls.
|
T:Mode$ Phase | Phase$ EndCombat | ValidPlayer$ You | TriggerZones$ Command | OptionalDecider$ You | Execute$ TrigExchange | TriggerDescription$ At end of combat, you may exchange control of target creature you control that dealt combat damage to a player this combat and target creature that player controls.
|
||||||
SVar:TrigExchange:DB$ Pump | ValidTgts$ Creature.YouCtrl+dealtCombatDamageThisCombat Player | TgtPrompt$ Select target creature you control that dealt combat damage to a player | SubAbility$ DBExchange
|
SVar:TrigExchange:DB$ Pump | ValidTgts$ Creature.YouCtrl+dealtCombatDamageThisCombat | TgtPrompt$ Select target creature you control that dealt combat damage to a player | SubAbility$ DBExchange
|
||||||
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Creature.ControlledBy Player.wasDealtCombatDamageThisCombatBy ParentTarget | TgtPrompt$ Select target creature that player controls.
|
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Creature.ControlledBy Player.wasDealtCombatDamageThisCombatBy ParentTarget | TgtPrompt$ Select target creature that player controls.
|
||||||
T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, gain control of target creature you own.
|
T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, gain control of target creature you own.
|
||||||
SVar:RolledChaos:DB$ GainControl | ValidTgts$ Creature.YouOwn | TgtPrompt$ Select target creature you own to gain control of
|
SVar:RolledChaos:DB$ GainControl | ValidTgts$ Creature.YouOwn | TgtPrompt$ Select target creature you own to gain control of
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ SVar:GrothamaFight:DB$ Fight | Defined$ TriggeredAttackerLKICopy | ExtraDefined$
|
|||||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigRepeat | TriggerDescription$ When CARDNAME leaves the battlefield, each player draws cards equal to the amount of damage dealt to Grothama this turn by sources they controlled.
|
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigRepeat | TriggerDescription$ When CARDNAME leaves the battlefield, each player draws cards equal to the amount of damage dealt to Grothama this turn by sources they controlled.
|
||||||
SVar:TrigRepeat:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ TrigDraw
|
SVar:TrigRepeat:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ TrigDraw
|
||||||
SVar:TrigDraw:DB$ Draw | Defined$ Remembered | NumCards$ X
|
SVar:TrigDraw:DB$ Draw | Defined$ Remembered | NumCards$ X
|
||||||
SVar:X:TriggeredCard$DamageDoneByPlayerThisTurn.Remembered
|
SVar:X:TriggeredCard$TotalDamageThisTurn Card.RememberedPlayerCtrl
|
||||||
SVar:HasAttackEffect:TRUE
|
SVar:HasAttackEffect:TRUE
|
||||||
Oracle:Other creatures have "Whenever this creature attacks, you may have it fight Grothama, All-Devouring."\nWhen Grothama leaves the battlefield, each player draws cards equal to the amount of damage dealt to Grothama this turn by sources they controlled.
|
Oracle:Other creatures have "Whenever this creature attacks, you may have it fight Grothama, All-Devouring."\nWhen Grothama leaves the battlefield, each player draws cards equal to the amount of damage dealt to Grothama this turn by sources they controlled.
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ ManaCost:1
|
|||||||
Types:Legendary Artifact Creature Thopter
|
Types:Legendary Artifact Creature Thopter
|
||||||
PT:1/1
|
PT:1/1
|
||||||
K:Flying
|
K:Flying
|
||||||
A:AB$ Effect | Cost$ Sac<1/CARDNAME> | ValidTgts$ Player.wasDealtCombatDamageThisTurnBy Self | Name$ Hope of Ghirapur Effect | StaticAbilities$ STCantBeCast | RememberObjects$ Targeted | Duration$ UntilYourNextTurn | SpellDescription$ Until your next turn, target player who was dealt combat damage by Hope of Ghirapur can't cast noncreature spells.
|
A:AB$ Effect | Cost$ Sac<1/CARDNAME> | ValidTgts$ Player.wasDealtCombatDamageThisTurnBySource | Name$ Hope of Ghirapur Effect | StaticAbilities$ STCantBeCast | RememberObjects$ Targeted | Duration$ UntilYourNextTurn | SpellDescription$ Until your next turn, target player who was dealt combat damage by Hope of Ghirapur can't cast noncreature spells.
|
||||||
SVar:STCantBeCast:Mode$ CantBeCast | EffectZone$ Command | ValidCard$ Card.nonCreature | Caster$ Player.IsRemembered | Description$ Until your next turn, target player who was dealt combat damage by Hope of Ghirapur this turn can't cast noncreature spells.
|
SVar:STCantBeCast:Mode$ CantBeCast | EffectZone$ Command | ValidCard$ Card.nonCreature | Caster$ Player.IsRemembered | Description$ Until your next turn, target player who was dealt combat damage by Hope of Ghirapur this turn can't cast noncreature spells.
|
||||||
Oracle:Flying\nSacrifice Hope of Ghirapur: Until your next turn, target player who was dealt combat damage by Hope of Ghirapur this turn can't cast noncreature spells.
|
Oracle:Flying\nSacrifice Hope of Ghirapur: Until your next turn, target player who was dealt combat damage by Hope of Ghirapur this turn can't cast noncreature spells.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
Name:Inferno Trap
|
Name:Inferno Trap
|
||||||
ManaCost:3 R
|
ManaCost:3 R
|
||||||
Types:Instant Trap
|
Types:Instant Trap
|
||||||
SVar:AltCost:Cost$ R | CheckSVar$ CreaturesAttacked | SVarCompare$ GE2 | Description$ If you've been dealt damage by two or more creatures this turn, you may pay {R} rather than pay this spell's mana cost.
|
SVar:AltCost:Cost$ R | CheckSVar$ CreaturesDmg | SVarCompare$ GE2 | Description$ If you've been dealt damage by two or more creatures this turn, you may pay {R} rather than pay this spell's mana cost.
|
||||||
A:SP$ DealDamage | Cost$ 3 R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 4 | SpellDescription$ CARDNAME deals 4 damage to target creature.
|
A:SP$ DealDamage | Cost$ 3 R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 4 | SpellDescription$ CARDNAME deals 4 damage to target creature.
|
||||||
SVar:CreaturesAttacked:Count$YourDamageSourcesThisTurn Creature
|
SVar:CreaturesDmg:Count$NumDamageThisTurn Creature You
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
Oracle:If you've been dealt damage by two or more creatures this turn, you may pay {R} rather than pay this spell's mana cost.\nInferno Trap deals 4 damage to target creature.
|
Oracle:If you've been dealt damage by two or more creatures this turn, you may pay {R} rather than pay this spell's mana cost.\nInferno Trap deals 4 damage to target creature.
|
||||||
|
|||||||
@@ -25,6 +25,6 @@ Colors:red
|
|||||||
Types:Enchantment Creature Human Shaman
|
Types:Enchantment Creature Human Shaman
|
||||||
PT:2/2
|
PT:2/2
|
||||||
K:Haste
|
K:Haste
|
||||||
R:Event$ Moved | ValidLKI$ Creature.DamagedByCard.YouCtrl,Creature.DamagedByEmblem.YouCtrl | Destination$ Graveyard | ReplaceWith$ DBExile | ActiveZones$ Battlefield | Description$ If a creature dealt damage this turn by a source you controlled would die, exile it instead.
|
R:Event$ Moved | ValidLKI$ Creature.DamagedByCard.YouCtrl,Emblem.YouCtrl | Destination$ Graveyard | ReplaceWith$ DBExile | ActiveZones$ Battlefield | Description$ If a creature dealt damage this turn by a source you controlled would die, exile it instead.
|
||||||
SVar:DBExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ Exile
|
SVar:DBExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ Exile
|
||||||
Oracle:Haste\nIf a creature dealt damage this turn by a source you controlled would die, exile it instead.
|
Oracle:Haste\nIf a creature dealt damage this turn by a source you controlled would die, exile it instead.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Types:Enchantment Aura
|
|||||||
K:Flash
|
K:Flash
|
||||||
K:Enchant creature
|
K:Enchant creature
|
||||||
A:SP$ Attach | Cost$ 2 R | ValidTgts$ Creature | AILogic$ Pump
|
A:SP$ Attach | Cost$ 2 R | ValidTgts$ Creature | AILogic$ Pump
|
||||||
R:Event$ Moved | ValidLKI$ Creature.DamagedByEnchanted | Destination$ Graveyard | ActiveZones$ Battlefield | ReplaceWith$ DBExile | Description$ If a creature dealt damage by enchanted creature this turn would die, exile it instead.
|
R:Event$ Moved | ValidLKI$ Creature.DamagedBy Enchanted | Destination$ Graveyard | ActiveZones$ Battlefield | ReplaceWith$ DBExile | Description$ If a creature dealt damage by enchanted creature this turn would die, exile it instead.
|
||||||
SVar:DBExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ Exile
|
SVar:DBExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ Exile
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
SVar:NonStackingAttachEffect:True
|
SVar:NonStackingAttachEffect:True
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:5 W
|
|||||||
Types:Creature Elephant Cleric
|
Types:Creature Elephant Cleric
|
||||||
PT:4/6
|
PT:4/6
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigLife | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may have your life total become the total toughness of creatures you control.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigLife | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may have your life total become the total toughness of creatures you control.
|
||||||
SVar:TrigLife:DB$ SetLife | Defined$ You | LifeAmount$ Y | SubAbility$ DBCleanup
|
SVar:TrigLife:DB$ SetLife | Defined$ You | LifeAmount$ Y
|
||||||
SVar:Y:Count$Valid Creature.YouCtrl$SumToughness
|
SVar:Y:Count$Valid Creature.YouCtrl$SumToughness
|
||||||
A:AB$ Pump | Cost$ 5 W | NumAtt$ X | NumDef$ X | SpellDescription$ CARDNAME gets +X/+X until end of turn, where X is your life total.
|
A:AB$ Pump | Cost$ 5 W | NumAtt$ X | NumDef$ X | SpellDescription$ CARDNAME gets +X/+X until end of turn, where X is your life total.
|
||||||
SVar:X:Count$YourLifeTotal
|
SVar:X:Count$YourLifeTotal
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ R:Event$ DamageDone | ActiveZones$ Command | ValidSource$ Card.OppCtrl,Emblem.Op
|
|||||||
SVar:DBReplace:DB$ ReplaceDamage | Amount$ 1
|
SVar:DBReplace:DB$ ReplaceDamage | Amount$ 1
|
||||||
T:Mode$ Phase | Phase$ End of Turn | CheckSVar$ X | SVarCompare$ GE5 | TriggerZones$ Command | Execute$ Abandon | TriggerDescription$ At the beginning of each end step, if you've been dealt 5 or more damage this turn, abandon this scheme.
|
T:Mode$ Phase | Phase$ End of Turn | CheckSVar$ X | SVarCompare$ GE5 | TriggerZones$ Command | Execute$ Abandon | TriggerDescription$ At the beginning of each end step, if you've been dealt 5 or more damage this turn, abandon this scheme.
|
||||||
SVar:Abandon:AB$ Abandon | Cost$ 0
|
SVar:Abandon:AB$ Abandon | Cost$ 0
|
||||||
SVar:X:Count$YourDamageThisTurn
|
SVar:X:PlayerCountPropertyYou$DamageThisTurn
|
||||||
Oracle:(An ongoing scheme remains face up until it's abandoned.)\nIf a source an opponent controls would deal damage to you, prevent 1 of that damage.\nAt the beginning of each end step, if you've been dealt 5 or more damage this turn, abandon this scheme.
|
Oracle:(An ongoing scheme remains face up until it's abandoned.)\nIf a source an opponent controls would deal damage to you, prevent 1 of that damage.\nAt the beginning of each end step, if you've been dealt 5 or more damage this turn, abandon this scheme.
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ Types:Tribal Sorcery Rogue
|
|||||||
K:Prowl:5 U
|
K:Prowl:5 U
|
||||||
A:SP$ Token | Cost$ 3 U | TokenAmount$ X | TokenScript$ b_1_1_faerie_rogue_flying | TokenOwner$ You | SubAbility$ DBTakeTurn | SpellDescription$ Create X 1/1 black Faerie Rogue creature tokens with flying, where X is the damage dealt to your opponents this turn. If CARDNAME's prowl cost was paid, take an extra turn after this one.
|
A:SP$ Token | Cost$ 3 U | TokenAmount$ X | TokenScript$ b_1_1_faerie_rogue_flying | TokenOwner$ You | SubAbility$ DBTakeTurn | SpellDescription$ Create X 1/1 black Faerie Rogue creature tokens with flying, where X is the damage dealt to your opponents this turn. If CARDNAME's prowl cost was paid, take an extra turn after this one.
|
||||||
SVar:DBTakeTurn:DB$ AddTurn | NumTurns$ 1 | ConditionDefined$ Self | ConditionPresent$ Card.prowled
|
SVar:DBTakeTurn:DB$ AddTurn | NumTurns$ 1 | ConditionDefined$ Self | ConditionPresent$ Card.prowled
|
||||||
SVar:X:Count$TotalOppDamageThisTurn
|
SVar:X:PlayerCountPropertyYou$DamageToOppsThisTurn
|
||||||
DeckNeeds:Type$Rogue
|
DeckNeeds:Type$Rogue
|
||||||
Oracle:Prowl {5}{U} (You may cast this for its prowl cost if you dealt combat damage to a player this turn with a Rogue.)\nCreate X 1/1 black Faerie Rogue creature tokens with flying, where X is the damage dealt to your opponents this turn. If this spell's prowl cost was paid, take an extra turn after this one.
|
Oracle:Prowl {5}{U} (You may cast this for its prowl cost if you dealt combat damage to a player this turn with a Rogue.)\nCreate X 1/1 black Faerie Rogue creature tokens with flying, where X is the damage dealt to your opponents this turn. If this spell's prowl cost was paid, take an extra turn after this one.
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ SVar:RuneswordSac:DB$ SacrificeAll | Defined$ Imprinted | SubAbility$ ExileEffec
|
|||||||
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
|
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
|
||||||
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: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
|
SVar:PumpNogen:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ TriggeredTarget
|
||||||
SVar:RuneswordRep:Event$ Moved | ValidLKI$ Creature.DamagedByRemembered | Destination$ Graveyard | ReplaceWith$ RuneswordExile | Description$ If a creature dealt damage by CARDNAME this turn would die, exile it instead.
|
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
|
SVar:RuneswordExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ Exile
|
||||||
Oracle:{3}, {T}: Target attacking creature gets +2/+0 until end of turn. When that creature leaves the battlefield this turn, sacrifice Runesword. 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.
|
Oracle:{3}, {T}: Target attacking creature gets +2/+0 until end of turn. When that creature leaves the battlefield this turn, sacrifice Runesword. 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.
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ ManaCost:1 B
|
|||||||
Types:Instant
|
Types:Instant
|
||||||
A:SP$ GainLife | Cost$ 1 B | Defined$ You | LifeAmount$ X | SubAbility$ Dmg | SpellDescription$ You gain life equal to the damage dealt to you this turn. CARDNAME deals damage to target creature you control equal to the damage dealt to you this turn.
|
A:SP$ GainLife | Cost$ 1 B | Defined$ You | LifeAmount$ X | SubAbility$ Dmg | SpellDescription$ You gain life equal to the damage dealt to you this turn. CARDNAME deals damage to target creature you control equal to the damage dealt to you this turn.
|
||||||
SVar:Dmg:DB$ DealDamage | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumDmg$ X
|
SVar:Dmg:DB$ DealDamage | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumDmg$ X
|
||||||
SVar:X:Count$YourDamageThisTurn
|
SVar:X:PlayerCountPropertyYou$DamageThisTurn
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
Oracle:You gain life equal to the damage dealt to you this turn. Simulacrum deals damage to target creature you control equal to the damage dealt to you this turn.
|
Oracle:You gain life equal to the damage dealt to you this turn. Simulacrum deals damage to target creature you control equal to the damage dealt to you this turn.
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ PT:3/3
|
|||||||
K:Bloodthirst:3
|
K:Bloodthirst:3
|
||||||
K:Flying
|
K:Flying
|
||||||
A:AB$ ChangeZone | Cost$ R R R | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | CheckSVar$ OppDamaged | SVarCompare$ GE1 | SpellDescription$ Return CARDNAME from your graveyard to your hand. Activate only if an opponent was dealt damage this turn.
|
A:AB$ ChangeZone | Cost$ R R R | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | CheckSVar$ OppDamaged | SVarCompare$ GE1 | SpellDescription$ Return CARDNAME from your graveyard to your hand. Activate only if an opponent was dealt damage this turn.
|
||||||
SVar:OppDamaged:Count$TotalOppDamageThisTurn
|
SVar:OppDamaged:PlayerCountPropertyYou$DamageToOppsThisTurn
|
||||||
Oracle:Bloodthirst 3 (If an opponent was dealt damage this turn, this creature enters the battlefield with three +1/+1 counters on it.)\nFlying\n{R}{R}{R}: Return Skarrgan Firebird from your graveyard to your hand. Activate only if an opponent was dealt damage this turn.
|
Oracle:Bloodthirst 3 (If an opponent was dealt damage this turn, this creature enters the battlefield with three +1/+1 counters on it.)\nFlying\n{R}{R}{R}: Return Skarrgan Firebird from your graveyard to your hand. Activate only if an opponent was dealt damage this turn.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:1 R
|
|||||||
Types:Creature Human Wizard
|
Types:Creature Human Wizard
|
||||||
PT:1/2
|
PT:1/2
|
||||||
K:Haste
|
K:Haste
|
||||||
A:AB$ SetState | Cost$ T | ValidTgts$ Creature.YouCtrl+faceDown | Mode$ TurnFace | SubAbility$ DBDelTrig | SpellDescription$ Turn target face-down creature you control face up. At the beginning of the next end step, sacrifice it.
|
A:AB$ SetState | Cost$ T | ValidTgts$ Creature.YouCtrl+faceDown | Mode$ TurnFace | SubAbility$ DBPump | SpellDescription$ Turn target face-down creature you control face up. At the beginning of the next end step, sacrifice it.
|
||||||
SVar:DBPump:DB$ Pump | Defined$ Targeted | AtEOT$ Sacrifice
|
SVar:DBPump:DB$ Pump | Defined$ Targeted | AtEOT$ Sacrifice
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
Oracle:Haste\n{T}: Turn target face-down creature you control face up. At the beginning of the next end step, sacrifice it.
|
Oracle:Haste\n{T}: Turn target face-down creature you control face up. At the beginning of the next end step, sacrifice it.
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ ManaCost:B
|
|||||||
Types:Instant
|
Types:Instant
|
||||||
A:SP$ Pump | Cost$ B | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +1 | KW$ Deathtouch | RememberObjects$ Targeted | SubAbility$ DBMoonglove | SpellDescription$ Target creature you control gets +1/+0 and gains deathtouch until end of turn. Whenever a creature dealt damage by that creature dies this turn, its controller loses 2 life. (Any amount of damage a creature with deathtouch deals to a creature is enough to destroy it.)
|
A:SP$ Pump | Cost$ B | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +1 | KW$ Deathtouch | RememberObjects$ Targeted | SubAbility$ DBMoonglove | SpellDescription$ Target creature you control gets +1/+0 and gains deathtouch until end of turn. Whenever a creature dealt damage by that creature dies this turn, its controller loses 2 life. (Any amount of damage a creature with deathtouch deals to a creature is enough to destroy it.)
|
||||||
SVar:DBMoonglove:DB$ Effect | Triggers$ MoongloveTrigger | RememberObjects$ Remembered | StackDescription$ Whenever a creature dealt damage by that creature dies this turn, its controller loses 2 life.
|
SVar:DBMoonglove:DB$ Effect | Triggers$ MoongloveTrigger | RememberObjects$ Remembered | StackDescription$ Whenever a creature dealt damage by that creature dies this turn, its controller loses 2 life.
|
||||||
SVar:MoongloveTrigger:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.DamagedByRemembered | TriggerZones$ Command | Execute$ TrigLoseLife | TriggerDescription$ Whenever a creature dealt damage by that creature dies this turn, its controller loses 2 life.
|
SVar:MoongloveTrigger:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.DamagedBy Remembered | TriggerZones$ Command | Execute$ TrigLoseLife | TriggerDescription$ Whenever a creature dealt damage by that creature dies this turn, its controller loses 2 life.
|
||||||
SVar:TrigLoseLife:DB$ LoseLife | LifeAmount$ 2 | Defined$ TriggeredCardController
|
SVar:TrigLoseLife:DB$ LoseLife | LifeAmount$ 2 | Defined$ TriggeredCardController
|
||||||
Oracle:Target creature you control gets +1/+0 and gains deathtouch until end of turn. Whenever a creature dealt damage by that creature dies this turn, its controller loses 2 life. (Any amount of damage a creature with deathtouch deals to a creature is enough to destroy it.)
|
Oracle:Target creature you control gets +1/+0 and gains deathtouch until end of turn. Whenever a creature dealt damage by that creature dies this turn, its controller loses 2 life. (Any amount of damage a creature with deathtouch deals to a creature is enough to destroy it.)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:U B B R
|
|||||||
Types:Legendary Artifact Equipment
|
Types:Legendary Artifact Equipment
|
||||||
K:Equip:2
|
K:Equip:2
|
||||||
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 3 | AddToughness$ 3 | AddKeyword$ First Strike | Description$ Equipped creature gets +3/+3 and has first strike.
|
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 3 | AddToughness$ 3 | AddKeyword$ First Strike | Description$ Equipped creature gets +3/+3 and has first strike.
|
||||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.DamagedByEquipped | Execute$ UnscytheTrigExile | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ Whenever a creature dealt damage by equipped creature this turn dies, you may exile that card. If you do, create a 2/2 black Zombie creature token.
|
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.DamagedBy Equipped | Execute$ UnscytheTrigExile | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ Whenever a creature dealt damage by equipped creature this turn dies, you may exile that card. If you do, create a 2/2 black Zombie creature token.
|
||||||
SVar:UnscytheTrigExile:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | SubAbility$ UnscytheDBToken
|
SVar:UnscytheTrigExile:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | SubAbility$ UnscytheDBToken
|
||||||
SVar:UnscytheDBToken:DB$ Token | TokenOwner$ You | TokenAmount$ 1 | TokenScript$ b_2_2_zombie | ConditionDefined$ Remembered | ConditionPresent$ Card | SubAbility$ UnscytheDBCleanup
|
SVar:UnscytheDBToken:DB$ Token | TokenOwner$ You | TokenAmount$ 1 | TokenScript$ b_2_2_zombie | ConditionDefined$ Remembered | ConditionPresent$ Card | SubAbility$ UnscytheDBCleanup
|
||||||
SVar:UnscytheDBCleanup:DB$ Cleanup | ClearRemembered$ True
|
SVar:UnscytheDBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
|
|||||||
9
forge-gui/res/cardsfolder/upcoming/dragon_cultist.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/dragon_cultist.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Dragon Cultist
|
||||||
|
ManaCost:4 R
|
||||||
|
Types:Legendary Enchantment Background
|
||||||
|
S:Mode$ Continuous | Affected$ Creature.IsCommander+YouOwn | AddTrigger$ TrigDragon | Description$ Commander creatures you own have "At the beginning of your end step, if a source you controlled dealt 5 or more damage this turn, create a 4/4 red Dragon creature token with flying."
|
||||||
|
SVar:TrigDragon:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | CheckDefinedPlayer$ You.damageDoneSingleSource GE5 | Execute$ DBDragon | TriggerDescription$ At the beginning of your end step, if a source you controlled dealt 5 or more damage this turn, create a 4/4 red Dragon creature token with flying.
|
||||||
|
SVar:DBDragon:DB$ Token | TokenScript$ r_4_4_dragon_flying
|
||||||
|
DeckHas:Ability$Token & Type$Dragon
|
||||||
|
AI:RemoveDeck:NonCommander
|
||||||
|
Oracle:Commander creatures you own have "At the beginning of your end step, if a source you controlled dealt 5 or more damage this turn, create a 4/4 red Dragon creature token with flying."
|
||||||
9
forge-gui/res/cardsfolder/upcoming/gnoll_war_band.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/gnoll_war_band.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Gnoll War Band
|
||||||
|
ManaCost:5 R
|
||||||
|
Types:Creature Gnoll
|
||||||
|
PT:5/5
|
||||||
|
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ X | EffectZone$ All | Description$ This spell costs {1} less to cast for each opponent who was dealt damage this turn.
|
||||||
|
SVar:X:PlayerCountOpponents$HasPropertywasDealtDamageThisTurn
|
||||||
|
K:Menace
|
||||||
|
K:Myriad
|
||||||
|
Oracle:This spell costs {1} less to cast for each opponent who was dealt damage this turn.\nMenace\nMyriad
|
||||||
22
forge-gui/res/cardsfolder/upcoming/indulge_excess.txt
Normal file
22
forge-gui/res/cardsfolder/upcoming/indulge_excess.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Name:Indulge
|
||||||
|
ManaCost:2 R
|
||||||
|
Types:Sorcery
|
||||||
|
A:SP$ Effect | CounterType$ P1P1 | CounterNum$ 3 | Triggers$ TriggerAttacks | AddSVar$ AE | SpellDescription$ Whenever a creature you control attacks this turn, create a 1/1 green and white Citizen creature token that's tapped and attacking.
|
||||||
|
SVar:TriggerAttacks:Mode$ Attacks | ValidCard$ Creature.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever a creature you control attacks this turn, create a 1/1 green and white Citizen creature token that's tapped and attacking.
|
||||||
|
SVar:TrigToken:DB$ Token | TokenScript$ gw_1_1_citizen | TokenTapped$ True | TokenAttacking$ True
|
||||||
|
SVar:AE:SVar:HasAttackEffect:TRUE
|
||||||
|
DeckHas:Ability$Token & Type$Citizen
|
||||||
|
AlternateMode:Split
|
||||||
|
Oracle:Whenever a creature you control attacks this turn, create a 1/1 green and white Citizen creature token that's tapped and attacking.
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Excess
|
||||||
|
ManaCost:1 R
|
||||||
|
Types:Sorcery
|
||||||
|
K:Aftermath
|
||||||
|
A:SP$ Token | TokenAmount$ X | TokenScript$ c_a_treasure_sac | SpellDescription$ Create a Treasure token for each creature you controlled that dealt combat damage to a player this turn.
|
||||||
|
SVar:X:Count$NumCombatDamageThisTurn Creature.YouCtrl Player
|
||||||
|
DeckHas:Ability$Token|Sacrifice|Graveyard & Type$Artifact|Treasure
|
||||||
|
SVar:NeedsToPlayVar:X GE3
|
||||||
|
Oracle:Aftermath (Cast this spell only from your graveyard. Then exile it.)\nCreate a Treasure token for each creature you controlled that dealt combat damage to a player this turn.
|
||||||
@@ -4,7 +4,7 @@ Types:Creature Elemental
|
|||||||
PT:1/1
|
PT:1/1
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSac | TriggerDescription$ When CARDNAME enters the battlefield, sacrifice it unless an opponent was dealt damage this turn.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSac | TriggerDescription$ When CARDNAME enters the battlefield, sacrifice it unless an opponent was dealt damage this turn.
|
||||||
SVar:TrigSac:DB$ Sacrifice | Defined$ Self | ConditionCheckSVar$ WarElementalX | ConditionSVarCompare$ EQ0
|
SVar:TrigSac:DB$ Sacrifice | Defined$ Self | ConditionCheckSVar$ WarElementalX | ConditionSVarCompare$ EQ0
|
||||||
SVar:WarElementalX:Count$TotalOppDamageThisTurn
|
SVar:WarElementalX:PlayerCountPropertyYou$DamageToOppsThisTurn
|
||||||
T:Mode$ DamageDoneOnce | ValidSource$ Card | ValidTarget$ Opponent | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever an opponent is dealt damage, put that many +1/+1 counters on CARDNAME.
|
T:Mode$ DamageDoneOnce | ValidSource$ Card | ValidTarget$ Opponent | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever an opponent is dealt damage, put that many +1/+1 counters on CARDNAME.
|
||||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ WarElementalY
|
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ WarElementalY
|
||||||
SVar:WarElementalY:TriggerCount$DamageAmount
|
SVar:WarElementalY:TriggerCount$DamageAmount
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ Name:Wicked Akuba
|
|||||||
ManaCost:B B
|
ManaCost:B B
|
||||||
Types:Creature Spirit
|
Types:Creature Spirit
|
||||||
PT:2/2
|
PT:2/2
|
||||||
A:AB$ LoseLife | Cost$ B | ValidTgts$ Player.wasDealtDamageThisTurnBy Self | TgtPrompt$ Select target player that was dealt damage this turn | LifeAmount$ 1 | SpellDescription$ Target player dealt damage by CARDNAME this turn loses 1 life.
|
A:AB$ LoseLife | Cost$ B | ValidTgts$ Player.wasDealtDamageThisTurnBySource | TgtPrompt$ Select target player that was dealt damage this turn | LifeAmount$ 1 | SpellDescription$ Target player dealt damage by CARDNAME this turn loses 1 life.
|
||||||
Oracle:{B}: Target player dealt damage by Wicked Akuba this turn loses 1 life.
|
Oracle:{B}: Target player dealt damage by Wicked Akuba this turn loses 1 life.
|
||||||
|
|||||||
Reference in New Issue
Block a user