mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
Read ahead Saga Ability (#1413)
This commit is contained in:
@@ -1201,7 +1201,7 @@ public abstract class GameState {
|
|||||||
String[] allCounterStrings = counterString.split(",");
|
String[] allCounterStrings = counterString.split(",");
|
||||||
for (final String counterPair : allCounterStrings) {
|
for (final String counterPair : allCounterStrings) {
|
||||||
String[] pair = counterPair.split("=", 2);
|
String[] pair = counterPair.split("=", 2);
|
||||||
entity.addCounterInternal(CounterType.getType(pair[0]), Integer.parseInt(pair[1]), null, false, null);
|
entity.addCounterInternal(CounterType.getType(pair[0]), Integer.parseInt(pair[1]), null, false, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ public class SpecialCardAi {
|
|||||||
|
|
||||||
Card animated = AnimateAi.becomeAnimated(sa.getHostCard(), sa.getSubAbility());
|
Card animated = AnimateAi.becomeAnimated(sa.getHostCard(), sa.getSubAbility());
|
||||||
if (sa.getHostCard().canReceiveCounters(CounterEnumType.P1P1)) {
|
if (sa.getHostCard().canReceiveCounters(CounterEnumType.P1P1)) {
|
||||||
animated.addCounterInternal(CounterEnumType.P1P1, 2, ai, false, null);
|
animated.addCounterInternal(CounterEnumType.P1P1, 2, ai, false, null, null);
|
||||||
}
|
}
|
||||||
boolean isOppEOT = ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai;
|
boolean isOppEOT = ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai;
|
||||||
boolean isValuableAttacker = ph.is(PhaseType.MAIN1, ai) && ComputerUtilCard.doesSpecifiedCreatureAttackAI(ai, animated);
|
boolean isValuableAttacker = ph.is(PhaseType.MAIN1, ai) && ComputerUtilCard.doesSpecifiedCreatureAttackAI(ai, animated);
|
||||||
|
|||||||
@@ -223,6 +223,8 @@ public class ForgeScript {
|
|||||||
return sa.hasParam("Nightbound");
|
return sa.hasParam("Nightbound");
|
||||||
} else if (property.equals("paidPhyrexianMana")) {
|
} else if (property.equals("paidPhyrexianMana")) {
|
||||||
return sa.getSpendPhyrexianMana();
|
return sa.getSpendPhyrexianMana();
|
||||||
|
} else if (property.equals("LastChapter")) {
|
||||||
|
return sa.isLastChapter();
|
||||||
} else if (property.startsWith("ManaSpent")) {
|
} else if (property.startsWith("ManaSpent")) {
|
||||||
String[] k = property.split(" ", 2);
|
String[] k = property.split(" ", 2);
|
||||||
String comparator = k[1].substring(0, 2);
|
String comparator = k[1].substring(0, 2);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import com.google.common.collect.Iterables;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -330,9 +331,9 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
|||||||
subtractCounter(CounterType.get(counterName), n);
|
subtractCounter(CounterType.get(counterName), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table);
|
abstract public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params);
|
||||||
public void addCounterInternal(final CounterEnumType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table) {
|
public void addCounterInternal(final CounterEnumType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
|
||||||
addCounterInternal(CounterType.get(counterType), n, source, fireEvents, table);
|
addCounterInternal(CounterType.get(counterType), n, source, fireEvents, table, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void receiveDamage(Pair<Integer, Boolean> dmg) {
|
public void receiveDamage(Pair<Integer, Boolean> dmg) {
|
||||||
|
|||||||
@@ -155,11 +155,18 @@ public class GameEntityCounterTable extends ForwardingTable<Optional<Player>, Ga
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add ETB flag
|
||||||
|
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||||
|
runParams.put(AbilityKey.ETB, etb);
|
||||||
|
if (params != null) {
|
||||||
|
runParams.putAll(params);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply counter after replacement effect
|
// Apply counter after replacement effect
|
||||||
for (Map.Entry<Optional<Player>, Map<CounterType, Integer>> e : values.entrySet()) {
|
for (Map.Entry<Optional<Player>, Map<CounterType, Integer>> e : values.entrySet()) {
|
||||||
boolean remember = cause != null && cause.hasParam("RememberPut");
|
boolean remember = cause != null && cause.hasParam("RememberPut");
|
||||||
for (Map.Entry<CounterType, Integer> ec : e.getValue().entrySet()) {
|
for (Map.Entry<CounterType, Integer> ec : e.getValue().entrySet()) {
|
||||||
gm.getKey().addCounterInternal(ec.getKey(), ec.getValue(), e.getKey().orNull(), true, result);
|
gm.getKey().addCounterInternal(ec.getKey(), ec.getValue(), e.getKey().orNull(), true, result, runParams);
|
||||||
if (remember && ec.getValue() >= 1) {
|
if (remember && ec.getValue() >= 1) {
|
||||||
cause.getHostCard().addRemembered(gm.getKey());
|
cause.getHostCard().addRemembered(gm.getKey());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -450,11 +450,12 @@ public class CountersPutEffect extends SpellAbilityEffect {
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
if (sa.hasParam("UpTo")) {
|
if (sa.hasParam("UpTo")) {
|
||||||
|
int min = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("UpToMin", "0"), sa);
|
||||||
Map<String, Object> params = Maps.newHashMap();
|
Map<String, Object> params = Maps.newHashMap();
|
||||||
params.put("Target", obj);
|
params.put("Target", obj);
|
||||||
params.put("CounterType", counterType);
|
params.put("CounterType", counterType);
|
||||||
counterAmount = pc.chooseNumber(sa,
|
counterAmount = pc.chooseNumber(sa,
|
||||||
Localizer.getInstance().getMessage("lblHowManyCounters"), 0, counterAmount, params);
|
Localizer.getInstance().getMessage("lblHowManyCounters"), min, counterAmount, params);
|
||||||
}
|
}
|
||||||
if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) {
|
if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) {
|
||||||
Map<String, Object> params = Maps.newHashMap();
|
Map<String, Object> params = Maps.newHashMap();
|
||||||
@@ -479,6 +480,10 @@ public class CountersPutEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sa.hasParam("ReadAhead")) {
|
||||||
|
gameCard.setReadAhead(counterAmount);
|
||||||
|
}
|
||||||
|
|
||||||
if (sa.hasParam("Tribute")) {
|
if (sa.hasParam("Tribute")) {
|
||||||
// make a copy to check if it would be on the battlefield
|
// make a copy to check if it would be on the battlefield
|
||||||
Card noTributeLKI = CardUtil.getLKICopy(gameCard);
|
Card noTributeLKI = CardUtil.getLKICopy(gameCard);
|
||||||
|
|||||||
@@ -338,6 +338,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
private ReplacementEffect shieldCounterReplaceDestroy = null;
|
private ReplacementEffect shieldCounterReplaceDestroy = null;
|
||||||
private ReplacementEffect stunCounterReplaceUntap = null;
|
private ReplacementEffect stunCounterReplaceUntap = null;
|
||||||
|
|
||||||
|
private Integer readAhead = null;
|
||||||
|
|
||||||
// Enumeration for CMC request types
|
// Enumeration for CMC request types
|
||||||
public enum SplitCMCMode {
|
public enum SplitCMCMode {
|
||||||
CurrentSideCMC,
|
CurrentSideCMC,
|
||||||
@@ -1405,7 +1407,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table) {
|
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
|
||||||
int addAmount = n;
|
int addAmount = n;
|
||||||
if (addAmount <= 0 || !canReceiveCounters(counterType)) {
|
if (addAmount <= 0 || !canReceiveCounters(counterType)) {
|
||||||
// As per rule 107.1b
|
// As per rule 107.1b
|
||||||
@@ -1439,6 +1441,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
|
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
|
||||||
runParams.put(AbilityKey.Source, source);
|
runParams.put(AbilityKey.Source, source);
|
||||||
runParams.put(AbilityKey.CounterType, counterType);
|
runParams.put(AbilityKey.CounterType, counterType);
|
||||||
|
if (params != null) {
|
||||||
|
runParams.putAll(params);
|
||||||
|
}
|
||||||
for (int i = 0; i < addAmount; i++) {
|
for (int i = 0; i < addAmount; i++) {
|
||||||
runParams.put(AbilityKey.CounterAmount, oldValue + i + 1);
|
runParams.put(AbilityKey.CounterAmount, oldValue + i + 1);
|
||||||
getGame().getTriggerHandler().runTrigger(
|
getGame().getTriggerHandler().runTrigger(
|
||||||
@@ -2233,7 +2238,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
|| keyword.startsWith("Embalm") || keyword.startsWith("Level up") || keyword.equals("Prowess")
|
|| keyword.startsWith("Embalm") || keyword.startsWith("Level up") || keyword.equals("Prowess")
|
||||||
|| keyword.startsWith("Eternalize") || keyword.startsWith("Reinforce")
|
|| keyword.startsWith("Eternalize") || keyword.startsWith("Reinforce")
|
||||||
|| keyword.startsWith("Champion") || keyword.startsWith("Prowl") || keyword.startsWith("Adapt")
|
|| keyword.startsWith("Champion") || keyword.startsWith("Prowl") || keyword.startsWith("Adapt")
|
||||||
|| keyword.startsWith("Amplify") || keyword.startsWith("Ninjutsu") || keyword.startsWith("Saga")
|
|| keyword.startsWith("Amplify") || keyword.startsWith("Ninjutsu") || keyword.startsWith("Saga") || keyword.startsWith("Read ahead")
|
||||||
|| keyword.startsWith("Transfigure") || keyword.startsWith("Aura swap")
|
|| keyword.startsWith("Transfigure") || keyword.startsWith("Aura swap")
|
||||||
|| keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling")
|
|| keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling")
|
||||||
|| keyword.startsWith("Encore") || keyword.startsWith("Mutate") || keyword.startsWith("Dungeon")
|
|| keyword.startsWith("Encore") || keyword.startsWith("Mutate") || keyword.startsWith("Dungeon")
|
||||||
@@ -7132,4 +7137,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
}
|
}
|
||||||
return StaticAbilityIgnoreLegendRule.ignoreLegendRule(this);
|
return StaticAbilityIgnoreLegendRule.ignoreLegendRule(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getReadAhead() {
|
||||||
|
return readAhead;
|
||||||
|
}
|
||||||
|
public void setReadAhead(int value) {
|
||||||
|
readAhead = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1697,7 +1697,7 @@ public class CardFactoryUtil {
|
|||||||
parsedTrigger.setOverridingAbility(sa);
|
parsedTrigger.setOverridingAbility(sa);
|
||||||
|
|
||||||
inst.addTrigger(parsedTrigger);
|
inst.addTrigger(parsedTrigger);
|
||||||
} else if (keyword.startsWith("Saga")) {
|
} else if (keyword.startsWith("Saga") || keyword.startsWith("Read ahead")) {
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final List<String> abs = Arrays.asList(k[2].split(","));
|
final List<String> abs = Arrays.asList(k[2].split(","));
|
||||||
if (abs.size() != Integer.valueOf(k[1])) {
|
if (abs.size() != Integer.valueOf(k[1])) {
|
||||||
@@ -1724,9 +1724,10 @@ public class CardFactoryUtil {
|
|||||||
for (int i = idx; i <= skipId; i++) {
|
for (int i = idx; i <= skipId; i++) {
|
||||||
SpellAbility sa = AbilityFactory.getAbility(card, ab);
|
SpellAbility sa = AbilityFactory.getAbility(card, ab);
|
||||||
sa.setChapter(i);
|
sa.setChapter(i);
|
||||||
|
sa.setLastChapter(idx == abs.size());
|
||||||
|
|
||||||
StringBuilder trigStr = new StringBuilder("Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield");
|
StringBuilder trigStr = new StringBuilder("Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield");
|
||||||
trigStr.append("| CounterType$ LORE | CounterAmount$ EQ").append(i);
|
trigStr.append("| Chapter$ True | CounterType$ LORE | CounterAmount$ EQ").append(i);
|
||||||
if (i != idx) {
|
if (i != idx) {
|
||||||
trigStr.append(" | Secondary$ True");
|
trigStr.append(" | Secondary$ True");
|
||||||
}
|
}
|
||||||
@@ -2310,6 +2311,23 @@ public class CardFactoryUtil {
|
|||||||
if ("Sunburst".equals(m)) {
|
if ("Sunburst".equals(m)) {
|
||||||
re.getOverridingAbility().setSVar("Sunburst", "Count$Converge");
|
re.getOverridingAbility().setSVar("Sunburst", "Count$Converge");
|
||||||
}
|
}
|
||||||
|
inst.addReplacement(re);
|
||||||
|
} else if (keyword.startsWith("Read ahead")) {
|
||||||
|
final String[] k = keyword.split(":");
|
||||||
|
String repeffstr = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | Secondary$ True | ReplacementResult$ Updated | Description$ Choose a chapter and start with that many lore counters.";
|
||||||
|
|
||||||
|
String effStr = "DB$ PutCounter | Defined$ Self | CounterType$ LORE | ETB$ True | UpTo$ True | UpToMin$ 1 | ReadAhead$ True | CounterNum$ " + k[1];
|
||||||
|
|
||||||
|
SpellAbility saCounter = AbilityFactory.getAbility(effStr, card);
|
||||||
|
|
||||||
|
if (!intrinsic) {
|
||||||
|
saCounter.setIntrinsic(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, host, intrinsic, card);
|
||||||
|
|
||||||
|
re.setOverridingAbility(saCounter);
|
||||||
|
|
||||||
inst.addReplacement(re);
|
inst.addReplacement(re);
|
||||||
} else if (keyword.equals("Rebound")) {
|
} else if (keyword.equals("Rebound")) {
|
||||||
String repeffstr = "Event$ Moved | ValidLKI$ Card.Self+wasCastFromHand+YouOwn+YouCtrl "
|
String repeffstr = "Event$ Moved | ValidLKI$ Card.Self+wasCastFromHand+YouOwn+YouCtrl "
|
||||||
|
|||||||
@@ -835,7 +835,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table) {
|
@Override
|
||||||
|
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
|
||||||
int addAmount = n;
|
int addAmount = n;
|
||||||
if (addAmount <= 0 || !canReceiveCounters(counterType)) {
|
if (addAmount <= 0 || !canReceiveCounters(counterType)) {
|
||||||
// As per rule 107.1b
|
// As per rule 107.1b
|
||||||
@@ -849,6 +850,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
|
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
|
||||||
runParams.put(AbilityKey.Source, source);
|
runParams.put(AbilityKey.Source, source);
|
||||||
runParams.put(AbilityKey.CounterType, counterType);
|
runParams.put(AbilityKey.CounterType, counterType);
|
||||||
|
if (params != null) {
|
||||||
|
runParams.putAll(params);
|
||||||
|
}
|
||||||
for (int i = 0; i < addAmount; i++) {
|
for (int i = 0; i < addAmount; i++) {
|
||||||
runParams.put(AbilityKey.CounterAmount, oldValue + i + 1);
|
runParams.put(AbilityKey.CounterAmount, oldValue + i + 1);
|
||||||
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAdded, AbilityKey.newMap(runParams), false);
|
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAdded, AbilityKey.newMap(runParams), false);
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
private boolean cumulativeupkeep = false;
|
private boolean cumulativeupkeep = false;
|
||||||
private boolean blessing = false;
|
private boolean blessing = false;
|
||||||
private Integer chapter = null;
|
private Integer chapter = null;
|
||||||
|
private boolean lastChapter = false;
|
||||||
|
|
||||||
/** The pay costs. */
|
/** The pay costs. */
|
||||||
private Cost payCosts;
|
private Cost payCosts;
|
||||||
@@ -1066,6 +1067,13 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
chapter = val;
|
chapter = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLastChapter() {
|
||||||
|
return lastChapter;
|
||||||
|
}
|
||||||
|
public boolean setLastChapter(boolean value) {
|
||||||
|
return lastChapter = value;
|
||||||
|
}
|
||||||
|
|
||||||
public StaticAbility getMayPlay() {
|
public StaticAbility getMayPlay() {
|
||||||
return mayPlay;
|
return mayPlay;
|
||||||
}
|
}
|
||||||
@@ -1129,6 +1137,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
clone.paidAbilities = Lists.newArrayList();
|
clone.paidAbilities = Lists.newArrayList();
|
||||||
clone.setPaidHash(Maps.newHashMap(getPaidHash()));
|
clone.setPaidHash(Maps.newHashMap(getPaidHash()));
|
||||||
|
|
||||||
|
// copy last chapter flag for Trigger
|
||||||
|
clone.lastChapter = this.lastChapter;
|
||||||
|
|
||||||
if (usesTargeting()) {
|
if (usesTargeting()) {
|
||||||
// the targets need to be cloned, otherwise they might be cleared
|
// the targets need to be cloned, otherwise they might be cleared
|
||||||
clone.targetChosen = getTargets().clone();
|
clone.targetChosen = getTargets().clone();
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package forge.game.trigger;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import forge.game.Game;
|
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardZoneTable;
|
import forge.game.card.CardZoneTable;
|
||||||
@@ -54,8 +53,8 @@ public class TriggerAbilityTriggered extends Trigger {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final Card source = spellAbility.getHostCard();
|
final Card source = spellAbility.getHostCard();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
final Iterable<Card> causes = (Iterable<Card>) runParams.get(AbilityKey.Cause);
|
final Iterable<Card> causes = (Iterable<Card>) runParams.get(AbilityKey.Cause);
|
||||||
final Game game = source.getGame();
|
|
||||||
|
|
||||||
if (hasParam("ValidMode")) {
|
if (hasParam("ValidMode")) {
|
||||||
List<String> validModes = Arrays.asList(getParam("ValidMode").split(","));
|
List<String> validModes = Arrays.asList(getParam("ValidMode").split(","));
|
||||||
@@ -73,6 +72,10 @@ public class TriggerAbilityTriggered extends Trigger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!matchesValidParam("ValidSpellAbility", spellAbility)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!matchesValidParam("ValidSource", source)) {
|
if (!matchesValidParam("ValidSource", source)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,19 @@ public class TriggerCounterAdded extends Trigger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO check CR for Read Ahead when they are out
|
||||||
|
// for now assume it only is about etb counter
|
||||||
|
if (hasParam("Chapter") && runParams.containsKey(AbilityKey.ETB) && true == (boolean)runParams.get(AbilityKey.ETB)) {
|
||||||
|
Card card = (Card)runParams.get(AbilityKey.Card);
|
||||||
|
Integer readAhead = card.getReadAhead();
|
||||||
|
if (readAhead != null) {
|
||||||
|
final int actualAmount = (Integer) runParams.get(AbilityKey.CounterAmount);
|
||||||
|
if (actualAmount < readAhead) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -286,19 +286,30 @@ public class WrappedAbility extends Ability {
|
|||||||
return sa.isCycling();
|
return sa.isCycling();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isChapter() {
|
public boolean isChapter() {
|
||||||
return sa.isChapter();
|
return sa.isChapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Integer getChapter() {
|
public Integer getChapter() {
|
||||||
return sa.getChapter();
|
return sa.getChapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setChapter(int val) {
|
public void setChapter(int val) {
|
||||||
sa.setChapter(val);
|
sa.setChapter(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLastChapter() {
|
||||||
|
return sa.isLastChapter();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean setLastChapter(boolean value) {
|
||||||
|
return sa.setLastChapter(value);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFlashBackAbility() {
|
public boolean isFlashBackAbility() {
|
||||||
return sa.isFlashBackAbility();
|
return sa.isFlashBackAbility();
|
||||||
@@ -566,4 +577,5 @@ public class WrappedAbility extends Ability {
|
|||||||
public void setChosenList(List<AbilitySub> choices) {
|
public void setChosenList(List<AbilitySub> choices) {
|
||||||
sa.setChosenList(choices);
|
sa.setChosenList(choices);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -230,7 +230,7 @@ public class GameSimulationTest extends SimulationTest {
|
|||||||
Game game = initAndCreateGame();
|
Game game = initAndCreateGame();
|
||||||
Player p = game.getPlayers().get(1);
|
Player p = game.getPlayers().get(1);
|
||||||
Card sorin = addCard("Sorin, Solemn Visitor", p);
|
Card sorin = addCard("Sorin, Solemn Visitor", p);
|
||||||
sorin.addCounterInternal(CounterEnumType.LOYALTY, 5, p, false, null);
|
sorin.addCounterInternal(CounterEnumType.LOYALTY, 5, p, false, null, null);
|
||||||
|
|
||||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||||
game.getAction().checkStateEffects(true);
|
game.getAction().checkStateEffects(true);
|
||||||
@@ -275,7 +275,7 @@ public class GameSimulationTest extends SimulationTest {
|
|||||||
String bearCardName = "Runeclaw Bear";
|
String bearCardName = "Runeclaw Bear";
|
||||||
addCard(bearCardName, p);
|
addCard(bearCardName, p);
|
||||||
Card gideon = addCard("Gideon, Ally of Zendikar", p);
|
Card gideon = addCard("Gideon, Ally of Zendikar", p);
|
||||||
gideon.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null);
|
gideon.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null, null);
|
||||||
|
|
||||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||||
game.getAction().checkStateEffects(true);
|
game.getAction().checkStateEffects(true);
|
||||||
@@ -404,7 +404,7 @@ public class GameSimulationTest extends SimulationTest {
|
|||||||
Game game = initAndCreateGame();
|
Game game = initAndCreateGame();
|
||||||
Player p = game.getPlayers().get(1);
|
Player p = game.getPlayers().get(1);
|
||||||
Card sarkhan = addCard(sarkhanCardName, p);
|
Card sarkhan = addCard(sarkhanCardName, p);
|
||||||
sarkhan.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null);
|
sarkhan.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null, null);
|
||||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||||
game.getAction().checkStateEffects(true);
|
game.getAction().checkStateEffects(true);
|
||||||
|
|
||||||
@@ -439,7 +439,7 @@ public class GameSimulationTest extends SimulationTest {
|
|||||||
addCard(ornithoperCardName, p);
|
addCard(ornithoperCardName, p);
|
||||||
addCard(bearCardName, p);
|
addCard(bearCardName, p);
|
||||||
Card ajani = addCard(ajaniCardName, p);
|
Card ajani = addCard(ajaniCardName, p);
|
||||||
ajani.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null);
|
ajani.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null, null);
|
||||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||||
game.getAction().checkStateEffects(true);
|
game.getAction().checkStateEffects(true);
|
||||||
|
|
||||||
@@ -472,7 +472,7 @@ public class GameSimulationTest extends SimulationTest {
|
|||||||
SpellAbility boltSA = boltCard.getFirstSpellAbility();
|
SpellAbility boltSA = boltCard.getFirstSpellAbility();
|
||||||
|
|
||||||
Card ajani = addCard(ajaniCardName, p);
|
Card ajani = addCard(ajaniCardName, p);
|
||||||
ajani.addCounterInternal(CounterEnumType.LOYALTY, 8, p, false, null);
|
ajani.addCounterInternal(CounterEnumType.LOYALTY, 8, p, false, null, null);
|
||||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||||
game.getAction().checkStateEffects(true);
|
game.getAction().checkStateEffects(true);
|
||||||
|
|
||||||
@@ -523,7 +523,7 @@ public class GameSimulationTest extends SimulationTest {
|
|||||||
addCard("Swamp", p);
|
addCard("Swamp", p);
|
||||||
addCard("Swamp", p);
|
addCard("Swamp", p);
|
||||||
Card depths = addCard("Dark Depths", p);
|
Card depths = addCard("Dark Depths", p);
|
||||||
depths.addCounterInternal(CounterEnumType.ICE, 10, p, false, null);
|
depths.addCounterInternal(CounterEnumType.ICE, 10, p, false, null, null);
|
||||||
Card thespian = addCard("Thespian's Stage", p);
|
Card thespian = addCard("Thespian's Stage", p);
|
||||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||||
game.getAction().checkStateEffects(true);
|
game.getAction().checkStateEffects(true);
|
||||||
@@ -2256,7 +2256,7 @@ public class GameSimulationTest extends SimulationTest {
|
|||||||
Player p = game.getPlayers().get(0);
|
Player p = game.getPlayers().get(0);
|
||||||
|
|
||||||
Card polukranos = addCard(polukranosCardName, p);
|
Card polukranos = addCard(polukranosCardName, p);
|
||||||
polukranos.addCounterInternal(CounterEnumType.P1P1, 6, p, false, null);
|
polukranos.addCounterInternal(CounterEnumType.P1P1, 6, p, false, null, null);
|
||||||
addCard(hydraCardName, p);
|
addCard(hydraCardName, p);
|
||||||
addCard(leylineCardName, p);
|
addCard(leylineCardName, p);
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
@@ -2301,7 +2301,7 @@ public class GameSimulationTest extends SimulationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Card nishoba = addCard(nishobaName, p1);
|
Card nishoba = addCard(nishobaName, p1);
|
||||||
nishoba.addCounterInternal(CounterEnumType.P1P1, 7, p1, false, null);
|
nishoba.addCounterInternal(CounterEnumType.P1P1, 7, p1, false, null, null);
|
||||||
addCard(capridorName, p1);
|
addCard(capridorName, p1);
|
||||||
Card pridemate = addCard(pridemateName, p1);
|
Card pridemate = addCard(pridemateName, p1);
|
||||||
Card indestructibility = addCard(indestructibilityName, p1);
|
Card indestructibility = addCard(indestructibilityName, p1);
|
||||||
|
|||||||
10
forge-gui/res/cardsfolder/upcoming/historians_boon.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/historians_boon.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Name:Historian's Boon
|
||||||
|
ManaCost:3 W
|
||||||
|
Types:Enchantment
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.nonToken+Other+YouCtrl | Execute$ TrigSmallToken | TriggerDescription$ Whenever CARDNAME or another nontoken enchantment enters the battlefield under your control, create a 1/1 white Soldier creature token.
|
||||||
|
SVar:TrigSmallToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_soldier | TokenOwner$ You
|
||||||
|
T:Mode$ AbilityTriggered | ValidMode$ CounterAdded | ValidSpellAbility$ Triggered.LastChapter | TriggerZones$ Battlefield | Execute$ TrigBigToken | TriggerDescription$ Whenever the final chapter of a Saga you control triggers, create a 4/4 white Angel creature token with flying and vigilance.
|
||||||
|
SVar:TrigBigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_4_4_angel_flying_vigilance | TokenOwner$ You
|
||||||
|
DeckHas:Ability$Token
|
||||||
|
DeckHints:Type$Enchantment|Saga
|
||||||
|
Oracle:Whenever Historian’s Boon or another nontoken enchantment enters the battlefield under your control, create a 1/1 white Soldier creature token.\nWhenever the final chapter of a Saga you control triggers, create a 4/4 white Angel creature token with flying and vigilance.
|
||||||
12
forge-gui/res/cardsfolder/upcoming/the_elder_dragon_war.txt
Normal file
12
forge-gui/res/cardsfolder/upcoming/the_elder_dragon_war.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Name:The Elder Dragon War
|
||||||
|
ManaCost:2 R R
|
||||||
|
Types:Enchantment Saga
|
||||||
|
K:Read ahead:3:DBDealDamage,DBDiscard,DBToken
|
||||||
|
SVar:DBDealDamage:DB$ DamageAll | ValidCards$ Creature | ValidPlayers$ Opponent | NumDmg$ 2 | ValidDescription$ each creature and each opponent. | SpellDescription$ CARDNAME deals 2 damage to each opponent and you gain 2 life.
|
||||||
|
SVar:DBDiscard:DB$ Discard | AnyNumber$ True | Optional$ True | Mode$ TgtChoose | RememberDiscarded$ True | SubAbility$ DBDraw | StackDescription$ {p:You} discards any number of cards, | SpellDescription$ Discard any number of cards,
|
||||||
|
SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ Y | SubAbility$ DBCleanup | StackDescription$ then draws that many cards. | SpellDescription$ then draw that many cards.
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
|
SVar:Y:Count$RememberedSize
|
||||||
|
SVar:DBToken:DB$ Token | TokenScript$ r_4_4_dragon_flying | SpellDescription$ Create a 4/4 red Dragon creature token with flying.
|
||||||
|
DeckHas:Ability$Token
|
||||||
|
Oracle:Read ahead (Choose a chapter and start with that many lore counters. Add one after your draw step. Skipped chapters don’t trigger. Sacrifice after III.)\nI — The Elder Dragon War deals 2 damage to each creature and each opponent.\nII — Discard any number of cards, then draw that many cards.\nIII — Create a 4/4 red Dragon creature token with flying.
|
||||||
@@ -2527,7 +2527,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
|||||||
if (subtract) {
|
if (subtract) {
|
||||||
card.subtractCounter(counter, count);
|
card.subtractCounter(counter, count);
|
||||||
} else {
|
} else {
|
||||||
card.addCounterInternal(counter, count, card.getController(), false, null);
|
card.addCounterInternal(counter, count, card.getController(), false, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user