MagicStack: ThisTurnActivated

This commit is contained in:
Hans Mackowiak
2024-04-13 19:11:08 +02:00
parent abba1c7230
commit d6422688b8
11 changed files with 53 additions and 69 deletions

View File

@@ -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")) {

View File

@@ -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);
}

View File

@@ -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")) {

View File

@@ -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();
@@ -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")))

View File

@@ -4,7 +4,6 @@ public enum AlternativeCost {
Awaken,
Bestow,
Blitz,
Cycling, // ActivatedAbility
Dash,
Disturb,
Emerge,

View File

@@ -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() {

View File

@@ -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);

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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.