mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 02:08:00 +00:00
Card: add Keyword methods that work with Keyword Enum
This commit is contained in:
@@ -358,7 +358,7 @@ public class AiAttackController {
|
|||||||
// In addition, if the computer guesses it needs no blockers, make sure
|
// In addition, if the computer guesses it needs no blockers, make sure
|
||||||
// that
|
// that
|
||||||
// it won't be surprised by Exalted
|
// it won't be surprised by Exalted
|
||||||
final int humanExaltedBonus = countExaltedBonus(opp);
|
final int humanExaltedBonus = opp.countExaltedBonus();
|
||||||
|
|
||||||
if (humanExaltedBonus > 0) {
|
if (humanExaltedBonus > 0) {
|
||||||
final boolean finestHour = opp.isCardInPlay("Finest Hour");
|
final boolean finestHour = opp.isCardInPlay("Finest Hour");
|
||||||
@@ -1049,24 +1049,6 @@ public class AiAttackController {
|
|||||||
}
|
}
|
||||||
} // getAttackers()
|
} // getAttackers()
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* countExaltedBonus.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param player
|
|
||||||
* a {@link forge.game.player.Player} object.
|
|
||||||
* @return a int.
|
|
||||||
*/
|
|
||||||
public final static int countExaltedBonus(final Player player) {
|
|
||||||
int bonus = 0;
|
|
||||||
for (Card c : player.getCardsIn(ZoneType.Battlefield)) {
|
|
||||||
bonus += c.getAmountOfKeyword("Exalted");
|
|
||||||
}
|
|
||||||
|
|
||||||
return bonus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* getAttack.
|
* getAttack.
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import forge.game.card.*;
|
|||||||
import forge.game.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
import forge.game.combat.CombatUtil;
|
import forge.game.combat.CombatUtil;
|
||||||
import forge.game.cost.CostPayment;
|
import forge.game.cost.CostPayment;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.phase.Untap;
|
import forge.game.phase.Untap;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -226,14 +227,15 @@ public class ComputerUtilCombat {
|
|||||||
int damage = attacker.getNetCombatDamage();
|
int damage = attacker.getNetCombatDamage();
|
||||||
int poison = 0;
|
int poison = 0;
|
||||||
damage += ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, null, null, false);
|
damage += ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, null, null, false);
|
||||||
if (attacker.hasKeyword("Infect")) {
|
if (attacker.hasKeyword(Keyword.INFECT)) {
|
||||||
poison += ComputerUtilCombat.predictDamageTo(attacked, damage, attacker, true);
|
int pd = ComputerUtilCombat.predictDamageTo(attacked, damage, attacker, true);
|
||||||
if (attacker.hasKeyword("Double Strike")) {
|
poison += pd;
|
||||||
poison += ComputerUtilCombat.predictDamageTo(attacked, damage, attacker, true);
|
if (attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
||||||
|
poison += pd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (attacker.hasKeyword("Poisonous") && (damage > 0)) {
|
if (attacker.hasKeyword(Keyword.POISONOUS) && (damage > 0)) {
|
||||||
poison += attacker.getKeywordMagnitude("Poisonous");
|
poison += attacker.getKeywordMagnitude(Keyword.POISONOUS);
|
||||||
}
|
}
|
||||||
return poison;
|
return poison;
|
||||||
}
|
}
|
||||||
@@ -343,13 +345,13 @@ public class ComputerUtilCombat {
|
|||||||
|| attacker.hasKeyword("You may have CARDNAME assign its combat damage"
|
|| attacker.hasKeyword("You may have CARDNAME assign its combat damage"
|
||||||
+ " as though it weren't blocked.")) {
|
+ " as though it weren't blocked.")) {
|
||||||
unblocked.add(attacker);
|
unblocked.add(attacker);
|
||||||
} else if (attacker.hasKeyword("Trample")
|
} else if (attacker.hasKeyword(Keyword.TRAMPLE)
|
||||||
&& (ComputerUtilCombat.getAttack(attacker) > ComputerUtilCombat.totalShieldDamage(attacker, blockers))) {
|
&& (ComputerUtilCombat.getAttack(attacker) > ComputerUtilCombat.totalShieldDamage(attacker, blockers))) {
|
||||||
if (attacker.hasKeyword("Infect")) {
|
if (attacker.hasKeyword(Keyword.INFECT)) {
|
||||||
poison += ComputerUtilCombat.getAttack(attacker) - ComputerUtilCombat.totalShieldDamage(attacker, blockers);
|
poison += ComputerUtilCombat.getAttack(attacker) - ComputerUtilCombat.totalShieldDamage(attacker, blockers);
|
||||||
}
|
}
|
||||||
if (attacker.hasKeyword("Poisonous")) {
|
if (attacker.hasKeyword(Keyword.POISONOUS)) {
|
||||||
poison += attacker.getKeywordMagnitude("Poisonous");
|
poison += attacker.getKeywordMagnitude(Keyword.POISONOUS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -595,20 +597,21 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int flankingMagnitude = 0;
|
int flankingMagnitude = 0;
|
||||||
if (attacker.hasKeyword("Flanking") && !defender.hasKeyword("Flanking")) {
|
if (attacker.hasKeyword(Keyword.FLANKING) && !defender.hasKeyword(Keyword.FLANKING)) {
|
||||||
|
|
||||||
flankingMagnitude = attacker.getAmountOfKeyword("Flanking");
|
flankingMagnitude = attacker.getAmountOfKeyword(Keyword.FLANKING);
|
||||||
|
|
||||||
if (flankingMagnitude >= defender.getNetToughness()) {
|
if (flankingMagnitude >= defender.getNetToughness()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((flankingMagnitude >= (defender.getNetToughness() - defender.getDamage()))
|
if ((flankingMagnitude >= (defender.getNetToughness() - defender.getDamage()))
|
||||||
&& !defender.hasKeyword("Indestructible")) {
|
&& !defender.hasKeyword(Keyword.INDESTRUCTIBLE)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // flanking
|
} // flanking
|
||||||
if (attacker.hasKeyword("Indestructible") && !(defender.hasKeyword("Wither") || defender.hasKeyword("Infect"))) {
|
if (attacker.hasKeyword(Keyword.INDESTRUCTIBLE)
|
||||||
|
&& !(defender.hasKeyword(Keyword.WITHER) || defender.hasKeyword(Keyword.INFECT))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -667,21 +670,21 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int flankingMagnitude = 0;
|
int flankingMagnitude = 0;
|
||||||
if (attacker.hasKeyword("Flanking") && !blocker.hasKeyword("Flanking")) {
|
if (attacker.hasKeyword(Keyword.FLANKING) && !blocker.hasKeyword(Keyword.FLANKING)) {
|
||||||
|
|
||||||
flankingMagnitude = attacker.getAmountOfKeyword("Flanking");
|
flankingMagnitude = attacker.getAmountOfKeyword(Keyword.FLANKING);
|
||||||
|
|
||||||
if (flankingMagnitude >= blocker.getNetToughness()) {
|
if (flankingMagnitude >= blocker.getNetToughness()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((flankingMagnitude >= (blocker.getNetToughness() - blocker.getDamage()))
|
if ((flankingMagnitude >= (blocker.getNetToughness() - blocker.getDamage()))
|
||||||
&& !blocker.hasKeyword("Indestructible")) {
|
&& !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // flanking
|
} // flanking
|
||||||
|
|
||||||
final int defBushidoMagnitude = blocker.getKeywordMagnitude("Bushido");
|
final int defBushidoMagnitude = blocker.getKeywordMagnitude(Keyword.BUSHIDO);
|
||||||
|
|
||||||
final int defenderDefense = (blocker.getLethalDamage() - flankingMagnitude) + defBushidoMagnitude;
|
final int defenderDefense = (blocker.getLethalDamage() - flankingMagnitude) + defBushidoMagnitude;
|
||||||
|
|
||||||
@@ -727,16 +730,16 @@ public class ComputerUtilCombat {
|
|||||||
|
|
||||||
for (final Card defender : blockers) {
|
for (final Card defender : blockers) {
|
||||||
if (ComputerUtilCombat.canDestroyAttacker(ai, attacker, defender, combat, true)
|
if (ComputerUtilCombat.canDestroyAttacker(ai, attacker, defender, combat, true)
|
||||||
&& !(defender.hasKeyword("Wither") || defender.hasKeyword("Infect"))) {
|
&& !(defender.hasKeyword(Keyword.WITHER) || defender.hasKeyword(Keyword.INFECT))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (defender.hasKeyword("First Strike") || defender.hasKeyword("Double Strike")) {
|
if (defender.hasKeyword(Keyword.FIRST_STRIKE) || defender.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
||||||
firstStrikeBlockerDmg += defender.getNetCombatDamage();
|
firstStrikeBlockerDmg += defender.getNetCombatDamage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consider first strike and double strike
|
// Consider first strike and double strike
|
||||||
if (attacker.hasKeyword("First Strike") || attacker.hasKeyword("Double Strike")) {
|
if (attacker.hasKeyword(Keyword.FIRST_STRIKE) || attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
||||||
return firstStrikeBlockerDmg >= ComputerUtilCombat.getDamageToKill(attacker);
|
return firstStrikeBlockerDmg >= ComputerUtilCombat.getDamageToKill(attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1069,8 +1072,8 @@ public class ComputerUtilCombat {
|
|||||||
public static int predictToughnessBonusOfBlocker(final Card attacker, final Card blocker, boolean withoutAbilities) {
|
public static int predictToughnessBonusOfBlocker(final Card attacker, final Card blocker, boolean withoutAbilities) {
|
||||||
int toughness = 0;
|
int toughness = 0;
|
||||||
|
|
||||||
if (attacker.hasKeyword("Flanking") && !blocker.hasKeyword("Flanking")) {
|
if (attacker.hasKeyword(Keyword.FLANKING) && !blocker.hasKeyword(Keyword.FLANKING)) {
|
||||||
toughness -= attacker.getAmountOfKeyword("Flanking");
|
toughness -= attacker.getAmountOfKeyword(Keyword.FLANKING);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blocker.getName().equals("Shape Stealer")) {
|
if (blocker.getName().equals("Shape Stealer")) {
|
||||||
@@ -1239,9 +1242,7 @@ public class ComputerUtilCombat {
|
|||||||
|
|
||||||
//check Exalted only for the first attacker
|
//check Exalted only for the first attacker
|
||||||
if (combat != null && combat.getAttackers().isEmpty()) {
|
if (combat != null && combat.getAttackers().isEmpty()) {
|
||||||
for (Card card : attacker.getController().getCardsIn(ZoneType.Battlefield)) {
|
power += attacker.getController().countExaltedBonus();
|
||||||
power += card.getAmountOfKeyword("Exalted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serene Master switches power with attacker
|
// Serene Master switches power with attacker
|
||||||
@@ -1263,8 +1264,8 @@ public class ComputerUtilCombat {
|
|||||||
// less damage than expected
|
// less damage than expected
|
||||||
if (null != blocker) {
|
if (null != blocker) {
|
||||||
if (ComputerUtilCombat.dealsFirstStrikeDamage(blocker, withoutAbilities, combat)
|
if (ComputerUtilCombat.dealsFirstStrikeDamage(blocker, withoutAbilities, combat)
|
||||||
&& (blocker.hasKeyword("Wither") || blocker.hasKeyword("Infect"))
|
&& (blocker.hasKeyword(Keyword.WITHER) || blocker.hasKeyword(Keyword.INFECT))
|
||||||
&& !ComputerUtilCombat.dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
|
&& !ComputerUtilCombat.dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
|
||||||
&& !attacker.hasKeyword("CARDNAME can't have counters put on it.")) {
|
&& !attacker.hasKeyword("CARDNAME can't have counters put on it.")) {
|
||||||
power -= blocker.getNetCombatDamage();
|
power -= blocker.getNetCombatDamage();
|
||||||
}
|
}
|
||||||
@@ -1446,9 +1447,7 @@ public class ComputerUtilCombat {
|
|||||||
|
|
||||||
//check Exalted only for the first attacker
|
//check Exalted only for the first attacker
|
||||||
if (combat != null && combat.getAttackers().isEmpty()) {
|
if (combat != null && combat.getAttackers().isEmpty()) {
|
||||||
for (Card card : attacker.getController().getCardsIn(ZoneType.Battlefield)) {
|
toughness += attacker.getController().countExaltedBonus();
|
||||||
toughness += card.getAmountOfKeyword("Exalted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blocker != null && attacker.getName().equals("Shape Stealer")) {
|
if (blocker != null && attacker.getName().equals("Shape Stealer")) {
|
||||||
@@ -1766,24 +1765,24 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int flankingMagnitude = 0;
|
int flankingMagnitude = 0;
|
||||||
if (attacker.hasKeyword("Flanking") && !blocker.hasKeyword("Flanking")) {
|
if (attacker.hasKeyword(Keyword.FLANKING) && !blocker.hasKeyword(Keyword.FLANKING)) {
|
||||||
|
|
||||||
flankingMagnitude = attacker.getAmountOfKeyword("Flanking");
|
flankingMagnitude = attacker.getAmountOfKeyword(Keyword.FLANKING);
|
||||||
|
|
||||||
if (flankingMagnitude >= blocker.getNetToughness()) {
|
if (flankingMagnitude >= blocker.getNetToughness()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((flankingMagnitude >= (blocker.getNetToughness() - blocker.getDamage()))
|
if ((flankingMagnitude >= (blocker.getNetToughness() - blocker.getDamage()))
|
||||||
&& !blocker.hasKeyword("Indestructible")) {
|
&& !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} // flanking
|
} // flanking
|
||||||
|
|
||||||
if (((attacker.hasKeyword("Indestructible") || (ComputerUtil.canRegenerate(ai, attacker) && !withoutAbilities))
|
if (((attacker.hasKeyword(Keyword.INDESTRUCTIBLE) || (ComputerUtil.canRegenerate(ai, attacker) && !withoutAbilities))
|
||||||
&& !(blocker.hasKeyword("Wither") || blocker.hasKeyword("Infect")))
|
&& !(blocker.hasKeyword(Keyword.WITHER) || blocker.hasKeyword(Keyword.INFECT)))
|
||||||
|| (attacker.hasKeyword("Persist") && !attacker.canReceiveCounters(CounterType.M1M1) && (attacker
|
|| (attacker.hasKeyword(Keyword.PERSIST) && !attacker.canReceiveCounters(CounterType.M1M1) && (attacker
|
||||||
.getCounters(CounterType.M1M1) == 0))
|
.getCounters(CounterType.M1M1) == 0))
|
||||||
|| (attacker.hasKeyword("Undying") && !attacker.canReceiveCounters(CounterType.P1P1) && (attacker
|
|| (attacker.hasKeyword(Keyword.UNDYING) && !attacker.canReceiveCounters(CounterType.P1P1) && (attacker
|
||||||
.getCounters(CounterType.P1P1) == 0))) {
|
.getCounters(CounterType.P1P1) == 0))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1895,7 +1894,7 @@ public class ComputerUtilCombat {
|
|||||||
|
|
||||||
for (Card attacker : attackers) {
|
for (Card attacker : attackers) {
|
||||||
if (ComputerUtilCombat.canDestroyBlocker(ai, blocker, attacker, combat, true)
|
if (ComputerUtilCombat.canDestroyBlocker(ai, blocker, attacker, combat, true)
|
||||||
&& !(attacker.hasKeyword("Wither") || attacker.hasKeyword("Infect"))) {
|
&& !(attacker.hasKeyword(Keyword.WITHER) || attacker.hasKeyword(Keyword.INFECT))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1913,19 +1912,21 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int flankingMagnitude = 0;
|
int flankingMagnitude = 0;
|
||||||
if (attacker.hasKeyword("Flanking") && !blocker.hasKeyword("Flanking")) {
|
if (attacker.hasKeyword(Keyword.FLANKING) && !blocker.hasKeyword(Keyword.FLANKING)) {
|
||||||
|
|
||||||
flankingMagnitude = attacker.getAmountOfKeyword("Flanking");
|
flankingMagnitude = attacker.getAmountOfKeyword(Keyword.FLANKING);
|
||||||
|
|
||||||
if (flankingMagnitude >= blocker.getNetToughness()) {
|
if (flankingMagnitude >= blocker.getNetToughness()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((flankingMagnitude >= ComputerUtilCombat.getDamageToKill(blocker)) && !blocker.hasKeyword("Indestructible")) {
|
if ((flankingMagnitude >= ComputerUtilCombat.getDamageToKill(blocker))
|
||||||
|
&& !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // flanking
|
} // flanking
|
||||||
|
|
||||||
if (blocker.hasKeyword("Indestructible") || dontTestRegen || ComputerUtil.canRegenerate(blocker.getController(), blocker)) {
|
if (blocker.hasKeyword(Keyword.INDESTRUCTIBLE) || dontTestRegen
|
||||||
|
|| ComputerUtil.canRegenerate(blocker.getController(), blocker)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2516,7 +2517,7 @@ public class ComputerUtilCombat {
|
|||||||
|
|
||||||
public static boolean attackerHasThreateningAfflict(Card attacker, Player aiDefender) {
|
public static boolean attackerHasThreateningAfflict(Card attacker, Player aiDefender) {
|
||||||
// TODO: expand this to account for more complex situations like the Wildfire Eternal unblocked trigger
|
// TODO: expand this to account for more complex situations like the Wildfire Eternal unblocked trigger
|
||||||
int afflictDmg = attacker.getKeywordMagnitude("Afflict");
|
int afflictDmg = attacker.getKeywordMagnitude(Keyword.AFFLICT);
|
||||||
return afflictDmg > attacker.getNetPower() || afflictDmg >= aiDefender.getLife();
|
return afflictDmg > attacker.getNetPower() || afflictDmg >= aiDefender.getLife();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import forge.game.ability.ApiType;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
import forge.game.cost.CostPayEnergy;
|
import forge.game.cost.CostPayEnergy;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
|
||||||
@@ -53,10 +54,10 @@ public class CreatureEvaluator implements Function<Card, Integer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Evasion keywords
|
// Evasion keywords
|
||||||
if (c.hasKeyword("Flying")) {
|
if (c.hasKeyword(Keyword.FLYING)) {
|
||||||
value += addValue(power * 10, "flying");
|
value += addValue(power * 10, "flying");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Horsemanship")) {
|
if (c.hasKeyword(Keyword.HORSEMANSHIP)) {
|
||||||
value += addValue(power * 10, "horses");
|
value += addValue(power * 10, "horses");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Unblockable")) {
|
if (c.hasKeyword("Unblockable")) {
|
||||||
@@ -65,13 +66,13 @@ public class CreatureEvaluator implements Function<Card, Integer> {
|
|||||||
if (c.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")) {
|
if (c.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")) {
|
||||||
value += addValue(power * 6, "thorns");
|
value += addValue(power * 6, "thorns");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Fear")) {
|
if (c.hasKeyword(Keyword.FEAR)) {
|
||||||
value += addValue(power * 6, "fear");
|
value += addValue(power * 6, "fear");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Intimidate")) {
|
if (c.hasKeyword(Keyword.INTIMIDATE)) {
|
||||||
value += addValue(power * 6, "intimidate");
|
value += addValue(power * 6, "intimidate");
|
||||||
}
|
}
|
||||||
if (c.hasStartOfKeyword("Menace")) {
|
if (c.hasKeyword(Keyword.MENACE)) {
|
||||||
value += addValue(power * 4, "menace");
|
value += addValue(power * 4, "menace");
|
||||||
}
|
}
|
||||||
if (c.hasStartOfKeyword("CantBeBlockedBy")) {
|
if (c.hasStartOfKeyword("CantBeBlockedBy")) {
|
||||||
@@ -81,49 +82,49 @@ public class CreatureEvaluator implements Function<Card, Integer> {
|
|||||||
|
|
||||||
// Other good keywords
|
// Other good keywords
|
||||||
if (power > 0) {
|
if (power > 0) {
|
||||||
if (c.hasKeyword("Double Strike")) {
|
if (c.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
||||||
value += addValue(10 + (power * 15), "ds");
|
value += addValue(10 + (power * 15), "ds");
|
||||||
} else if (c.hasKeyword("First Strike")) {
|
} else if (c.hasKeyword("First Strike")) {
|
||||||
value += addValue(10 + (power * 5), "fs");
|
value += addValue(10 + (power * 5), "fs");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Deathtouch")) {
|
if (c.hasKeyword(Keyword.DEATHTOUCH)) {
|
||||||
value += addValue(25, "dt");
|
value += addValue(25, "dt");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Lifelink")) {
|
if (c.hasKeyword(Keyword.LIFELINK)) {
|
||||||
value += addValue(power * 10, "lifelink");
|
value += addValue(power * 10, "lifelink");
|
||||||
}
|
}
|
||||||
if (power > 1 && c.hasKeyword("Trample")) {
|
if (power > 1 && c.hasKeyword(Keyword.TRAMPLE)) {
|
||||||
value += addValue((power - 1) * 5, "trample");
|
value += addValue((power - 1) * 5, "trample");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Vigilance")) {
|
if (c.hasKeyword(Keyword.VIGILANCE)) {
|
||||||
value += addValue((power * 5) + (toughness * 5), "vigilance");
|
value += addValue((power * 5) + (toughness * 5), "vigilance");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Wither")) {
|
if (c.hasKeyword(Keyword.WITHER)) {
|
||||||
value += addValue(power * 10, "Wither");
|
value += addValue(power * 10, "Wither");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Infect")) {
|
if (c.hasKeyword(Keyword.INFECT)) {
|
||||||
value += addValue(power * 15, "infect");
|
value += addValue(power * 15, "infect");
|
||||||
}
|
}
|
||||||
value += addValue(c.getKeywordMagnitude("Rampage"), "rampage");
|
value += addValue(c.getKeywordMagnitude(Keyword.RAMPAGE), "rampage");
|
||||||
value += addValue(c.getKeywordMagnitude("Afflict") * 5, "afflict");
|
value += addValue(c.getKeywordMagnitude(Keyword.AFFLICT) * 5, "afflict");
|
||||||
}
|
}
|
||||||
|
|
||||||
value += addValue(c.getKeywordMagnitude("Bushido") * 16, "bushido");
|
value += addValue(c.getKeywordMagnitude(Keyword.BUSHIDO) * 16, "bushido");
|
||||||
value += addValue(c.getAmountOfKeyword("Flanking") * 15, "flanking");
|
value += addValue(c.getAmountOfKeyword(Keyword.FLANKING) * 15, "flanking");
|
||||||
value += addValue(c.getAmountOfKeyword("Exalted") * 15, "exalted");
|
value += addValue(c.getAmountOfKeyword(Keyword.EXALTED) * 15, "exalted");
|
||||||
value += addValue(c.getKeywordMagnitude("Annihilator") * 50, "eldrazi");
|
value += addValue(c.getKeywordMagnitude(Keyword.ANNIHILATOR) * 50, "eldrazi");
|
||||||
value += addValue(c.getKeywordMagnitude("Absorb") * 11, "absorb");
|
value += addValue(c.getKeywordMagnitude(Keyword.ABSORB) * 11, "absorb");
|
||||||
|
|
||||||
// Keywords that may produce temporary or permanent buffs over time
|
// Keywords that may produce temporary or permanent buffs over time
|
||||||
if (c.hasKeyword("Prowess")) {
|
if (c.hasKeyword("Prowess")) {
|
||||||
value += addValue(5, "prowess");
|
value += addValue(5, "prowess");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Outlast")) {
|
if (c.hasKeyword(Keyword.OUTLAST)) {
|
||||||
value += addValue(10, "outlast");
|
value += addValue(10, "outlast");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defensive Keywords
|
// Defensive Keywords
|
||||||
if (c.hasKeyword("Reach") && !c.hasKeyword("Flying")) {
|
if (c.hasKeyword(Keyword.REACH) && !c.hasKeyword(Keyword.FLYING)) {
|
||||||
value += addValue(5, "reach");
|
value += addValue(5, "reach");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("CARDNAME can block creatures with shadow as though they didn't have shadow.")) {
|
if (c.hasKeyword("CARDNAME can block creatures with shadow as though they didn't have shadow.")) {
|
||||||
@@ -131,7 +132,7 @@ public class CreatureEvaluator implements Function<Card, Integer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Protection
|
// Protection
|
||||||
if (c.hasKeyword("Indestructible")) {
|
if (c.hasKeyword(Keyword.INDESTRUCTIBLE)) {
|
||||||
value += addValue(70, "darksteel");
|
value += addValue(70, "darksteel");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Prevent all damage that would be dealt to CARDNAME.")) {
|
if (c.hasKeyword("Prevent all damage that would be dealt to CARDNAME.")) {
|
||||||
@@ -139,20 +140,17 @@ public class CreatureEvaluator implements Function<Card, Integer> {
|
|||||||
} else if (c.hasKeyword("Prevent all combat damage that would be dealt to CARDNAME.")) {
|
} else if (c.hasKeyword("Prevent all combat damage that would be dealt to CARDNAME.")) {
|
||||||
value += addValue(50, "fogbank");
|
value += addValue(50, "fogbank");
|
||||||
}
|
}
|
||||||
if (c.hasKeyword("Hexproof")) {
|
if (c.hasKeyword(Keyword.HEXPROOF)) {
|
||||||
value += addValue(35, "hexproof");
|
value += addValue(35, "hexproof");
|
||||||
} else if (c.hasKeyword("Shroud")) {
|
} else if (c.hasKeyword(Keyword.SHROUD)) {
|
||||||
value += addValue(30, "shroud");
|
value += addValue(30, "shroud");
|
||||||
}
|
}
|
||||||
if (c.hasStartOfKeyword("Protection")) {
|
if (c.hasStartOfKeyword("Protection")) {
|
||||||
value += addValue(20, "protection");
|
value += addValue(20, "protection");
|
||||||
}
|
}
|
||||||
if (c.hasStartOfKeyword("PreventAllDamageBy")) {
|
|
||||||
value += addValue(10, "prevent-dmg");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bad keywords
|
// Bad keywords
|
||||||
if (c.hasKeyword("Defender") || c.hasKeyword("CARDNAME can't attack.")) {
|
if (c.hasKeyword(Keyword.DEFENDER) || c.hasKeyword("CARDNAME can't attack.")) {
|
||||||
value -= subValue((power * 9) + 40, "defender");
|
value -= subValue((power * 9) + 40, "defender");
|
||||||
} else if (c.getSVar("SacrificeEndCombat").equals("True")) {
|
} else if (c.getSVar("SacrificeEndCombat").equals("True")) {
|
||||||
value -= subValue(40, "sac-end");
|
value -= subValue(40, "sac-end");
|
||||||
@@ -195,10 +193,10 @@ public class CreatureEvaluator implements Function<Card, Integer> {
|
|||||||
if (c.hasStartOfKeyword("At the beginning of your upkeep, CARDNAME deals")) {
|
if (c.hasStartOfKeyword("At the beginning of your upkeep, CARDNAME deals")) {
|
||||||
value -= subValue(20, "upkeep-dmg");
|
value -= subValue(20, "upkeep-dmg");
|
||||||
}
|
}
|
||||||
if (c.hasStartOfKeyword("Fading")) {
|
if (c.hasKeyword(Keyword.FADING)) {
|
||||||
value -= subValue(20, "fading");
|
value -= subValue(20, "fading");
|
||||||
}
|
}
|
||||||
if (c.hasStartOfKeyword("Vanishing")) {
|
if (c.hasKeyword(Keyword.VANISHING)) {
|
||||||
value -= subValue(20, "vanishing");
|
value -= subValue(20, "vanishing");
|
||||||
}
|
}
|
||||||
if (c.getSVar("Targeting").equals("Dies")) {
|
if (c.getSVar("Targeting").equals("Dies")) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package forge.util;
|
package forge.util;
|
||||||
|
|
||||||
public abstract class Visitor<T> {
|
public abstract class Visitor<T> {
|
||||||
public abstract void visit(T object);
|
public abstract boolean visit(T object);
|
||||||
|
|
||||||
public void visitAll(Iterable<? extends T> objects) {
|
public void visitAll(Iterable<? extends T> objects) {
|
||||||
for (T obj : objects) {
|
for (T obj : objects) {
|
||||||
|
|||||||
@@ -553,8 +553,9 @@ public class Game {
|
|||||||
final CardCollection all = new CardCollection();
|
final CardCollection all = new CardCollection();
|
||||||
Visitor<Card> visitor = new Visitor<Card>() {
|
Visitor<Card> visitor = new Visitor<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(Card card) {
|
public boolean visit(Card card) {
|
||||||
all.add(card);
|
all.add(card);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
forEachCardInGame(visitor);
|
forEachCardInGame(visitor);
|
||||||
|
|||||||
@@ -792,7 +792,7 @@ public class GameAction {
|
|||||||
|
|
||||||
game.forEachCardInGame(new Visitor<Card>() {
|
game.forEachCardInGame(new Visitor<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(final Card c) {
|
public boolean visit(final Card c) {
|
||||||
// need to get Card from preList if able
|
// need to get Card from preList if able
|
||||||
final Card co = preList.get(c);
|
final Card co = preList.get(c);
|
||||||
for (int i = 0; i < co.getStaticAbilities().size(); i++) {
|
for (int i = 0; i < co.getStaticAbilities().size(); i++) {
|
||||||
@@ -808,6 +808,7 @@ public class GameAction {
|
|||||||
if (!co.getStaticCommandList().isEmpty()) {
|
if (!co.getStaticCommandList().isEmpty()) {
|
||||||
staticList.add(co);
|
staticList.add(co);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import forge.game.ability.ApiType;
|
|||||||
import forge.game.card.*;
|
import forge.game.card.*;
|
||||||
import forge.game.card.CardPlayOption.PayManaCost;
|
import forge.game.card.CardPlayOption.PayManaCost;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.*;
|
import forge.game.spellability.*;
|
||||||
@@ -482,8 +483,8 @@ public final class GameActionUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.hasKeyword("Conspire")) {
|
if (source.hasKeyword(Keyword.CONSPIRE)) {
|
||||||
int amount = source.getAmountOfKeyword("Conspire");
|
int amount = source.getAmountOfKeyword(Keyword.CONSPIRE);
|
||||||
for (int kwInstance = 1; kwInstance <= amount; kwInstance++) {
|
for (int kwInstance = 1; kwInstance <= amount; kwInstance++) {
|
||||||
for (int i = 0; i < abilities.size(); i++) {
|
for (int i = 0; i < abilities.size(); i++) {
|
||||||
final SpellAbility newSA = abilities.get(i).copy();
|
final SpellAbility newSA = abilities.get(i).copy();
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import forge.game.card.CardDamageMap;
|
|||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
import forge.game.event.GameEventCardAttachment;
|
import forge.game.event.GameEventCardAttachment;
|
||||||
import forge.game.event.GameEventCardAttachment.AttachMethod;
|
import forge.game.event.GameEventCardAttachment.AttachMethod;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
import forge.util.collect.FCollection;
|
import forge.util.collect.FCollection;
|
||||||
@@ -275,6 +276,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean hasKeyword(final String keyword);
|
public abstract boolean hasKeyword(final String keyword);
|
||||||
|
public abstract boolean hasKeyword(final Keyword keyword);
|
||||||
|
|
||||||
// GameEntities can now be Enchanted
|
// GameEntities can now be Enchanted
|
||||||
public final CardCollectionView getEnchantedBy(boolean allowModify) {
|
public final CardCollectionView getEnchantedBy(boolean allowModify) {
|
||||||
|
|||||||
@@ -1007,11 +1007,11 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasFirstStrike() {
|
public final boolean hasFirstStrike() {
|
||||||
return hasKeyword("First Strike");
|
return hasKeyword(Keyword.FIRST_STRIKE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasDoubleStrike() {
|
public final boolean hasDoubleStrike() {
|
||||||
return hasKeyword("Double Strike");
|
return hasKeyword(Keyword.DOUBLE_STRIKE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasSecondStrike() {
|
public final boolean hasSecondStrike() {
|
||||||
@@ -2338,11 +2338,11 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasSickness() {
|
public final boolean hasSickness() {
|
||||||
return sickness && !hasKeyword("Haste");
|
return sickness && !hasKeyword(Keyword.HASTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isSick() {
|
public final boolean isSick() {
|
||||||
return sickness && isCreature() && !hasKeyword("Haste");
|
return sickness && isCreature() && !hasKeyword(Keyword.HASTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasBecomeTargetThisTurn() {
|
public boolean hasBecomeTargetThisTurn() {
|
||||||
@@ -3217,6 +3217,15 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
visitHiddenExtreinsicKeywords(visitor);
|
visitHiddenExtreinsicKeywords(visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean hasKeyword(Keyword keyword) {
|
||||||
|
return hasKeyword(keyword, currentState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean hasKeyword(Keyword key, CardState state) {
|
||||||
|
return state.hasKeyword(key);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean hasKeyword(String keyword) {
|
public final boolean hasKeyword(String keyword) {
|
||||||
return hasKeyword(keyword, currentState);
|
return hasKeyword(keyword, currentState);
|
||||||
@@ -3227,9 +3236,9 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
keyword = keyword.substring(7);
|
keyword = keyword.substring(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
CountKeywordVisitor visitor = new CountKeywordVisitor(keyword);
|
HasKeywordVisitor visitor = new HasKeywordVisitor(keyword, false);
|
||||||
visitKeywords(state, visitor);
|
visitKeywords(state, visitor);
|
||||||
return visitor.getCount() > 0;
|
return visitor.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void updateKeywords() {
|
public final void updateKeywords() {
|
||||||
@@ -3345,20 +3354,26 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.setCachedKeywords(keywords.getValues());
|
state.setCachedKeywords(keywords);
|
||||||
}
|
}
|
||||||
private void visitUnhiddenKeywords(CardState state, Visitor<KeywordInterface> visitor) {
|
private void visitUnhiddenKeywords(CardState state, Visitor<KeywordInterface> visitor) {
|
||||||
if (changedCardKeywords.isEmpty()) {
|
if (changedCardKeywords.isEmpty()) {
|
||||||
// Fast path that doesn't involve temp allocations.
|
// Fast path that doesn't involve temp allocations.
|
||||||
for (KeywordInterface kw : state.getIntrinsicKeywords()) {
|
for (KeywordInterface kw : state.getIntrinsicKeywords()) {
|
||||||
visitor.visit(kw);
|
if (!visitor.visit(kw)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (KeywordInterface kw : extrinsicKeyword.getValues()) {
|
for (KeywordInterface kw : extrinsicKeyword.getValues()) {
|
||||||
visitor.visit(kw);
|
if (!visitor.visit(kw)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (KeywordInterface kw : getUnhiddenKeywords(state)) {
|
for (KeywordInterface kw : getUnhiddenKeywords(state)) {
|
||||||
visitor.visit(kw);
|
if (!visitor.visit(kw)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3571,7 +3586,9 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
private void visitHiddenExtreinsicKeywords(Visitor<KeywordInterface> visitor) {
|
private void visitHiddenExtreinsicKeywords(Visitor<KeywordInterface> visitor) {
|
||||||
for (KeywordInterface inst : hiddenExtrinsicKeyword.getValues()) {
|
for (KeywordInterface inst : hiddenExtrinsicKeyword.getValues()) {
|
||||||
visitor.visit(inst);
|
if (!visitor.visit(inst)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3820,18 +3837,18 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
return hasStartOfKeyword(keyword, currentState);
|
return hasStartOfKeyword(keyword, currentState);
|
||||||
}
|
}
|
||||||
public final boolean hasStartOfKeyword(String keyword, CardState state) {
|
public final boolean hasStartOfKeyword(String keyword, CardState state) {
|
||||||
CountKeywordVisitor visitor = new CountKeywordVisitor(keyword, true);
|
HasKeywordVisitor visitor = new HasKeywordVisitor(keyword, true);
|
||||||
visitKeywords(state, visitor);
|
visitKeywords(state, visitor);
|
||||||
return visitor.getCount() > 0;
|
return visitor.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasStartOfUnHiddenKeyword(String keyword) {
|
public final boolean hasStartOfUnHiddenKeyword(String keyword) {
|
||||||
return hasStartOfUnHiddenKeyword(keyword, currentState);
|
return hasStartOfUnHiddenKeyword(keyword, currentState);
|
||||||
}
|
}
|
||||||
public final boolean hasStartOfUnHiddenKeyword(String keyword, CardState state) {
|
public final boolean hasStartOfUnHiddenKeyword(String keyword, CardState state) {
|
||||||
CountKeywordVisitor visitor = new CountKeywordVisitor(keyword, true);
|
HasKeywordVisitor visitor = new HasKeywordVisitor(keyword, true);
|
||||||
visitUnhiddenKeywords(state, visitor);
|
visitUnhiddenKeywords(state, visitor);
|
||||||
return visitor.getCount() > 0;
|
return visitor.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean hasAnyKeyword(final Iterable<String> keywords) {
|
public final boolean hasAnyKeyword(final Iterable<String> keywords) {
|
||||||
@@ -3856,25 +3873,42 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
return visitor.getCount();
|
return visitor.getCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final int getAmountOfKeyword(final Keyword k) {
|
||||||
|
return getAmountOfKeyword(k, currentState);
|
||||||
|
}
|
||||||
|
public final int getAmountOfKeyword(final Keyword k, CardState state) {
|
||||||
|
return state.getCachedKeyword(k).size();
|
||||||
|
}
|
||||||
|
|
||||||
// This is for keywords with a number like Bushido, Annihilator and Rampage.
|
// This is for keywords with a number like Bushido, Annihilator and Rampage.
|
||||||
// It returns the total.
|
// It returns the total.
|
||||||
public final int getKeywordMagnitude(final String k) {
|
public final int getKeywordMagnitude(final Keyword k) {
|
||||||
return getKeywordMagnitude(k, currentState);
|
return getKeywordMagnitude(k, currentState);
|
||||||
}
|
}
|
||||||
public final int getKeywordMagnitude(final String k, CardState state) {
|
|
||||||
|
/**
|
||||||
|
* use it only for real keywords and not with hidden ones
|
||||||
|
*
|
||||||
|
* @param Keyword k
|
||||||
|
* @param CardState state
|
||||||
|
* @return Int
|
||||||
|
*/
|
||||||
|
public final int getKeywordMagnitude(final Keyword k, CardState state) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (final KeywordInterface inst : getKeywords(state)) {
|
for (final KeywordInterface inst : state.getCachedKeyword(k)) {
|
||||||
String kw = inst.getOriginal();
|
String kw = inst.getOriginal();
|
||||||
if (kw.startsWith(k)) {
|
// this can't be used yet for everything because of X values in Bushido X
|
||||||
final String[] parse = kw.contains(":") ? kw.split(":") : kw.split(" ");
|
// KeywordInterface#getAmount
|
||||||
final String s = parse[1];
|
// KeywordCollection#getAmount
|
||||||
if (StringUtils.isNumeric(s)) {
|
|
||||||
count += Integer.parseInt(s);
|
final String[] parse = kw.contains(":") ? kw.split(":") : kw.split(" ");
|
||||||
} else {
|
final String s = parse[1];
|
||||||
String svar = StringUtils.join(parse);
|
if (StringUtils.isNumeric(s)) {
|
||||||
if (state.hasSVar(svar)) {
|
count += Integer.parseInt(s);
|
||||||
count += AbilityUtils.calculateAmount(this, state.getSVar(svar), null);
|
} else {
|
||||||
}
|
String svar = StringUtils.join(parse);
|
||||||
|
if (state.hasSVar(svar)) {
|
||||||
|
count += AbilityUtils.calculateAmount(this, state.getSVar(svar), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4538,7 +4572,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
final Game game = source.getGame();
|
final Game game = source.getGame();
|
||||||
|
|
||||||
boolean wither = (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.alwaysWither)
|
boolean wither = (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.alwaysWither)
|
||||||
|| source.hasKeyword("Wither") || source.hasKeyword("Infect"));
|
|| source.hasKeyword(Keyword.WITHER) || source.hasKeyword(Keyword.INFECT));
|
||||||
|
|
||||||
if (isInPlay()) {
|
if (isInPlay()) {
|
||||||
if (wither) {
|
if (wither) {
|
||||||
@@ -4551,7 +4585,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.hasKeyword("Deathtouch") && isCreature()) {
|
if (source.hasKeyword(Keyword.DEATHTOUCH) && isCreature()) {
|
||||||
setHasBeenDealtDeathtouchDamage(true);
|
setHasBeenDealtDeathtouchDamage(true);
|
||||||
damageType = DamageType.Deathtouch;
|
damageType = DamageType.Deathtouch;
|
||||||
}
|
}
|
||||||
@@ -4943,7 +4977,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final boolean canBeDestroyed() {
|
public final boolean canBeDestroyed() {
|
||||||
return isInPlay() && (!hasKeyword("Indestructible") || (isCreature() && getNetToughness() <= 0));
|
return isInPlay() && (!hasKeyword(Keyword.INDESTRUCTIBLE) || (isCreature() && getNetToughness() <= 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean canBeSacrificed() {
|
public final boolean canBeSacrificed() {
|
||||||
@@ -4983,10 +5017,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
final MutableBoolean result = new MutableBoolean(true);
|
final MutableBoolean result = new MutableBoolean(true);
|
||||||
visitKeywords(currentState, new Visitor<KeywordInterface>() {
|
visitKeywords(currentState, new Visitor<KeywordInterface>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(KeywordInterface kw) {
|
public boolean visit(KeywordInterface kw) {
|
||||||
if (result.isFalse()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (kw.getOriginal()) {
|
switch (kw.getOriginal()) {
|
||||||
case "Shroud":
|
case "Shroud":
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -5015,6 +5046,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return result.isTrue();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (result.isFalse()) {
|
if (result.isFalse()) {
|
||||||
@@ -5506,11 +5538,12 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(KeywordInterface inst) {
|
public boolean visit(KeywordInterface inst) {
|
||||||
final String kw = inst.getOriginal();
|
final String kw = inst.getOriginal();
|
||||||
if ((startOf && kw.startsWith(keyword)) || kw.equals(keyword)) {
|
if ((startOf && kw.startsWith(keyword)) || kw.equals(keyword)) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
@@ -5518,13 +5551,38 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class HasKeywordVisitor extends Visitor<KeywordInterface> {
|
||||||
|
private String keyword;
|
||||||
|
private final MutableBoolean result = new MutableBoolean(false);
|
||||||
|
|
||||||
|
private boolean startOf;
|
||||||
|
private HasKeywordVisitor(String keyword, boolean startOf) {
|
||||||
|
this.keyword = keyword;
|
||||||
|
this.startOf = startOf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(KeywordInterface inst) {
|
||||||
|
final String kw = inst.getOriginal();
|
||||||
|
if ((startOf && kw.startsWith(keyword)) || kw.equals(keyword)) {
|
||||||
|
result.setTrue();
|
||||||
|
}
|
||||||
|
return result.isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getResult() {
|
||||||
|
return result.isTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Collects all the keywords into a list.
|
// Collects all the keywords into a list.
|
||||||
private static final class ListKeywordVisitor extends Visitor<KeywordInterface> {
|
private static final class ListKeywordVisitor extends Visitor<KeywordInterface> {
|
||||||
private List<KeywordInterface> keywords = Lists.newArrayList();
|
private List<KeywordInterface> keywords = Lists.newArrayList();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(KeywordInterface kw) {
|
public boolean visit(KeywordInterface kw) {
|
||||||
keywords.add(kw);
|
keywords.add(kw);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<KeywordInterface> getKeywords() {
|
public List<KeywordInterface> getKeywords() {
|
||||||
@@ -5645,7 +5703,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean withFlash(Player p) {
|
public boolean withFlash(Player p) {
|
||||||
if (hasKeyword("Flash")) {
|
if (hasKeyword(Keyword.FLASH)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (withFlash.containsValue(p)) {
|
if (withFlash.containsValue(p)) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import com.google.common.collect.Sets;
|
|||||||
import com.google.common.collect.Table;
|
import com.google.common.collect.Table;
|
||||||
|
|
||||||
import forge.game.GameEntity;
|
import forge.game.GameEntity;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ public class CardDamageMap extends ForwardingTable<Card, GameEntity, Integer> {
|
|||||||
|
|
||||||
sourceLKI.getGame().getTriggerHandler().runTrigger(TriggerType.DamageDealtOnce, runParams, false);
|
sourceLKI.getGame().getTriggerHandler().runTrigger(TriggerType.DamageDealtOnce, runParams, false);
|
||||||
|
|
||||||
if (sourceLKI.hasKeyword("Lifelink")) {
|
if (sourceLKI.hasKeyword(Keyword.LIFELINK)) {
|
||||||
sourceLKI.getController().gainLife(sum, sourceLKI, sa);
|
sourceLKI.getController().gainLife(sum, sourceLKI, sa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1196,7 +1196,7 @@ public class CardFactoryUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sq[0].contains("BushidoPoint")) {
|
if (sq[0].contains("BushidoPoint")) {
|
||||||
return doXMath(c.getKeywordMagnitude("Bushido"), m, c);
|
return doXMath(c.getKeywordMagnitude(Keyword.BUSHIDO), m, c);
|
||||||
}
|
}
|
||||||
if (sq[0].contains("TimesKicked")) {
|
if (sq[0].contains("TimesKicked")) {
|
||||||
return doXMath(c.getKickerMagnitude(), m, c);
|
return doXMath(c.getKickerMagnitude(), m, c);
|
||||||
@@ -4036,7 +4036,7 @@ public class CardFactoryUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getHostCard().isInstant() || this.getHostCard().hasKeyword("Flash")) {
|
if (this.getHostCard().isInstant() || this.getHostCard().hasKeyword(Keyword.FLASH)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import com.google.common.base.Predicates;
|
|||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.util.collect.FCollectionView;
|
import forge.util.collect.FCollectionView;
|
||||||
@@ -250,6 +251,13 @@ public class CardLists {
|
|||||||
}
|
}
|
||||||
return nKeyword;
|
return nKeyword;
|
||||||
}
|
}
|
||||||
|
public static int getAmountOfKeyword(final Iterable<Card> cardList, final Keyword keyword) {
|
||||||
|
int nKeyword = 0;
|
||||||
|
for (final Card c : cardList) {
|
||||||
|
nKeyword += c.getAmountOfKeyword(keyword);
|
||||||
|
}
|
||||||
|
return nKeyword;
|
||||||
|
}
|
||||||
// cardType is like "Land" or "Goblin", returns a new CardCollection that is a
|
// cardType is like "Land" or "Goblin", returns a new CardCollection that is a
|
||||||
// subset of current CardList
|
// subset of current CardList
|
||||||
public static CardCollection getNotType(Iterable<Card> cardList, String cardType) {
|
public static CardCollection getNotType(Iterable<Card> cardList, String cardType) {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package forge.game.card;
|
|||||||
|
|
||||||
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 com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import forge.card.*;
|
import forge.card.*;
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
@@ -28,6 +27,7 @@ import forge.game.CardTraitBase;
|
|||||||
import forge.game.ForgeScript;
|
import forge.game.ForgeScript;
|
||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
import forge.game.card.CardView.CardStateView;
|
import forge.game.card.CardView.CardStateView;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.keyword.KeywordCollection;
|
import forge.game.keyword.KeywordCollection;
|
||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -60,7 +60,7 @@ public class CardState extends GameObject {
|
|||||||
private String imageKey = "";
|
private String imageKey = "";
|
||||||
private Map<String, String> sVars = Maps.newTreeMap();
|
private Map<String, String> sVars = Maps.newTreeMap();
|
||||||
|
|
||||||
private List<KeywordInterface> cachedKeywords = Lists.newArrayList();
|
private KeywordCollection cachedKeywords = new KeywordCollection();
|
||||||
|
|
||||||
private CardRarity rarity = CardRarity.Unknown;
|
private CardRarity rarity = CardRarity.Unknown;
|
||||||
private String setCode = CardEdition.UNKNOWN.getCode();
|
private String setCode = CardEdition.UNKNOWN.getCode();
|
||||||
@@ -167,12 +167,19 @@ public class CardState extends GameObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final Collection<KeywordInterface> getCachedKeywords() {
|
public final Collection<KeywordInterface> getCachedKeywords() {
|
||||||
return cachedKeywords;
|
return cachedKeywords.getValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setCachedKeywords(final Collection<KeywordInterface> col) {
|
public final Collection<KeywordInterface> getCachedKeyword(final Keyword keyword) {
|
||||||
cachedKeywords.clear();
|
return cachedKeywords.getValues(keyword);
|
||||||
cachedKeywords.addAll(col);
|
}
|
||||||
|
|
||||||
|
public final void setCachedKeywords(final KeywordCollection col) {
|
||||||
|
cachedKeywords = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean hasKeyword(Keyword key) {
|
||||||
|
return cachedKeywords.contains(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Collection<KeywordInterface> getIntrinsicKeywords() {
|
public final Collection<KeywordInterface> getIntrinsicKeywords() {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import forge.game.card.Card;
|
|||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
import forge.game.card.CardDamageMap;
|
import forge.game.card.CardDamageMap;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbilityStackInstance;
|
import forge.game.spellability.SpellAbilityStackInstance;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
@@ -692,7 +693,7 @@ public class Combat {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean trampler = attacker.hasKeyword("Trample");
|
boolean trampler = attacker.hasKeyword(Keyword.TRAMPLE);
|
||||||
orderedBlockers = blockersOrderedForDamageAssignment.get(attacker);
|
orderedBlockers = blockersOrderedForDamageAssignment.get(attacker);
|
||||||
assignedDamage = true;
|
assignedDamage = true;
|
||||||
// If the Attacker is unblocked, or it's a trampler and has 0 blockers, deal damage to defender
|
// If the Attacker is unblocked, or it's a trampler and has 0 blockers, deal damage to defender
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import forge.game.GameEntity;
|
|||||||
import forge.game.GlobalRuleChange;
|
import forge.game.GlobalRuleChange;
|
||||||
import forge.game.card.*;
|
import forge.game.card.*;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -985,17 +986,17 @@ public class CombatUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// rare case:
|
// rare case:
|
||||||
if (blocker.hasKeyword("Shadow")
|
if (blocker.hasKeyword(Keyword.SHADOW)
|
||||||
&& blocker.hasKeyword("CARDNAME can block creatures with shadow as though they didn't have shadow.")) {
|
&& blocker.hasKeyword("CARDNAME can block creatures with shadow as though they didn't have shadow.")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attacker.hasKeyword("Shadow") && !blocker.hasKeyword("Shadow")
|
if (attacker.hasKeyword(Keyword.SHADOW) && !blocker.hasKeyword(Keyword.SHADOW)
|
||||||
&& !blocker.hasKeyword("CARDNAME can block creatures with shadow as though they didn't have shadow.")) {
|
&& !blocker.hasKeyword("CARDNAME can block creatures with shadow as though they didn't have shadow.")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!attacker.hasKeyword("Shadow") && blocker.hasKeyword("Shadow")) {
|
if (!attacker.hasKeyword(Keyword.SHADOW) && blocker.hasKeyword(Keyword.SHADOW)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1034,11 +1035,11 @@ public class CombatUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blocker.hasKeyword("CARDNAME can block only creatures with flying.") && !attacker.hasKeyword("Flying")) {
|
if (blocker.hasKeyword("CARDNAME can block only creatures with flying.") && !attacker.hasKeyword(Keyword.FLYING)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attacker.hasKeyword("Flying") && !blocker.hasKeyword("Flying") && !blocker.hasKeyword("Reach")) {
|
if (attacker.hasKeyword(Keyword.FLYING) && !blocker.hasKeyword(Keyword.FLYING) && !blocker.hasKeyword(Keyword.REACH)) {
|
||||||
boolean stillblock = false;
|
boolean stillblock = false;
|
||||||
for (KeywordInterface inst : blocker.getKeywords()) {
|
for (KeywordInterface inst : blocker.getKeywords()) {
|
||||||
String k = inst.getOriginal();
|
String k = inst.getOriginal();
|
||||||
@@ -1055,15 +1056,16 @@ public class CombatUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attacker.hasKeyword("Horsemanship") && !blocker.hasKeyword("Horsemanship")) {
|
if (attacker.hasKeyword(Keyword.HORSEMANSHIP) && !blocker.hasKeyword(Keyword.HORSEMANSHIP)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attacker.hasKeyword("Fear") && !blocker.isArtifact() && !blocker.isBlack()) {
|
// color is hardcoded there
|
||||||
|
if (attacker.hasKeyword(Keyword.FEAR) && !blocker.isArtifact() && !blocker.isBlack()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attacker.hasKeyword("Intimidate") && !blocker.isArtifact() && !blocker.sharesColorWith(attacker)) {
|
if (attacker.hasKeyword(Keyword.INTIMIDATE) && !blocker.isArtifact() && !blocker.sharesColorWith(attacker)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import forge.game.Game;
|
|||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.card.*;
|
import forge.game.card.*;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.mana.ManaCostBeingPaid;
|
import forge.game.mana.ManaCostBeingPaid;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -210,7 +211,7 @@ public class CostAdjustment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sa.isSpell()) {
|
if (sa.isSpell()) {
|
||||||
if (sa.getHostCard().hasKeyword("Delve")) {
|
if (sa.getHostCard().hasKeyword(Keyword.DELVE)) {
|
||||||
sa.getHostCard().clearDelved();
|
sa.getHostCard().clearDelved();
|
||||||
|
|
||||||
final CardCollection delved = new CardCollection();
|
final CardCollection delved = new CardCollection();
|
||||||
@@ -235,10 +236,10 @@ public class CostAdjustment {
|
|||||||
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sa.getHostCard().hasKeyword("Convoke")) {
|
if (sa.getHostCard().hasKeyword(Keyword.CONVOKE)) {
|
||||||
adjustCostByConvokeOrImprovise(cost, sa, false, test);
|
adjustCostByConvokeOrImprovise(cost, sa, false, test);
|
||||||
}
|
}
|
||||||
if (sa.getHostCard().hasKeyword("Improvise")) {
|
if (sa.getHostCard().hasKeyword(Keyword.IMPROVISE)) {
|
||||||
adjustCostByConvokeOrImprovise(cost, sa, true, test);
|
adjustCostByConvokeOrImprovise(cost, sa, true, test);
|
||||||
}
|
}
|
||||||
} // isSpell
|
} // isSpell
|
||||||
|
|||||||
@@ -143,6 +143,10 @@ public class KeywordCollection implements Iterable<String>, Serializable {
|
|||||||
return map.values();
|
return map.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<KeywordInterface> getValues(final Keyword keyword) {
|
||||||
|
return map.get(keyword);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<String> iterator() {
|
public Iterator<String> iterator() {
|
||||||
return new Iterator<String>() {
|
return new Iterator<String>() {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import forge.game.ability.effects.DetachedCardEffect;
|
|||||||
import forge.game.card.*;
|
import forge.game.card.*;
|
||||||
import forge.game.card.CardPredicates.Presets;
|
import forge.game.card.CardPredicates.Presets;
|
||||||
import forge.game.event.*;
|
import forge.game.event.*;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.keyword.KeywordCollection;
|
import forge.game.keyword.KeywordCollection;
|
||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.keyword.KeywordCollection.KeywordCollectionView;
|
import forge.game.keyword.KeywordCollection.KeywordCollectionView;
|
||||||
@@ -1070,6 +1071,11 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return keywords.contains(keyword);
|
return keywords.contains(keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean hasKeyword(final Keyword keyword) {
|
||||||
|
return keywords.contains(keyword);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateKeywords() {
|
private void updateKeywords() {
|
||||||
keywords.clear();
|
keywords.clear();
|
||||||
|
|
||||||
@@ -2773,4 +2779,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|
|
||||||
this.updateZoneForView(com);
|
this.updateZoneForView(com);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final int countExaltedBonus() {
|
||||||
|
return CardLists.getAmountOfKeyword(this.getCardsIn(ZoneType.Battlefield), Keyword.EXALTED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public class ReplacementHandler {
|
|||||||
// Round up Static replacement effects
|
// Round up Static replacement effects
|
||||||
game.forEachCardInGame(new Visitor<Card>() {
|
game.forEachCardInGame(new Visitor<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(Card crd) {
|
public boolean visit(Card crd) {
|
||||||
for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) {
|
for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) {
|
||||||
|
|
||||||
// Use "CheckLKIZone" parameter to test for effects that care abut where the card was last (e.g. Kalitas, Traitor of Ghet
|
// Use "CheckLKIZone" parameter to test for effects that care abut where the card was last (e.g. Kalitas, Traitor of Ghet
|
||||||
@@ -111,6 +111,7 @@ public class ReplacementHandler {
|
|||||||
possibleReplacers.add(replacementEffect);
|
possibleReplacers.add(replacementEffect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -307,7 +308,7 @@ public class ReplacementHandler {
|
|||||||
public void cleanUpTemporaryReplacements() {
|
public void cleanUpTemporaryReplacements() {
|
||||||
game.forEachCardInGame(new Visitor<Card>() {
|
game.forEachCardInGame(new Visitor<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(Card c) {
|
public boolean visit(Card c) {
|
||||||
for (int i = 0; i < c.getReplacementEffects().size(); i++) {
|
for (int i = 0; i < c.getReplacementEffects().size(); i++) {
|
||||||
ReplacementEffect rep = c.getReplacementEffects().get(i);
|
ReplacementEffect rep = c.getReplacementEffects().get(i);
|
||||||
if (rep.isTemporary()) {
|
if (rep.isTemporary()) {
|
||||||
@@ -315,14 +316,16 @@ public class ReplacementHandler {
|
|||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
game.forEachCardInGame(new Visitor<Card>() {
|
game.forEachCardInGame(new Visitor<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(Card c) {
|
public boolean visit(Card c) {
|
||||||
for (int i = 0; i < c.getReplacementEffects().size(); i++) {
|
for (int i = 0; i < c.getReplacementEffects().size(); i++) {
|
||||||
c.getReplacementEffects().get(i).setTemporarilySuppressed(false);
|
c.getReplacementEffects().get(i).setTemporarilySuppressed(false);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class TriggerHandler {
|
|||||||
public final void cleanUpTemporaryTriggers() {
|
public final void cleanUpTemporaryTriggers() {
|
||||||
game.forEachCardInGame(new Visitor<Card>() {
|
game.forEachCardInGame(new Visitor<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(Card c) {
|
public boolean visit(Card c) {
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (int i = 0; i < c.getTriggers().size(); i++) {
|
for (int i = 0; i < c.getTriggers().size(); i++) {
|
||||||
Trigger trigger = c.getTriggers().get(i);
|
Trigger trigger = c.getTriggers().get(i);
|
||||||
@@ -74,11 +74,12 @@ public class TriggerHandler {
|
|||||||
if (changed) {
|
if (changed) {
|
||||||
c.updateStateForView();
|
c.updateStateForView();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
game.forEachCardInGame(new Visitor<Card>() {
|
game.forEachCardInGame(new Visitor<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(Card c) {
|
public boolean visit(Card c) {
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (int i = 0; i < c.getTriggers().size(); i++) {
|
for (int i = 0; i < c.getTriggers().size(); i++) {
|
||||||
if (c.getTriggers().get(i).isSuppressed()) {
|
if (c.getTriggers().get(i).isSuppressed()) {
|
||||||
@@ -89,6 +90,7 @@ public class TriggerHandler {
|
|||||||
if (changed) {
|
if (changed) {
|
||||||
c.updateStateForView();
|
c.updateStateForView();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -226,12 +228,13 @@ public class TriggerHandler {
|
|||||||
activeTriggers.clear();
|
activeTriggers.clear();
|
||||||
game.forEachCardInGame(new Visitor<Card>() {
|
game.forEachCardInGame(new Visitor<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(Card c) {
|
public boolean visit(Card c) {
|
||||||
for (final Trigger t : c.getTriggers()) {
|
for (final Trigger t : c.getTriggers()) {
|
||||||
if (isTriggerActive(t)) {
|
if (isTriggerActive(t)) {
|
||||||
activeTriggers.add(t);
|
activeTriggers.add(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import forge.game.event.GameEventSpellAbilityCast;
|
|||||||
import forge.game.event.GameEventSpellRemovedFromStack;
|
import forge.game.event.GameEventSpellRemovedFromStack;
|
||||||
import forge.game.event.GameEventSpellResolved;
|
import forge.game.event.GameEventSpellResolved;
|
||||||
import forge.game.event.GameEventZone;
|
import forge.game.event.GameEventZone;
|
||||||
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.player.PlayerController.ManaPaymentPurpose;
|
import forge.game.player.PlayerController.ManaPaymentPurpose;
|
||||||
import forge.game.replacement.ReplacementEffect;
|
import forge.game.replacement.ReplacementEffect;
|
||||||
@@ -119,7 +120,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
|
|
||||||
public final boolean isSplitSecondOnStack() {
|
public final boolean isSplitSecondOnStack() {
|
||||||
for(SpellAbilityStackInstance si : stack) {
|
for(SpellAbilityStackInstance si : stack) {
|
||||||
if (si.isSpell() && si.getSourceCard().hasKeyword("Split second")) {
|
if (si.isSpell() && si.getSourceCard().hasKeyword(Keyword.SPLIT_SECOND)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user