mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
MagicStack: ThisTurnActivated
This commit is contained in:
@@ -2269,14 +2269,6 @@ public class AbilityUtils {
|
||||
return doXMath(player.getOpponentsGreatestLifeTotal(), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].equals("YouCycledThisTurn")) {
|
||||
return doXMath(player.getCycledThisTurn(), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].equals("YouEquippedThisTurn")) {
|
||||
return doXMath(player.getEquippedThisTurn(), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].equals("YouDrewThisTurn")) {
|
||||
return doXMath(player.getNumDrawnThisTurn(), expr, c, ctb);
|
||||
}
|
||||
@@ -2727,6 +2719,12 @@ public class AbilityUtils {
|
||||
someCards = CardUtil.getLastTurnCast(validFilter, c, ctb, player);
|
||||
}
|
||||
}
|
||||
if (sq[0].startsWith("ThisTurnActivated")) {
|
||||
final String[] workingCopy = paidparts[0].split("_");
|
||||
final String validFilter = workingCopy[1];
|
||||
// use objectXCount ?
|
||||
return CardUtil.getThisTurnActivated(validFilter, c, ctb, player).size();
|
||||
}
|
||||
|
||||
// Count$ThisTurnEntered <ZoneDestination> [from <ZoneOrigin>] <Valid>
|
||||
if (sq[0].startsWith("ThisTurnEntered") || sq[0].startsWith("LastTurnEntered")) {
|
||||
|
||||
@@ -3679,7 +3679,6 @@ public class CardFactoryUtil {
|
||||
sb.append("| SpellDescription$ (").append(inst.getReminderText()).append(")");
|
||||
|
||||
SpellAbility sa = AbilityFactory.getAbility(sb.toString(), card);
|
||||
sa.setAlternativeCost(AlternativeCost.Cycling);
|
||||
sa.setIntrinsic(intrinsic);
|
||||
inst.addSpellAbility(sa);
|
||||
} else if (keyword.startsWith("TypeCycling")) {
|
||||
@@ -3704,7 +3703,6 @@ public class CardFactoryUtil {
|
||||
sb.append(" | SpellDescription$ (").append(inst.getReminderText()).append(")");
|
||||
|
||||
SpellAbility sa = AbilityFactory.getAbility(sb.toString(), card);
|
||||
sa.setAlternativeCost(AlternativeCost.Cycling);
|
||||
sa.setIntrinsic(intrinsic);
|
||||
inst.addSpellAbility(sa);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
@@ -36,6 +37,7 @@ import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityPredicates;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.TextUtil;
|
||||
@@ -138,6 +140,10 @@ public final class CardUtil {
|
||||
return CardLists.getValidCardsAsList(src.getGame().getStack().getSpellsCastLastTurn(), valid, controller, src, ctb);
|
||||
}
|
||||
|
||||
public static List<SpellAbility> getThisTurnActivated(final String valid, final Card src, final CardTraitBase ctb, final Player controller) {
|
||||
return Lists.newArrayList(Iterables.filter(src.getGame().getStack().getAbilityActivatedThisTurn(), SpellAbilityPredicates.isValid(valid.split(","), controller, src, ctb)));
|
||||
}
|
||||
|
||||
public static CardCollection getRadiance(final SpellAbility sa) {
|
||||
SpellAbility targetSA = sa.getSATargetingCard();
|
||||
if (targetSA == null || !targetSA.usesTargeting() || !targetSA.hasParam("Radiance")) {
|
||||
|
||||
@@ -92,8 +92,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
private int landsPlayedLastTurn;
|
||||
private int investigatedThisTurn;
|
||||
private int surveilThisTurn;
|
||||
private int cycledThisTurn;
|
||||
private int equippedThisTurn;
|
||||
private int lifeLostThisTurn;
|
||||
private int lifeLostLastTurn;
|
||||
private int lifeGainedThisTurn;
|
||||
@@ -2482,8 +2480,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
resetLandsPlayedThisTurn();
|
||||
resetInvestigatedThisTurn();
|
||||
resetSurveilThisTurn();
|
||||
resetCycledThisTurn();
|
||||
resetEquippedThisTurn();
|
||||
resetDiscardedThisTurn();
|
||||
resetSacrificedThisTurn();
|
||||
resetVenturedThisTurn();
|
||||
@@ -2969,23 +2965,23 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public boolean allCardsUniqueManaSymbols() {
|
||||
for (final Card c : getCardsIn(ZoneType.Library)) {
|
||||
Set<CardStateName> cardStateNames = c.isSplitCard() ? EnumSet.of(CardStateName.LeftSplit, CardStateName.RightSplit) : EnumSet.of(CardStateName.Original);
|
||||
Set<ManaCostShard> coloredManaSymbols = new HashSet<>();
|
||||
Set<Integer> genericManaSymbols = new HashSet<>();
|
||||
Set<ManaCostShard> coloredManaSymbols = new HashSet<>();
|
||||
Set<Integer> genericManaSymbols = new HashSet<>();
|
||||
|
||||
for (final CardStateName cardStateName : cardStateNames) {
|
||||
final ManaCost manaCost = c.getState(cardStateName).getManaCost();
|
||||
for (final ManaCostShard manaSymbol : manaCost) {
|
||||
if (!coloredManaSymbols.add(manaSymbol)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int generic = manaCost.getGenericCost();
|
||||
if (generic > 0 || manaCost.getCMC() == 0) {
|
||||
if (!genericManaSymbols.add(Integer.valueOf(generic))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (final CardStateName cardStateName : cardStateNames) {
|
||||
final ManaCost manaCost = c.getState(cardStateName).getManaCost();
|
||||
for (final ManaCostShard manaSymbol : manaCost) {
|
||||
if (!coloredManaSymbols.add(manaSymbol)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int generic = manaCost.getGenericCost();
|
||||
if (generic > 0 || manaCost.getCMC() == 0) {
|
||||
if (!genericManaSymbols.add(Integer.valueOf(generic))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -3028,9 +3024,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
legalCompanions.add(c);
|
||||
}
|
||||
} else if (specialRules.equals("UniqueManaSymbols")) {
|
||||
if (this.allCardsUniqueManaSymbols()) {
|
||||
legalCompanions.add(c);
|
||||
}
|
||||
if (this.allCardsUniqueManaSymbols()) {
|
||||
legalCompanions.add(c);
|
||||
}
|
||||
} else if (specialRules.equals("DeckSizePlus20")) {
|
||||
// +20 deck size to min deck size
|
||||
if (deckSize >= minSize + 20) {
|
||||
@@ -3114,7 +3110,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
else if (game.getRules().hasAppliedVariant(GameType.Oathbreaker)) {
|
||||
moved += " | Destination$ Graveyard,Exile,Hand,Library | Description$ If a commander would be exiled or put into hand, graveyard, or library from anywhere, that player may put it into the command zone instead.";
|
||||
} else {
|
||||
// rule 903.9b
|
||||
// rule 903.9b
|
||||
moved += " | Destination$ Hand,Library | Description$ If a commander would be put into its owner's hand or library from anywhere, its owner may put it into the command zone instead.";
|
||||
}
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(moved, eff, true);
|
||||
@@ -3691,33 +3687,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
public void addCycled(SpellAbility sp) {
|
||||
cycledThisTurn++;
|
||||
|
||||
Map<AbilityKey, Object> cycleParams = AbilityKey.mapFromCard(CardCopyService.getLKICopy(game.getCardState(sp.getHostCard())));
|
||||
cycleParams.put(AbilityKey.Cause, sp);
|
||||
cycleParams.put(AbilityKey.Player, this);
|
||||
cycleParams.put(AbilityKey.FirstTime, cycledThisTurn == 1);
|
||||
cycleParams.put(AbilityKey.FirstTime, CardUtil.getThisTurnActivated("Activated.Cycling+YouCtrl", sp.getHostCard(), sp, this).size() == 1);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Cycled, cycleParams, false);
|
||||
}
|
||||
|
||||
public int getCycledThisTurn() {
|
||||
return cycledThisTurn;
|
||||
}
|
||||
|
||||
public void resetCycledThisTurn() {
|
||||
cycledThisTurn = 0;
|
||||
}
|
||||
|
||||
public void addEquipped() { equippedThisTurn++; }
|
||||
|
||||
public int getEquippedThisTurn() {
|
||||
return equippedThisTurn;
|
||||
}
|
||||
|
||||
public void resetEquippedThisTurn() {
|
||||
equippedThisTurn = 0;
|
||||
}
|
||||
|
||||
public boolean hasUrzaLands() {
|
||||
final CardCollectionView landsControlled = getCardsIn(ZoneType.Battlefield);
|
||||
return Iterables.any(landsControlled, Predicates.and(CardPredicates.isType("Urza's"), CardPredicates.isType("Mine")))
|
||||
|
||||
@@ -4,7 +4,6 @@ public enum AlternativeCost {
|
||||
Awaken,
|
||||
Bestow,
|
||||
Blitz,
|
||||
Cycling, // ActivatedAbility
|
||||
Dash,
|
||||
Disturb,
|
||||
Emerge,
|
||||
|
||||
@@ -560,7 +560,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
|
||||
public boolean isCycling() {
|
||||
return isAlternativeCost(AlternativeCost.Cycling);
|
||||
return isKeyword(Keyword.CYCLING) || isKeyword(Keyword.TYPECYCLING);
|
||||
}
|
||||
|
||||
public boolean isBackup() {
|
||||
|
||||
@@ -85,6 +85,8 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
|
||||
private final List<Card> thisTurnCast = Lists.newArrayList();
|
||||
private List<Card> lastTurnCast = Lists.newArrayList();
|
||||
private final List<SpellAbility> abilitiesActivatedThisTurn = Lists.newArrayList();
|
||||
|
||||
private Card curResolvingCard = null;
|
||||
private final Map<String, List<GameCommand>> commandList = Maps.newHashMap();
|
||||
|
||||
@@ -263,7 +265,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
if (sp.isManaAbility()) { // Mana Abilities go straight through
|
||||
if (!sp.isCopied() && !sp.isTrigger()) {
|
||||
// Copied abilities aren't activated, so they shouldn't change these values
|
||||
source.addAbilityActivated(sp);
|
||||
addAbilityActivatedThisTurn(sp, source);
|
||||
}
|
||||
Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(source.getController());
|
||||
runParams.put(AbilityKey.Cost, sp.getPayCosts());
|
||||
@@ -336,7 +338,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
}
|
||||
|
||||
if (sp.isAbility() && !sp.isCopied() && !sp.isTrigger()) {
|
||||
source.addAbilityActivated(sp);
|
||||
addAbilityActivatedThisTurn(sp, source);
|
||||
}
|
||||
|
||||
if (sp instanceof AbilityStatic || (sp.isTrigger() && sp.getTrigger().getOverridingAbility() instanceof AbilityStatic)) {
|
||||
@@ -390,11 +392,6 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
activator.addCycled(sp);
|
||||
}
|
||||
|
||||
// Log number of Equips
|
||||
if (sp.isEquip()) {
|
||||
activator.addEquipped();
|
||||
}
|
||||
|
||||
if (sp.hasParam("Crew")) {
|
||||
// Trigger crews!
|
||||
runParams.put(AbilityKey.Vehicle, sp.getHostCard());
|
||||
@@ -894,6 +891,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
|
||||
public final void onNextTurn() {
|
||||
game.getStackZone().resetCardsAddedThisTurn();
|
||||
this.abilitiesActivatedThisTurn.clear();
|
||||
if (thisTurnCast.isEmpty()) {
|
||||
lastTurnCast = Lists.newArrayList();
|
||||
return;
|
||||
@@ -907,6 +905,15 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
return lastTurnCast;
|
||||
}
|
||||
|
||||
public void addAbilityActivatedThisTurn(SpellAbility sa, final Card source) {
|
||||
source.addAbilityActivated(sa);
|
||||
abilitiesActivatedThisTurn.add(sa.copy(CardCopyService.getLKICopy(source), true));
|
||||
}
|
||||
|
||||
public List<SpellAbility> getAbilityActivatedThisTurn() {
|
||||
return abilitiesActivatedThisTurn;
|
||||
}
|
||||
|
||||
public final void addCastCommand(final String valid, final GameCommand c) {
|
||||
if (commandList.containsKey(valid)) {
|
||||
commandList.get(valid).add(0, c);
|
||||
|
||||
@@ -5,5 +5,5 @@ PT:5/3
|
||||
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AffectedZone$ Battlefield | AddPower$ AffectedX | Description$ Each creature you control gets +2/+0 for each Equipment attached to it.
|
||||
SVar:AffectedX:Count$Valid Equipment.Attached/Times.2
|
||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ You may pay 0 rather than pay equip costs. | CheckSVar$ X | SVarCompare$ LT1 | Description$ You may pay {0} rather than pay the equip cost of the first equip ability you activate each turn.
|
||||
SVar:X:Count$YouEquippedThisTurn
|
||||
SVar:X:Count$ThisTurnActivated_Activated.Equip+YouCtrl
|
||||
Oracle:Each creature you control gets +2/+0 for each Equipment attached to it.\nYou may pay {0} rather than pay the equip cost of the first equip ability you activate each turn.
|
||||
|
||||
@@ -5,7 +5,7 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
|
||||
SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Card.Equipment+YouCtrl
|
||||
S:Mode$ CastWithFlash | ValidSA$ Activated.Equip | Caster$ You | Condition$ PlayerTurn | Description$ As long as it's your turn, you may activate equip abilities any time you could cast an instant.
|
||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ You may pay 0 rather than pay equip costs. | CheckSVar$ X | SVarCompare$ LT1 | Condition$ PlayerTurn | Description$ You may pay {0} rather than pay the equip cost of the first equip ability you activate during each of your turns.
|
||||
SVar:X:Count$YouEquippedThisTurn
|
||||
SVar:X:Count$ThisTurnActivated_Activated.Equip+YouCtrl
|
||||
DeckHas:Ability$Graveyard
|
||||
DeckNeeds:Type$Equipment
|
||||
Oracle:When Forge Anew enters the battlefield, return target Equipment card from your graveyard to the battlefield.\nAs long as it's your turn, you may activate equip abilities any time you could cast an instant.\nYou may pay {0} rather than pay the equip cost of the first equip ability you activate during each of your turns.
|
||||
|
||||
@@ -3,7 +3,7 @@ ManaCost:2 U R W
|
||||
Types:Legendary Creature Human Shaman
|
||||
PT:2/5
|
||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ CyclingForZero | CheckSVar$ X | SVarCompare$ LT1 | Description$ You may pay {0} rather than pay the cycling cost of the first card you cycle each turn.
|
||||
SVar:X:Count$YouCycledThisTurn
|
||||
SVar:X:Count$ThisTurnActivated_Activated.Cycling+YouCtrl
|
||||
T:Mode$ Drawn | ValidCard$ Card.YouCtrl | Number$ 2 | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever you draw your second card each turn, create a 2/2 red and white Dinosaur Cat creature token.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ rw_2_2_dinosaur_cat | TokenOwner$ You
|
||||
DeckHas:Ability$Token
|
||||
|
||||
@@ -7,5 +7,5 @@ T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefi
|
||||
SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Instant.YouOwn+withCycling,Instant.YouOwn+withTypeCycling,Sorcery.YouOwn+withCycling,Sorcery.YouOwn+withTypeCycling | TgtPrompt$ Select target instant or sorcery card with a cycling ability from your graveyard
|
||||
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Graveyard | CheckSVar$ YouCycled | SVarCompare$ GE2 | Execute$ TrigReturn | TriggerDescription$ At the beginning of each end step, if you cycled two or more cards this turn, return CARDNAME from your graveyard to your hand.
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ Self | Origin$ Graveyard | Destination$ Hand
|
||||
SVar:YouCycled:Count$YouCycledThisTurn
|
||||
SVar:YouCycled:Count$ThisTurnActivated_Activated.Cycling+YouCtrl
|
||||
Oracle:Flying\nWhen Spellpyre Phoenix enters the battlefield, you may return target instant or sorcery card with a cycling ability from your graveyard to your hand.\nAt the beginning of each end step, if you cycled two or more cards this turn, return Spellpyre Phoenix from your graveyard to your hand.
|
||||
|
||||
Reference in New Issue
Block a user