Card property targeted player

This commit is contained in:
Hans Mackowiak
2021-05-15 15:27:15 +00:00
committed by Michael Kamensky
parent cad42948cd
commit ff7f81c307
27 changed files with 1959 additions and 2109 deletions

View File

@@ -47,6 +47,7 @@ import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.GameEntity;
import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.SpellApiBased;
@@ -79,6 +80,7 @@ import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.replacement.ReplaceMoved;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementLayer;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.LandAbility;
@@ -509,20 +511,35 @@ public class AiController {
//try to skip lands that enter the battlefield tapped
if (!nonLandsInHand.isEmpty()) {
CardCollection nonTappeddLands = new CardCollection();
CardCollection nonTappedLands = new CardCollection();
for (Card land : landList) {
// Is this the best way to check if a land ETB Tapped?
if (land.hasSVar("ETBTappedSVar")) {
// check replacement effects if land would enter tapped or not
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(land);
repParams.put(AbilityKey.Origin, land.getZone().getZoneType());
repParams.put(AbilityKey.Destination, ZoneType.Battlefield);
repParams.put(AbilityKey.Source, land);
boolean foundTapped = false;
for (ReplacementEffect re : player.getGame().getReplacementHandler().getReplacementList(ReplacementType.Moved, repParams, ReplacementLayer.Other)) {
SpellAbility reSA = re.ensureAbility();
if (reSA == null || !ApiType.Tap.equals(reSA.getApi())) {
continue;
}
// Glacial Fortress and friends
if (land.hasSVar("ETBCheckSVar") && CardFactoryUtil.xCount(land, land.getSVar("ETBCheckSVar")) == 0) {
reSA.setActivatingPlayer(reSA.getHostCard().getController());
if (reSA.metConditions()) {
foundTapped = true;
break;
}
}
if (foundTapped) {
continue;
}
nonTappeddLands.add(land);
nonTappedLands.add(land);
}
if (!nonTappeddLands.isEmpty()) {
landList = nonTappeddLands;
if (!nonTappedLands.isEmpty()) {
landList = nonTappedLands;
}
}
@@ -1779,7 +1796,7 @@ public class AiController {
compareTo = Integer.parseInt(strCmpTo);
} catch (final Exception ignored) {
if (sa == null) {
compareTo = CardFactoryUtil.xCount(hostCard, hostCard.getSVar(strCmpTo));
compareTo = AbilityUtils.calculateAmount(hostCard, hostCard.getSVar(strCmpTo), effect);
} else {
compareTo = AbilityUtils.calculateAmount(hostCard, hostCard.getSVar(strCmpTo), sa);
}
@@ -1789,7 +1806,7 @@ public class AiController {
int left = 0;
if (sa == null) {
left = CardFactoryUtil.xCount(hostCard, hostCard.getSVar(svarToCheck));
left = AbilityUtils.calculateAmount(hostCard, svarToCheck, effect);
} else {
left = AbilityUtils.calculateAmount(hostCard, svarToCheck, sa);
}

View File

@@ -1125,7 +1125,7 @@ public class ComputerUtil {
creatures2.add(creatures.get(i));
}
}
if (((creatures2.size() + CardUtil.getThisTurnCast("Creature.YouCtrl", vengevines.get(0)).size()) > 1)
if (((creatures2.size() + CardUtil.getThisTurnCast("Creature.YouCtrl", vengevines.get(0), null).size()) > 1)
&& card.isCreature() && card.getManaCost().getCMC() <= 3) {
return true;
}

View File

@@ -982,7 +982,7 @@ public class ComputerUtilCard {
for(byte c : MagicColor.WUBRG) {
String devotionCode = "Count$Devotion." + MagicColor.toLongString(c);
int devotion = CardFactoryUtil.xCount(sa.getHostCard(), devotionCode);
int devotion = AbilityUtils.calculateAmount(sa.getHostCard(), devotionCode, sa);
if (devotion > curDevotion && !CardLists.filter(hand, CardPredicates.isColor(c)).isEmpty()) {
curDevotion = devotion;
chosenColor = MagicColor.toLongString(c);
@@ -1679,37 +1679,27 @@ public class ComputerUtilCard {
// remove old boost that might be copied
for (final StaticAbility stAb : c.getStaticAbilities()) {
vCard.removePTBoost(c.getTimestamp(), stAb.getId());
final Map<String, String> params = stAb.getMapParams();
if (!params.get("Mode").equals("Continuous")) {
if (!stAb.getParam("Mode").equals("Continuous")) {
continue;
}
if (!params.containsKey("Affected")) {
if (!stAb.hasParam("Affected")) {
continue;
}
if (!params.containsKey("AddPower") && !params.containsKey("AddToughness")) {
if (!stAb.hasParam("AddPower") && !stAb.hasParam("AddToughness")) {
continue;
}
final String valid = params.get("Affected");
if (!vCard.isValid(valid, c.getController(), c, null)) {
if (!vCard.isValid(stAb.getParam("Affected").split(","), c.getController(), c, stAb)) {
continue;
}
int att = 0;
if (params.containsKey("AddPower")) {
String addP = params.get("AddPower");
if (addP.equals("AffectedX")) {
att = CardFactoryUtil.xCount(vCard, AbilityUtils.getSVar(stAb, addP));
} else {
att = AbilityUtils.calculateAmount(c, addP, stAb);
}
if (stAb.hasParam("AddPower")) {
String addP = stAb.getParam("AddPower");
att = AbilityUtils.calculateAmount(addP.startsWith("Affected") ? vCard : c, addP, stAb, true);
}
int def = 0;
if (params.containsKey("AddToughness")) {
String addT = params.get("AddToughness");
if (addT.equals("AffectedY")) {
def = CardFactoryUtil.xCount(vCard, AbilityUtils.getSVar(stAb, addT));
} else {
def = AbilityUtils.calculateAmount(c, addT, stAb);
}
if (stAb.hasParam("AddToughness")) {
String addT = stAb.getParam("AddToughness");
def = AbilityUtils.calculateAmount(addT.startsWith("Affected") ? vCard : c, addT, stAb, true);
}
vCard.addPTBoost(att, def, c.getTimestamp(), stAb.getId());
}

View File

@@ -33,7 +33,6 @@ import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
@@ -938,25 +937,18 @@ public class ComputerUtilCombat {
final CardCollectionView cardList = CardCollection.combine(game.getCardsIn(ZoneType.Battlefield), game.getCardsIn(ZoneType.Command));
for (final Card card : cardList) {
for (final StaticAbility stAb : card.getStaticAbilities()) {
final Map<String, String> params = stAb.getMapParams();
if (!params.get("Mode").equals("Continuous")) {
if (!stAb.getParam("Mode").equals("Continuous")) {
continue;
}
if (!params.containsKey("Affected") || !params.get("Affected").contains("blocking")) {
if (!stAb.hasParam("Affected") || !stAb.getParam("Affected").contains("blocking")) {
continue;
}
final String valid = TextUtil.fastReplace(params.get("Affected"), "blocking", "Creature");
if (!blocker.isValid(valid, card.getController(), card, null)) {
final String valid = TextUtil.fastReplace(stAb.getParam("Affected"), "blocking", "Creature");
if (!blocker.isValid(valid, card.getController(), card, stAb)) {
continue;
}
if (params.containsKey("AddPower")) {
if (params.get("AddPower").equals("X")) {
power += CardFactoryUtil.xCount(card, card.getSVar("X"));
} else if (params.get("AddPower").equals("Y")) {
power += CardFactoryUtil.xCount(card, card.getSVar("Y"));
} else {
power += Integer.valueOf(params.get("AddPower"));
}
if (stAb.hasParam("AddPower")) {
power += AbilityUtils.calculateAmount(card, stAb.getParam("AddPower"), stAb);
}
}
}
@@ -1247,25 +1239,18 @@ public class ComputerUtilCombat {
final CardCollectionView cardList = CardCollection.combine(game.getCardsIn(ZoneType.Battlefield), game.getCardsIn(ZoneType.Command));
for (final Card card : cardList) {
for (final StaticAbility stAb : card.getStaticAbilities()) {
final Map<String, String> params = stAb.getMapParams();
if (!params.get("Mode").equals("Continuous")) {
if (!stAb.getParam("Mode").equals("Continuous")) {
continue;
}
if (!params.containsKey("Affected") || !params.get("Affected").contains("attacking")) {
if (!stAb.hasParam("Affected") || !stAb.getParam("Affected").contains("attacking")) {
continue;
}
final String valid = TextUtil.fastReplace(params.get("Affected"), "attacking", "Creature");
if (!attacker.isValid(valid, card.getController(), card, null)) {
final String valid = TextUtil.fastReplace(stAb.getParam("Affected"), "attacking", "Creature");
if (!attacker.isValid(valid, card.getController(), card, stAb)) {
continue;
}
if (params.containsKey("AddPower")) {
if (params.get("AddPower").equals("X")) {
power += CardFactoryUtil.xCount(card, card.getSVar("X"));
} else if (params.get("AddPower").equals("Y")) {
power += CardFactoryUtil.xCount(card, card.getSVar("Y"));
} else {
power += Integer.valueOf(params.get("AddPower"));
}
if (stAb.hasParam("AddPower")) {
power += AbilityUtils.calculateAmount(card, stAb.getParam("AddPower"), stAb);
}
}
}
@@ -1339,7 +1324,7 @@ public class ComputerUtilCombat {
} else if (bonus.contains("TriggeredAttacker$CardToughness")) {
bonus = TextUtil.fastReplace(bonus, "TriggeredAttacker$CardToughness", TextUtil.concatNoSpace("Number$", String.valueOf(attacker.getNetToughness())));
}
power += CardFactoryUtil.xCount(source, bonus);
power += AbilityUtils.calculateAmount(source, bonus, sa);
}
}
@@ -1529,7 +1514,7 @@ public class ComputerUtilCombat {
} else if (bonus.contains("TriggeredPlayersDefenders$Amount")) { // for Melee
bonus = TextUtil.fastReplace(bonus, "TriggeredPlayersDefenders$Amount", "Number$1");
}
toughness += CardFactoryUtil.xCount(source, bonus);
toughness += AbilityUtils.calculateAmount(source, bonus, sa);
}
} else if (ApiType.PumpAll.equals(sa.getApi())) {
@@ -1562,7 +1547,7 @@ public class ComputerUtilCombat {
} else if (bonus.contains("TriggeredPlayersDefenders$Amount")) { // for Melee
bonus = TextUtil.fastReplace(bonus, "TriggeredPlayersDefenders$Amount", "Number$1");
}
toughness += CardFactoryUtil.xCount(source, bonus);
toughness += AbilityUtils.calculateAmount(source, bonus, sa);
}
}
}

View File

@@ -157,7 +157,7 @@ public class ComputerUtilCost {
if (typeList.size() > ai.getMaxHandSize()) {
continue;
}
int num = AbilityUtils.calculateAmount(source, disc.getAmount(), null);
int num = AbilityUtils.calculateAmount(source, disc.getAmount(), sa);
for (int i = 0; i < num; i++) {
Card pref = ComputerUtil.getCardPreference(ai, source, "DiscardCost", typeList);

View File

@@ -39,7 +39,6 @@ import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
@@ -1085,7 +1084,7 @@ public class SpecialCardAi {
return false;
}
String prominentColor = ComputerUtilCard.getMostProminentColor(ai.getCardsIn(ZoneType.Battlefield));
int devotion = CardFactoryUtil.xCount(sa.getHostCard(), "Count$Devotion." + prominentColor);
int devotion = AbilityUtils.calculateAmount(sa.getHostCard(), "Count$Devotion." + prominentColor, sa);
int activationCost = sa.getPayCosts().getTotalMana().getCMC() + (sa.getPayCosts().hasTapCost() ? 1 : 0);
// do not use this SA if devotion to most prominent color is less than its own activation cost + 1 (to actually get advantage)

View File

@@ -766,7 +766,7 @@ public class AttachAi extends SpellAbilityAi {
int powerBuff = 0;
for (StaticAbility stAb : sa.getHostCard().getStaticAbilities()) {
if ("Card.EquippedBy".equals(stAb.getParam("Affected")) && stAb.hasParam("AddPower")) {
powerBuff = AbilityUtils.calculateAmount(sa.getHostCard(), stAb.getParam("AddPower"), null);
powerBuff = AbilityUtils.calculateAmount(sa.getHostCard(), stAb.getParam("AddPower"), stAb);
}
}
if (combat != null && combat.isAttacking(equipped) && ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS, sa.getActivatingPlayer())) {

View File

@@ -30,7 +30,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
@@ -132,7 +131,7 @@ public class DamageDealAi extends DamageAiBase {
// Set PayX here to maximum value. It will be adjusted later depending on the target.
sa.setXManaCostPaid(dmg);
} else if (sa.getSVar(damage).contains("InYourHand") && source.isInZone(ZoneType.Hand)) {
dmg = CardFactoryUtil.xCount(source, sa.getSVar(damage)) - 1; // the card will be spent casting the spell, so actual damage is 1 less
dmg = AbilityUtils.calculateAmount(source, damage, sa) - 1; // the card will be spent casting the spell, so actual damage is 1 less
} else if (sa.getSVar(damage).equals("TargetedPlayer$CardsInHand")) {
// cards that deal damage by the number of cards in target player's hand, e.g. Sudden Impact
if (sa.getTargetRestrictions().canTgtPlayer()) {

View File

@@ -441,7 +441,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
}
if (params.containsKey("WerewolfTransformCondition")) {
if (!CardUtil.getLastTurnCast("Card", this.getHostCard()).isEmpty()) {
if (!CardUtil.getLastTurnCast("Card", this.getHostCard(), this).isEmpty()) {
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,6 @@ import forge.game.GameObject;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardZoneTable;
import forge.game.combat.Combat;
import forge.game.player.Player;
@@ -123,7 +122,7 @@ public abstract class SpellAbilityEffect {
if (sa.hasParam("Announce")) {
String svar = sa.getParam("Announce");
int amount = CardFactoryUtil.xCount(sa.getHostCard(), sa.getSVar(svar));
int amount = AbilityUtils.calculateAmount(sa.getHostCard(), svar, sa);
sb.append(" ");
sb.append(TextUtil.enclosedParen(TextUtil.concatNoSpace(svar,"=",String.valueOf(amount))));
} else{

View File

@@ -5,11 +5,11 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -127,7 +127,7 @@ public class ChooseSourceEffect extends SpellAbilityEffect {
}
final String numericAmount = sa.getParamOrDefault("Amount", "1");
final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) : CardFactoryUtil.xCount(host, host.getSVar(numericAmount));
final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) : AbilityUtils.calculateAmount(host, numericAmount, sa);
for (final Player p : tgtPlayers) {
final CardCollection chosen = new CardCollection();

View File

@@ -8,7 +8,6 @@ import forge.game.GameObject;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardDamageMap;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -90,7 +89,7 @@ public class DamageEachEffect extends DamageBaseEffect {
final Card sourceLKI = game.getChangeZoneLKIInfo(source);
// TODO shouldn't that be using Num or something first?
final int dmg = CardFactoryUtil.xCount(source, sa.getSVar("X"));
final int dmg = AbilityUtils.calculateAmount(source, "X", sa);
// System.out.println(source+" deals "+dmg+" damage to "+o.toString());
if (o instanceof Card) {
@@ -113,14 +112,14 @@ public class DamageEachEffect extends DamageBaseEffect {
for (final Card source : sources) {
final Card sourceLKI = game.getChangeZoneLKIInfo(source);
final int dmg = CardFactoryUtil.xCount(source, card.getSVar("X"));
final int dmg = AbilityUtils.calculateAmount(source, "X", sa);
// System.out.println(source+" deals "+dmg+" damage to "+source);
source.addDamage(dmg, sourceLKI, damageMap, preventMap, counterTable, sa);
}
}
if (sa.getParam("DefinedCards").equals("Remembered")) {
for (final Card source : sources) {
final int dmg = CardFactoryUtil.xCount(source, card.getSVar("X"));
final int dmg = AbilityUtils.calculateAmount(source, "X", sa);
final Card sourceLKI = source.getGame().getChangeZoneLKIInfo(source);
for (final Object o : sa.getHostCard().getRemembered()) {

View File

@@ -4,7 +4,6 @@ import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardFactoryUtil;
import forge.game.spellability.SpellAbility;
import forge.util.TextUtil;
@@ -50,12 +49,12 @@ public class StoreSVarEffect extends SpellAbilityEffect {
int exprMath = AbilityUtils.calculateAmount(source, exprMathVar, sa);
expr = TextUtil.fastReplace(expr, exprMathVar, Integer.toString(exprMath));
}
value = CardFactoryUtil.xCount(source, "SVar$" + expr);
value = AbilityUtils.xCount(source, "SVar$" + expr, sa);
} else if (type.equals("Targeted")) {
value = CardFactoryUtil.handlePaid(sa.findTargetedCards(), expr, source);
value = AbilityUtils.handlePaid(sa.findTargetedCards(), expr, source, sa);
} else if (type.equals("Triggered")) {
Card trigCard = (Card)sa.getTriggeringObject(AbilityKey.Card);
value = CardFactoryUtil.xCount(trigCard, expr);
value = AbilityUtils.xCount(trigCard, expr, sa);
} else if (type.equals("Calculate")) {
value = AbilityUtils.calculateAmount(source, expr, sa);
}

File diff suppressed because it is too large Load Diff

View File

@@ -219,44 +219,12 @@ public class CardProperty {
return false;
}
} else if (property.equals("TargetedPlayerCtrl")) {
boolean foundTargetingSA = false;
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
final SpellAbility saTargeting = sa.getSATargetingPlayer();
if (saTargeting != null) {
foundTargetingSA = true;
for (final Player p : saTargeting.getTargets().getTargetPlayers()) {
if (!controller.equals(p)) {
if (!AbilityUtils.getDefinedPlayers(source, "TargetedPlayer", spellAbility).contains(controller)) {
return false;
}
}
}
}
if (!foundTargetingSA) {
// FIXME: Something went wrong with detecting the SA that has a target, this can happen
// e.g. when activating a SA on a card from another player's hand (e.g. opponent's Chandra's Fury
// activated via Sen Triplets). Needs further investigation as to why this is happening, it might
// cause issues elsewhere too.
System.err.println("Warning: could not deduce a player target for TargetedPlayerCtrl for " + source + ", trying to locate it via CastSA...");
SpellAbility castSA = source.getCastSA();
while (castSA != null) {
if (!Iterables.isEmpty(castSA.getTargets().getTargetPlayers())) {
foundTargetingSA = true;
for (final Player p : castSA.getTargets().getTargetPlayers()) {
if (!controller.equals(p)) {
return false;
}
}
}
castSA = castSA.getSubAbility();
}
if (!foundTargetingSA) {
System.err.println("Warning: checking targets in CastSA did not yield any results as well, TargetedPlayerCtrl check failed.");
}
}
} else if (property.equals("TargetedControllerCtrl")) {
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
final CardCollectionView cards = AbilityUtils.getDefinedCards(source, "Targeted", sa);
final List<SpellAbility> sas = AbilityUtils.getDefinedSpellAbilities(source, "Targeted", sa);
final CardCollectionView cards = AbilityUtils.getDefinedCards(source, "Targeted", spellAbility);
final List<SpellAbility> sas = AbilityUtils.getDefinedSpellAbilities(source, "Targeted", spellAbility);
for (final Card c : cards) {
final Player p = c.getController();
if (!controller.equals(p)) {
@@ -269,7 +237,6 @@ public class CardProperty {
return false;
}
}
}
} else if (property.startsWith("ActivePlayerCtrl")) {
if (!game.getPhaseHandler().isPlayerTurn(controller)) {
return false;
@@ -291,37 +258,9 @@ public class CardProperty {
return false;
}
} else if (property.equals("TargetedPlayerOwn")) {
boolean foundTargetingSA = false;
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
final SpellAbility saTargeting = sa.getSATargetingPlayer();
if (saTargeting != null) {
foundTargetingSA = true;
for (final Player p : saTargeting.getTargets().getTargetPlayers()) {
if (!card.getOwner().equals(p)) {
if (!AbilityUtils.getDefinedPlayers(source, "TargetedPlayer", spellAbility).contains(card.getOwner())) {
return false;
}
}
}
}
if (!foundTargetingSA) {
// FIXME: Something went wrong with detecting the SA that has a target, needs investigation
System.err.println("Warning: could not deduce a player target for TargetedPlayerOwn for " + source + ", trying to locate it via CastSA...");
SpellAbility castSA = source.getCastSA();
while (castSA != null) {
if (!Iterables.isEmpty(castSA.getTargets().getTargetPlayers())) {
foundTargetingSA = true;
for (final Player p : castSA.getTargets().getTargetPlayers()) {
if (!card.getOwner().equals(p)) {
return false;
}
}
}
castSA = castSA.getSubAbility();
}
if (!foundTargetingSA) {
System.err.println("Warning: checking targets in CastSA did not yield any results as well, TargetedPlayerOwn check failed.");
}
}
} else if (property.startsWith("OwnedBy")) {
final String valid = property.substring(8);
if (!card.getOwner().isValid(valid, sourceController, source, spellAbility)) {
@@ -475,16 +414,11 @@ public class CardProperty {
}
break;
case "Targeted":
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
final SpellAbility saTargeting = sa.getSATargetingCard();
if (saTargeting != null) {
for (final Card c : saTargeting.getTargets().getTargetCards()) {
for (final Card c : AbilityUtils.getDefinedCards(source, "Targeted", spellAbility)) {
if (!card.isEnchantedBy(c) && !card.equals(c.getEntityAttachedTo())) {
return false;
}
}
}
}
break;
default: // EnchantedBy Aura.Other
for (final Card aura : card.getEnchantedBy()) {
@@ -497,16 +431,11 @@ public class CardProperty {
}
} else if (property.startsWith("NotEnchantedBy")) {
if (property.substring(14).equals("Targeted")) {
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
final SpellAbility saTargeting = sa.getSATargetingCard();
if (saTargeting != null) {
for (final Card c : saTargeting.getTargets().getTargetCards()) {
for (final Card c : AbilityUtils.getDefinedCards(source, "Targeted", spellAbility)) {
if (card.isEnchantedBy(c)) {
return false;
}
}
}
}
} else {
if (card.isEnchantedBy(source)) {
return false;
@@ -528,16 +457,11 @@ public class CardProperty {
}
} else if (property.startsWith("CanBeEnchantedBy")) {
if (property.substring(16).equals("Targeted")) {
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
final SpellAbility saTargeting = sa.getSATargetingCard();
if (saTargeting != null) {
for (final Card c : saTargeting.getTargets().getTargetCards()) {
for (final Card c : AbilityUtils.getDefinedCards(source, "Targeted", spellAbility)) {
if (!card.canBeAttached(c)) {
return false;
}
}
}
}
} else if (property.substring(16).equals("AllRemembered")) {
for (final Object rem : source.getRemembered()) {
if (rem instanceof Card) {
@@ -554,16 +478,11 @@ public class CardProperty {
}
} else if (property.startsWith("EquippedBy")) {
if (property.substring(10).equals("Targeted")) {
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
final SpellAbility saTargeting = sa.getSATargetingCard();
if (saTargeting != null) {
for (final Card c : saTargeting.getTargets().getTargetCards()) {
for (final Card c : AbilityUtils.getDefinedCards(source, "Targeted", spellAbility)) {
if (!card.hasCardAttachment(c)) {
return false;
}
}
}
}
} else if (property.substring(10).equals("Enchanted")) {
if (source.getEnchantingCard() == null ||
!card.hasCardAttachment(source.getEnchantingCard())) {
@@ -697,18 +616,6 @@ public class CardProperty {
if (!card.getDealtDamageToThisTurn().containsKey(source)) {
return false;
}
} else if (property.startsWith("IsTargetingSource")) {
for (final SpellAbility sa : card.getCurrentState().getNonManaAbilities()) {
final SpellAbility saTargeting = sa.getSATargetingCard();
if (saTargeting != null) {
for (final Card c : saTargeting.getTargets().getTargetCards()) {
if (c.equals(source)) {
return true;
}
}
}
}
return false;
} else if (property.startsWith("SharesCMCWith")) {
if (property.equals("SharesCMCWith")) {
if (!card.sharesCMCWith(source)) {
@@ -916,10 +823,10 @@ public class CardProperty {
} else if (restriction.equals(ZoneType.Battlefield.toString())) {
return Iterables.any(game.getCardsIn(ZoneType.Battlefield), CardPredicates.sharesNameWith(card));
} else if (restriction.equals("ThisTurnCast")) {
return Iterables.any(CardUtil.getThisTurnCast("Card", source), CardPredicates.sharesNameWith(card));
return Iterables.any(CardUtil.getThisTurnCast("Card", source, spellAbility), CardPredicates.sharesNameWith(card));
} else if (restriction.equals("MovedToGrave")) {
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
final SpellAbility root = sa.getRootAbility();
if (!(spellAbility instanceof SpellAbility)) {
final SpellAbility root = ((SpellAbility)spellAbility).getRootAbility();
if (root != null && (root.getPaidList("MovedToGrave") != null)
&& !root.getPaidList("MovedToGrave").isEmpty()) {
final CardCollectionView cards = root.getPaidList("MovedToGrave");
@@ -1010,7 +917,7 @@ public class CardProperty {
}
}
} else if (property.startsWith("SecondSpellCastThisTurn")) {
final List<Card> cards = CardUtil.getThisTurnCast("Card", source);
final List<Card> cards = CardUtil.getThisTurnCast("Card", source, spellAbility);
if (cards.size() < 2) {
return false;
}
@@ -1018,7 +925,7 @@ public class CardProperty {
return false;
}
} else if (property.equals("ThisTurnCast")) {
for (final Card c : CardUtil.getThisTurnCast("Card", source)) {
for (final Card c : CardUtil.getThisTurnCast("Card", source, spellAbility)) {
if (card.equals(c)) {
return true;
}
@@ -1067,7 +974,7 @@ public class CardProperty {
return false;
}
List<Card> cards = CardUtil.getThisTurnEntered(ZoneType.Graveyard, ZoneType.Hand, "Card", source);
List<Card> cards = CardUtil.getThisTurnEntered(ZoneType.Graveyard, ZoneType.Hand, "Card", source, spellAbility);
if (!cards.contains(card) && !card.getMadnessWithoutCast()) {
return false;
}

View File

@@ -32,6 +32,7 @@ import forge.card.CardStateName;
import forge.card.CardType;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.game.CardTraitBase;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameObject;
@@ -115,7 +116,7 @@ public final class CardUtil {
* @param src a Card object
* @return a CardCollection that matches the given criteria
*/
public static List<Card> getThisTurnEntered(final ZoneType to, final ZoneType from, final String valid, final Card src) {
public static List<Card> getThisTurnEntered(final ZoneType to, final ZoneType from, final String valid, final Card src, final CardTraitBase ctb) {
List<Card> res = Lists.newArrayList();
final Game game = src.getGame();
if (to != ZoneType.Stack) {
@@ -126,8 +127,7 @@ public final class CardUtil {
else {
res.addAll(game.getStackZone().getCardsAddedThisTurn(from));
}
res = CardLists.getValidCardsAsList(res, valid, src.getController(), src, null);
return res;
return CardLists.getValidCardsAsList(res, valid, src.getController(), src, ctb);
}
/**
@@ -139,7 +139,7 @@ public final class CardUtil {
* @param src a Card object
* @return a CardCollection that matches the given criteria
*/
public static List<Card> getLastTurnEntered(final ZoneType to, final ZoneType from, final String valid, final Card src) {
public static List<Card> getLastTurnEntered(final ZoneType to, final ZoneType from, final String valid, final Card src, final CardTraitBase ctb) {
List<Card> res = Lists.newArrayList();
final Game game = src.getGame();
if (to != ZoneType.Stack) {
@@ -150,16 +150,15 @@ public final class CardUtil {
else {
res.addAll(game.getStackZone().getCardsAddedLastTurn(from));
}
res = CardLists.getValidCardsAsList(res, valid, src.getController(), src, null);
return res;
return CardLists.getValidCardsAsList(res, valid, src.getController(), src, ctb);
}
public static List<Card> getThisTurnCast(final String valid, final Card src) {
return CardLists.getValidCardsAsList(src.getGame().getStack().getSpellsCastThisTurn(), valid, src.getController(), src, null);
public static List<Card> getThisTurnCast(final String valid, final Card src, final CardTraitBase ctb) {
return CardLists.getValidCardsAsList(src.getGame().getStack().getSpellsCastThisTurn(), valid, src.getController(), src, ctb);
}
public static List<Card> getLastTurnCast(final String valid, final Card src) {
return CardLists.getValidCardsAsList(src.getGame().getStack().getSpellsCastLastTurn(), valid, src.getController(), src, null);
public static List<Card> getLastTurnCast(final String valid, final Card src, final CardTraitBase ctb) {
return CardLists.getValidCardsAsList(src.getGame().getStack().getSpellsCastLastTurn(), valid, src.getController(), src, ctb);
}

View File

@@ -18,7 +18,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
@@ -139,9 +138,9 @@ public class CostAdjustment {
count = Integer.parseInt(amount);
} else {
if (st.hasParam("AffectedAmount")) {
count = CardFactoryUtil.xCount(card, hostCard.getSVar(amount));
count = AbilityUtils.calculateAmount(card, amount, st);
} else {
count = AbilityUtils.calculateAmount(hostCard, amount, sa);
count = AbilityUtils.calculateAmount(hostCard, amount, st);
}
}
}
@@ -380,7 +379,7 @@ public class CostAdjustment {
int value;
if ("AffectedX".equals(amount)) {
value = CardFactoryUtil.xCount(card, hostCard.getSVar(amount));
value = AbilityUtils.calculateAmount(card, amount, staticAbility);
} else if ("Undaunted".equals(amount)) {
value = card.getController().getOpponents().size();
} else if (staticAbility.hasParam("Relative")) {
@@ -429,13 +428,13 @@ public class CostAdjustment {
final Card card = sa.getHostCard();
final Game game = hostCard.getGame();
if (st.hasParam("ValidCard") && !st.matchesValid(card, st.getParam("ValidCard").split(","))) {
if (!st.matchesValidParam("ValidCard", card)) {
return false;
}
if (st.hasParam("ValidSpell") && !st.matchesValid(sa, st.getParam("ValidSpell").split(","))) {
if (!st.matchesValidParam("ValidSpell", sa)) {
return false;
}
if (st.hasParam("Activator") && !st.matchesValid(activator, st.getParam("Activator").split(","))) {
if (!st.matchesValidParam("Activator", activator)) {
return false;
}
if (st.hasParam("NonActivatorTurn") && ((activator == null)
@@ -455,7 +454,7 @@ public class CostAdjustment {
}
List<Card> list;
if (st.hasParam("ValidCard")) {
list = CardUtil.getThisTurnCast(st.getParam("ValidCard"), hostCard);
list = CardUtil.getThisTurnCast(st.getParam("ValidCard"), hostCard, st);
} else {
list = game.getStack().getSpellsCastThisTurn();
}

View File

@@ -30,7 +30,6 @@ import forge.game.GameType;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPlayOption;
import forge.game.card.CardUtil;
@@ -455,13 +454,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
life = activator.getOpponentsSmallestLifeTotal();
}
int right = 1;
final String rightString = this.getLifeAmount().substring(2);
if (rightString.equals("X")) {
right = CardFactoryUtil.xCount(sa.getHostCard(), sa.getHostCard().getSVar("X"));
} else {
right = Integer.parseInt(this.getLifeAmount().substring(2));
}
int right =AbilityUtils.calculateAmount(sa.getHostCard(), this.getLifeAmount().substring(2), sa);
if (!Expressions.compare(life, this.getLifeAmount(), right)) {
return false;

View File

@@ -23,7 +23,6 @@ import forge.game.GameEntity;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardPredicates;
import forge.game.cost.Cost;
import forge.game.keyword.KeywordInterface;
@@ -199,7 +198,7 @@ public class StaticAbilityCantAttackBlock {
}
String costString = stAb.getParam("Cost");
if (stAb.hasSVar(costString)) {
costString = Integer.toString(CardFactoryUtil.xCount(hostCard, stAb.getSVar(costString)));
costString = Integer.toString(AbilityUtils.calculateAmount(hostCard, costString, stAb));
}
return new Cost(costString, true);

View File

@@ -132,7 +132,7 @@ public class StaticAbilityCantBeCast {
if (stAb.hasParam("NumLimitEachTurn") && activator != null) {
int limit = Integer.parseInt(stAb.getParam("NumLimitEachTurn"));
String valid = stAb.hasParam("ValidCard") ? stAb.getParam("ValidCard") : "Card";
List<Card> thisTurnCast = CardUtil.getThisTurnCast(valid, card);
List<Card> thisTurnCast = CardUtil.getThisTurnCast(valid, card, stAb);
if (CardLists.filterControlledBy(thisTurnCast, activator).size() < limit) {
return false;
}

View File

@@ -638,11 +638,11 @@ public final class StaticAbilityContinuous {
if (layer == StaticAbilityLayer.SETPT) {
if ((setPower != Integer.MAX_VALUE) || (setToughness != Integer.MAX_VALUE)) {
// non CharacteristicDefining
if (setP.startsWith("AffectedX")) {
setPower = CardFactoryUtil.xCount(affectedCard, AbilityUtils.getSVar(stAb, setP));
if (setP.startsWith("Affected")) {
setPower = AbilityUtils.calculateAmount(affectedCard, setP, stAb, true);
}
if (setT.startsWith("AffectedX")) {
setToughness = CardFactoryUtil.xCount(affectedCard, AbilityUtils.getSVar(stAb, setT));
if (setT.startsWith("Affected")) {
setToughness = AbilityUtils.calculateAmount(affectedCard, setT, stAb, true);
}
affectedCard.addNewPT(setPower, setToughness,
hostCard.getTimestamp(), stAb.hasParam("CharacteristicDefining"));
@@ -651,11 +651,11 @@ public final class StaticAbilityContinuous {
// add P/T bonus
if (layer == StaticAbilityLayer.MODIFYPT) {
if (addP.startsWith("AffectedX")) {
powerBonus = CardFactoryUtil.xCount(affectedCard, AbilityUtils.getSVar(stAb, addP));
if (addP.startsWith("Affected")) {
powerBonus = AbilityUtils.calculateAmount(affectedCard, addP, stAb, true);
}
if (addT.startsWith("AffectedX")) {
toughnessBonus = CardFactoryUtil.xCount(affectedCard, AbilityUtils.getSVar(stAb, addT));
if (addT.startsWith("Affected")) {
toughnessBonus = AbilityUtils.calculateAmount(affectedCard, addT, stAb, true);
}
affectedCard.addPTBoost(powerBonus, toughnessBonus, se.getTimestamp(), stAb.getId());
}

View File

@@ -30,7 +30,6 @@ import com.google.common.collect.Sets;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
@@ -139,7 +138,7 @@ public class TriggerChangesZone extends Trigger {
final String comparator = condition.length < 2 ? "GE1" : condition[1];
final int referenceValue = AbilityUtils.calculateAmount(host, comparator.substring(2), this);
final Card triggered = (Card) runParams.get(AbilityKey.Card);
final int actualValue = CardFactoryUtil.xCount(triggered, host.getSVar(condition[0]));
final int actualValue = AbilityUtils.calculateAmount(triggered, condition[0], this);
if (!Expressions.compare(actualValue, comparator.substring(0, 2), referenceValue)) {
return false;
}
@@ -179,7 +178,7 @@ public class TriggerChangesZone extends Trigger {
/* this trigger only activates for the nth spell you cast this turn */
if (hasParam("ConditionYouCastThisTurn")) {
final String compare = getParam("ConditionYouCastThisTurn");
List<Card> thisTurnCast = CardUtil.getThisTurnCast("Card", getHostCard());
List<Card> thisTurnCast = CardUtil.getThisTurnCast("Card", getHostCard(), this);
thisTurnCast = CardLists.filterControlledByAsList(thisTurnCast, getHostCard().getController());
// checks which card this spell was the castSA

View File

@@ -109,7 +109,7 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
if (hasParam("ActivatorThisTurnCast")) {
final String compare = getParam("ActivatorThisTurnCast");
final String valid = hasParam("ValidCard") ? getParam("ValidCard") : "Card";
List<Card> thisTurnCast = CardUtil.getThisTurnCast(valid, getHostCard());
List<Card> thisTurnCast = CardUtil.getThisTurnCast(valid, getHostCard(), this);
thisTurnCast = CardLists.filterControlledBy(thisTurnCast, si.getSpellAbility(true).getActivatingPlayer());
int left = thisTurnCast.size();
int right = Integer.parseInt(compare.substring(2));

View File

@@ -5,5 +5,4 @@ A:SP$ DealDamage | Cost$ 3 R | ValidTgts$ Player | TgtPrompt$ Select target play
SVar:X:TargetedPlayer$LifeTotal
SVar:Y:Count$OppsAtLifeTotal.10
SVar:NeedsToPlayVar:Y GE1
SVar:Picture:http://resources.wizards.com/magic/cards/sok/en-us/card88818.jpg
Oracle:If target player has exactly 10 life, Hidetsugu's Second Rite deals 10 damage to that player.

View File

@@ -11,5 +11,5 @@ SVar:STPlay:Mode$ Continuous | MayPlay$ True | MayPlayIgnoreColor$ True | Effect
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$ValidHand Card.DefenderCtrl
SVar:Y:Count$InYourHand
SVar:Z:Count$CreaturesAttackedThisTurn_Rogue
SVar:Z:Count$CreaturesAttackedThisTurn Creature.Rogue
Oracle:Reach, haste\nWhenever Robber of the Rich attacks, if defending player has more cards in hand than you, exile the top card of their library. During any turn you attacked with a Rogue, you may cast that card and you may spend mana as though it were mana of any color to cast that spell.

View File

@@ -412,8 +412,7 @@ public final class CardScriptParser {
"notTributed", "madness", "Paired", "NotPaired", "PairedWith",
"Above", "DirectlyAbove", "TopGraveyardCreature",
"BottomGraveyard", "TopLibrary", "Cloned", "DamagedBy", "Damaged",
"IsTargetingSource", "sharesPermanentTypeWith",
"canProduceSameManaTypeWith", "SecondSpellCastThisTurn",
"sharesPermanentTypeWith", "canProduceSameManaTypeWith", "SecondSpellCastThisTurn",
"ThisTurnCast", "withFlashback", "tapped", "untapped", "faceDown",
"faceUp", "hasLevelUp", "DrawnThisTurn", "notDrawnThisTurn",
"firstTurnControlled", "notFirstTurnControlled",