Merge branch 'cleanup' into 'master'

Cleanup predictDamageTo

See merge request core-developers/forge!5413
This commit is contained in:
Michael Kamensky
2021-09-22 17:46:55 +00:00
14 changed files with 121 additions and 187 deletions

View File

@@ -78,7 +78,6 @@ public class AiProfileUtil {
List<String> lines = FileUtil.readFile(buildFileName(profileName));
for (String line : lines) {
if (line.startsWith("#") || (line.length() == 0)) {
continue;
}

View File

@@ -576,7 +576,7 @@ public class ComputerUtil {
int count = 0;
while (count < amount) {
Card prefCard = ComputerUtil.getCardPreference(ai, source, "SacCost", typeList);
Card prefCard = getCardPreference(ai, source, "SacCost", typeList);
if (prefCard == null) {
prefCard = ComputerUtilCard.getWorstAI(typeList);
}
@@ -1051,7 +1051,7 @@ public class ComputerUtil {
}
if (card.isCreature() && !cardState.hasKeyword(Keyword.DEFENDER)
&& (cardState.hasKeyword(Keyword.HASTE) || ComputerUtil.hasACardGivingHaste(ai, true) || sa.isDash())) {
&& (cardState.hasKeyword(Keyword.HASTE) || hasACardGivingHaste(ai, true) || sa.isDash())) {
return true;
}
@@ -1556,7 +1556,7 @@ public class ComputerUtil {
sub = sub.getSubAbility();
}
if (sa == null || (sa != spell && sa != sub)) {
Iterables.addAll(objects, ComputerUtil.predictThreatenedObjects(ai, sa, spell));
Iterables.addAll(objects, predictThreatenedObjects(ai, sa, spell));
}
if (top) {
break; // only evaluate top-stack
@@ -1892,7 +1892,7 @@ public class ComputerUtil {
}
}
Iterables.addAll(threatened, ComputerUtil.predictThreatenedObjects(aiPlayer, saviour, topStack.getSubAbility()));
Iterables.addAll(threatened, predictThreatenedObjects(aiPlayer, saviour, topStack.getSubAbility()));
return threatened;
}
@@ -1927,7 +1927,7 @@ public class ComputerUtil {
}
}
}
willDieFromSpell = !noStackCheck && ComputerUtil.predictThreatenedObjects(creature.getController(), excludeSa).contains(creature);
willDieFromSpell = !noStackCheck && predictThreatenedObjects(creature.getController(), excludeSa).contains(creature);
return willDieInCombat || willDieFromSpell;
}
@@ -1950,7 +1950,7 @@ public class ComputerUtil {
List<Card> willBeKilled = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.isCreature() && ComputerUtil.predictCreatureWillDieThisTurn(ai, card, excludeSa);
return card.isCreature() && predictCreatureWillDieThisTurn(ai, card, excludeSa);
}
});
list.removeAll(willBeKilled);

View File

@@ -375,13 +375,13 @@ public class ComputerUtilCard {
public static Card getBestAI(final Iterable<Card> list) {
// Get Best will filter by appropriate getBest list if ALL of the list is of that type
if (Iterables.all(list, CardPredicates.Presets.CREATURES)) {
return ComputerUtilCard.getBestCreatureAI(list);
return getBestCreatureAI(list);
}
if (Iterables.all(list, CardPredicates.Presets.LANDS)) {
return getBestLandAI(list);
}
// TODO - Once we get an EvaluatePermanent this should call getBestPermanent()
return ComputerUtilCard.getMostExpensivePermanentAI(list);
return getMostExpensivePermanentAI(list);
}
/**
@@ -422,7 +422,7 @@ public class ComputerUtilCard {
int biggestvalue = -1;
for (Card card : CardLists.filter(list, CardPredicates.Presets.CREATURES)) {
int newvalue = ComputerUtilCard.evaluateCreature(card);
int newvalue = evaluateCreature(card);
newvalue += card.isToken() ? tokenBonus : 0; // raise the value of tokens
if (biggestvalue < newvalue) {
@@ -453,7 +453,7 @@ public class ComputerUtilCard {
* @return a {@link forge.game.card.Card} object.
*/
public static Card getWorstAI(final Iterable<Card> list) {
return ComputerUtilCard.getWorstPermanentAI(list, false, false, false, false);
return getWorstPermanentAI(list, false, false, false, false);
}
/**
@@ -956,43 +956,43 @@ public class ComputerUtilCard {
final String logic = sa.getParam("AILogic");
if (logic.equals("MostProminentInHumanDeck")) {
chosen.add(ComputerUtilCard.getMostProminentColor(CardLists.filterControlledBy(game.getCardsInGame(), opp), colorChoices));
chosen.add(getMostProminentColor(CardLists.filterControlledBy(game.getCardsInGame(), opp), colorChoices));
}
else if (logic.equals("MostProminentInComputerDeck")) {
chosen.add(ComputerUtilCard.getMostProminentColor(CardLists.filterControlledBy(game.getCardsInGame(), ai), colorChoices));
chosen.add(getMostProminentColor(CardLists.filterControlledBy(game.getCardsInGame(), ai), colorChoices));
}
else if (logic.equals("MostProminentDualInComputerDeck")) {
List<String> prominence = ComputerUtilCard.getColorByProminence(CardLists.filterControlledBy(game.getCardsInGame(), ai));
List<String> prominence = getColorByProminence(CardLists.filterControlledBy(game.getCardsInGame(), ai));
chosen.add(prominence.get(0));
chosen.add(prominence.get(1));
}
else if (logic.equals("MostProminentInGame")) {
chosen.add(ComputerUtilCard.getMostProminentColor(game.getCardsInGame(), colorChoices));
chosen.add(getMostProminentColor(game.getCardsInGame(), colorChoices));
}
else if (logic.equals("MostProminentHumanCreatures")) {
CardCollectionView list = opp.getCreaturesInPlay();
if (list.isEmpty()) {
list = CardLists.filter(CardLists.filterControlledBy(game.getCardsInGame(), opp), CardPredicates.Presets.CREATURES);
}
chosen.add(ComputerUtilCard.getMostProminentColor(list, colorChoices));
chosen.add(getMostProminentColor(list, colorChoices));
}
else if (logic.equals("MostProminentComputerControls")) {
chosen.add(ComputerUtilCard.getMostProminentColor(ai.getCardsIn(ZoneType.Battlefield), colorChoices));
chosen.add(getMostProminentColor(ai.getCardsIn(ZoneType.Battlefield), colorChoices));
}
else if (logic.equals("MostProminentHumanControls")) {
chosen.add(ComputerUtilCard.getMostProminentColor(opp.getCardsIn(ZoneType.Battlefield), colorChoices));
chosen.add(getMostProminentColor(opp.getCardsIn(ZoneType.Battlefield), colorChoices));
}
else if (logic.equals("MostProminentPermanent")) {
chosen.add(ComputerUtilCard.getMostProminentColor(game.getCardsIn(ZoneType.Battlefield), colorChoices));
chosen.add(getMostProminentColor(game.getCardsIn(ZoneType.Battlefield), colorChoices));
}
else if (logic.equals("MostProminentAttackers") && game.getPhaseHandler().inCombat()) {
chosen.add(ComputerUtilCard.getMostProminentColor(game.getCombat().getAttackers(), colorChoices));
chosen.add(getMostProminentColor(game.getCombat().getAttackers(), colorChoices));
}
else if (logic.equals("MostProminentInActivePlayerHand")) {
chosen.add(ComputerUtilCard.getMostProminentColor(game.getPhaseHandler().getPlayerTurn().getCardsIn(ZoneType.Hand), colorChoices));
chosen.add(getMostProminentColor(game.getPhaseHandler().getPlayerTurn().getCardsIn(ZoneType.Hand), colorChoices));
}
else if (logic.equals("MostProminentInComputerDeckButGreen")) {
List<String> prominence = ComputerUtilCard.getColorByProminence(CardLists.filterControlledBy(game.getCardsInGame(), ai));
List<String> prominence = getColorByProminence(CardLists.filterControlledBy(game.getCardsInGame(), ai));
if (prominence.get(0).equals(MagicColor.Constant.GREEN)) {
chosen.add(prominence.get(1));
} else {
@@ -1097,7 +1097,7 @@ public class ComputerUtilCard {
for (Card attacker : currCombat.getAttackersBlockedBy(c)) {
if (attacker.getShieldCount() == 0 && ComputerUtilCombat.attackerWouldBeDestroyed(ai, attacker, currCombat)) {
CardCollection blockers = currCombat.getBlockers(attacker);
ComputerUtilCard.sortByEvaluateCreature(blockers);
sortByEvaluateCreature(blockers);
Combat combat = new Combat(ai);
combat.addAttacker(attacker, opp);
for (Card blocker : blockers) {
@@ -1188,7 +1188,7 @@ public class ComputerUtilCard {
float threat = 0;
if (c.isCreature()) {
// the base value for evaluate creature is 100
threat += (-1 + 1.0f * ComputerUtilCard.evaluateCreature(c) / 100) / costRemoval;
threat += (-1 + 1.0f * evaluateCreature(c) / 100) / costRemoval;
if (ai.getLife() > 0 && ComputerUtilCombat.canAttackNextTurn(c)) {
Combat combat = game.getCombat();
threat += 1.0f * ComputerUtilCombat.damageIfUnblocked(c, opp, combat, true) / ai.getLife();
@@ -1335,7 +1335,7 @@ public class ComputerUtilCard {
&& phase.isPlayerTurn(ai)
&& SpellAbilityAi.isSorcerySpeed(sa) || main1Preferred
&& power > 0
&& ComputerUtilCard.doesCreatureAttackAI(ai, c)) {
&& doesCreatureAttackAI(ai, c)) {
return true;
}
@@ -1360,7 +1360,7 @@ public class ComputerUtilCard {
//create and buff attackers
if (phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS) && phase.isPlayerTurn(ai) && opp.getLife() > 0) {
//1. become attacker for whatever reason
if (!ComputerUtilCard.doesCreatureAttackAI(ai, c) && ComputerUtilCard.doesSpecifiedCreatureAttackAI(ai, pumped)) {
if (!doesCreatureAttackAI(ai, c) && doesSpecifiedCreatureAttackAI(ai, pumped)) {
float threat = 1.0f * ComputerUtilCombat.damageIfUnblocked(pumped, opp, combat, true) / opp.getLife();
if (CardLists.filter(oppCreatures, CardPredicates.possibleBlockers(pumped)).isEmpty()) {
threat *= 2;
@@ -1407,7 +1407,7 @@ public class ComputerUtilCard {
}
}
// combat Haste: only grant it if the creature will attack
if (ComputerUtilCard.doesSpecifiedCreatureAttackAI(ai, pumped)) {
if (doesSpecifiedCreatureAttackAI(ai, pumped)) {
combatChance += 0.5f + (0.5f * ComputerUtilCombat.damageIfUnblocked(pumped, opp, combat, true) / opp.getLife());
}
chance += nonCombatChance + combatChance;
@@ -1416,7 +1416,7 @@ public class ComputerUtilCard {
//3. grant evasive
if (!CardLists.filter(oppCreatures, CardPredicates.possibleBlockers(c)).isEmpty()) {
if (CardLists.filter(oppCreatures, CardPredicates.possibleBlockers(pumped)).isEmpty()
&& ComputerUtilCard.doesSpecifiedCreatureAttackAI(ai, pumped)) {
&& doesSpecifiedCreatureAttackAI(ai, pumped)) {
chance += 0.5f * ComputerUtilCombat.damageIfUnblocked(pumped, opp, combat, true) / opp.getLife();
}
}
@@ -1714,7 +1714,7 @@ public class ComputerUtilCard {
}
final long timestamp2 = c.getGame().getNextTimestamp(); //is this necessary or can the timestamp be re-used?
pumped.addChangedCardKeywordsInternal(toCopy, null, false, false, timestamp2, 0, true);
ComputerUtilCard.applyStaticContPT(ai.getGame(), pumped, new CardCollection(c));
applyStaticContPT(ai.getGame(), pumped, new CardCollection(c));
return pumped;
}
@@ -1794,7 +1794,7 @@ public class ComputerUtilCard {
}
}
if (!threatenedTargets.isEmpty()) {
ComputerUtilCard.sortByEvaluateCreature(threatenedTargets);
sortByEvaluateCreature(threatenedTargets);
for (Card c : threatenedTargets) {
if (sa.canAddMoreTarget()) {
sa.getTargets().add(c);
@@ -1953,7 +1953,7 @@ public class ComputerUtilCard {
// A special case which checks that this creature will attack if it's the AI's turn
if (needsToPlay.equalsIgnoreCase("WillAttack")) {
if (sa != null && game.getPhaseHandler().isPlayerTurn(sa.getActivatingPlayer())) {
return ComputerUtilCard.doesSpecifiedCreatureAttackAI(sa.getActivatingPlayer(), card) ?
return doesSpecifiedCreatureAttackAI(sa.getActivatingPlayer(), card) ?
AiPlayDecision.WillPlay : AiPlayDecision.BadEtbEffects;
} else {
return AiPlayDecision.WillPlay; // not our turn, skip this check for the possible Flash use etc.

View File

@@ -86,7 +86,7 @@ public class ComputerUtilCombat {
final Iterable<GameEntity> defenders = CombatUtil.getAllPossibleDefenders(attacker.getController());
return Iterables.any(defenders, new Predicate<GameEntity>() {
@Override public boolean apply(final GameEntity input) {
return ComputerUtilCombat.canAttackNextTurn(attacker, input);
return canAttackNextTurn(attacker, input);
}
});
}
@@ -162,7 +162,7 @@ public class ComputerUtilCombat {
}
});
return ComputerUtilCombat.totalDamageOfBlockers(attacker, list);
return totalDamageOfBlockers(attacker, list);
}
@@ -212,9 +212,9 @@ public class ComputerUtilCombat {
return 0;
}
damage += ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, null, combat, withoutAbilities);
damage += predictPowerBonusOfAttacker(attacker, null, combat, withoutAbilities);
if (!attacker.hasKeyword(Keyword.INFECT)) {
sum = ComputerUtilCombat.predictDamageTo(attacked, damage, attacker, true);
sum = predictDamageTo(attacked, damage, attacker, true);
if (attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
sum *= 2;
}
@@ -237,9 +237,9 @@ public class ComputerUtilCombat {
public static int poisonIfUnblocked(final Card attacker, final Player attacked) {
int damage = attacker.getNetCombatDamage();
int poison = 0;
damage += ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, null, null, false);
damage += predictPowerBonusOfAttacker(attacker, null, null, false);
if (attacker.hasKeyword(Keyword.INFECT)) {
int pd = ComputerUtilCombat.predictDamageTo(attacked, damage, attacker, true);
int pd = predictDamageTo(attacked, damage, attacker, true);
poison += pd;
if (attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
poison += pd;
@@ -265,7 +265,7 @@ public class ComputerUtilCombat {
public static int sumDamageIfUnblocked(final Iterable<Card> attackers, final Player attacked) {
int sum = 0;
for (final Card attacker : attackers) {
sum += ComputerUtilCombat.damageIfUnblocked(attacker, attacked, null, false);
sum += damageIfUnblocked(attacker, attacked, null, false);
}
return sum;
}
@@ -284,7 +284,7 @@ public class ComputerUtilCombat {
public static int sumPoisonIfUnblocked(final List<Card> attackers, final Player attacked) {
int sum = 0;
for (final Card attacker : attackers) {
sum += ComputerUtilCombat.poisonIfUnblocked(attacker, attacked);
sum += poisonIfUnblocked(attacker, attacked);
}
return sum;
}
@@ -313,14 +313,14 @@ public class ComputerUtilCombat {
+ "as though it weren't blocked.")) {
unblocked.add(attacker);
} else if (attacker.hasKeyword(Keyword.TRAMPLE)
&& (ComputerUtilCombat.getAttack(attacker) > ComputerUtilCombat.totalShieldDamage(attacker, blockers))) {
&& (getAttack(attacker) > totalShieldDamage(attacker, blockers))) {
if (!attacker.hasKeyword(Keyword.INFECT)) {
damage += ComputerUtilCombat.getAttack(attacker) - ComputerUtilCombat.totalShieldDamage(attacker, blockers);
damage += getAttack(attacker) - totalShieldDamage(attacker, blockers);
}
}
}
damage += ComputerUtilCombat.sumDamageIfUnblocked(unblocked, ai);
damage += sumDamageIfUnblocked(unblocked, ai);
if (!ai.canLoseLife()) {
damage = 0;
@@ -358,9 +358,9 @@ public class ComputerUtilCombat {
+ " as though it weren't blocked.")) {
unblocked.add(attacker);
} else if (attacker.hasKeyword(Keyword.TRAMPLE)
&& (ComputerUtilCombat.getAttack(attacker) > ComputerUtilCombat.totalShieldDamage(attacker, blockers))) {
&& (getAttack(attacker) > totalShieldDamage(attacker, blockers))) {
if (attacker.hasKeyword(Keyword.INFECT)) {
poison += ComputerUtilCombat.getAttack(attacker) - ComputerUtilCombat.totalShieldDamage(attacker, blockers);
poison += getAttack(attacker) - totalShieldDamage(attacker, blockers);
}
if (attacker.hasKeyword(Keyword.POISONOUS)) {
poison += attacker.getKeywordMagnitude(Keyword.POISONOUS);
@@ -368,7 +368,7 @@ public class ComputerUtilCombat {
}
}
poison += ComputerUtilCombat.sumPoisonIfUnblocked(unblocked, ai);
poison += sumPoisonIfUnblocked(unblocked, ai);
return ai.getPoisonCounters() + poison;
}
@@ -456,12 +456,12 @@ public class ComputerUtilCombat {
maxTreshold--;
}
if (ComputerUtilCombat.lifeThatWouldRemain(ai, combat) - payment < Math.min(threshold, ai.getLife())
if (lifeThatWouldRemain(ai, combat) - payment < Math.min(threshold, ai.getLife())
&& !ai.cantLoseForZeroOrLessLife()) {
return true;
}
return (ComputerUtilCombat.resultingPoison(ai, combat) > Math.max(7, ai.getPoisonCounters()));
return resultingPoison(ai, combat) > Math.max(7, ai.getPoisonCounters());
}
// Checks if the life of the attacked Player would be reduced
@@ -475,7 +475,7 @@ public class ComputerUtilCombat {
* @return a boolean.
*/
public static boolean wouldLoseLife(final Player ai, final Combat combat) {
return (ComputerUtilCombat.lifeThatWouldRemain(ai, combat) < ai.getLife());
return lifeThatWouldRemain(ai, combat) < ai.getLife();
}
// Checks if the life of the attacked Player/Planeswalker is in danger
@@ -497,7 +497,7 @@ public class ComputerUtilCombat {
return false;
}
final List<Card> threateningCommanders = ComputerUtilCombat.getLifeThreateningCommanders(ai, combat);
final List<Card> threateningCommanders = getLifeThreateningCommanders(ai, combat);
// check for creatures that must be blocked
final List<Card> attackers = combat.getAttackersOf(ai);
@@ -515,11 +515,11 @@ public class ComputerUtilCombat {
}
}
if (ComputerUtilCombat.lifeThatWouldRemain(ai, combat) - payment < 1 && !ai.cantLoseForZeroOrLessLife()) {
if (lifeThatWouldRemain(ai, combat) - payment < 1 && !ai.cantLoseForZeroOrLessLife()) {
return true;
}
return (ComputerUtilCombat.resultingPoison(ai, combat) > 9);
return resultingPoison(ai, combat) > 9;
}
@@ -543,7 +543,7 @@ public class ComputerUtilCombat {
}
for (final Card defender : defenders) {
damage += ComputerUtilCombat.dealsDamageAsBlocker(attacker, defender);
damage += dealsDamageAsBlocker(attacker, defender);
}
return damage;
}
@@ -561,7 +561,7 @@ public class ComputerUtilCombat {
}
for (final Card defender : defenders) {
damage += ComputerUtilCombat.predictDamageByBlockerWithoutDoubleStrike(attacker, defender);
damage += predictDamageByBlockerWithoutDoubleStrike(attacker, defender);
}
return damage;
}
@@ -620,9 +620,9 @@ public class ComputerUtilCombat {
int defenderDamage;
if (defender.toughnessAssignsDamage()) {
defenderDamage = defender.getNetToughness() + ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, defender, true);
defenderDamage = defender.getNetToughness() + predictToughnessBonusOfBlocker(attacker, defender, true);
} else {
defenderDamage = defender.getNetPower() + ComputerUtilCombat.predictPowerBonusOfBlocker(attacker, defender, true);
defenderDamage = defender.getNetPower() + predictPowerBonusOfBlocker(attacker, defender, true);
}
// consider static Damage Prevention
@@ -646,7 +646,7 @@ public class ComputerUtilCombat {
int defenderDefense = 0;
for (final Card defender : defenders) {
defenderDefense += ComputerUtilCombat.shieldDamage(attacker, defender);
defenderDefense += shieldDamage(attacker, defender);
}
return defenderDefense;
@@ -666,7 +666,7 @@ public class ComputerUtilCombat {
* @return a int.
*/
public static int shieldDamage(final Card attacker, final Card blocker) {
if (ComputerUtilCombat.canDestroyBlockerBeforeFirstStrike(blocker, attacker, false)) {
if (canDestroyBlockerBeforeFirstStrike(blocker, attacker, false)) {
return 0;
}
@@ -705,10 +705,10 @@ public class ComputerUtilCombat {
*/
public static boolean combatantWouldBeDestroyed(Player ai, final Card combatant, Combat combat) {
if (combat.isAttacking(combatant)) {
return ComputerUtilCombat.attackerWouldBeDestroyed(ai, combatant, combat);
return attackerWouldBeDestroyed(ai, combatant, combat);
}
if (combat.isBlocking(combatant)) {
return ComputerUtilCombat.blockerWouldBeDestroyed(ai, combatant, combat);
return blockerWouldBeDestroyed(ai, combatant, combat);
}
return false;
}
@@ -729,7 +729,7 @@ public class ComputerUtilCombat {
int firstStrikeBlockerDmg = 0;
for (final Card defender : blockers) {
if (ComputerUtilCombat.canDestroyAttacker(ai, attacker, defender, combat, true)
if (canDestroyAttacker(ai, attacker, defender, combat, true)
&& !(defender.hasKeyword(Keyword.WITHER) || defender.hasKeyword(Keyword.INFECT))) {
return true;
}
@@ -740,10 +740,10 @@ public class ComputerUtilCombat {
// Consider first strike and double strike
if (attacker.hasKeyword(Keyword.FIRST_STRIKE) || attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
return firstStrikeBlockerDmg >= ComputerUtilCombat.getDamageToKill(attacker);
return firstStrikeBlockerDmg >= getDamageToKill(attacker);
}
return ComputerUtilCombat.totalDamageOfBlockers(attacker, blockers) >= ComputerUtilCombat.getDamageToKill(attacker);
return totalDamageOfBlockers(attacker, blockers) >= getDamageToKill(attacker);
}
// Will this trigger trigger?
@@ -956,7 +956,7 @@ public class ComputerUtilCombat {
for (final Trigger trigger : theTriggers) {
final Card source = trigger.getHostCard();
if (!ComputerUtilCombat.combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
if (!combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
continue;
}
@@ -1074,7 +1074,7 @@ public class ComputerUtilCombat {
for (final Trigger trigger : theTriggers) {
final Card source = trigger.getHostCard();
if (!ComputerUtilCombat.combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
if (!combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
continue;
}
@@ -1089,7 +1089,7 @@ public class ComputerUtilCombat {
continue;
}
int damage = AbilityUtils.calculateAmount(source, sa.getParam("NumDmg"), sa);
toughness -= predictDamageTo(blocker, damage, 0, source, false);
toughness -= predictDamageTo(blocker, damage, source, false);
} else
// -1/-1 PutCounter triggers
@@ -1216,9 +1216,9 @@ public class ComputerUtilCombat {
// if the defender has first strike and wither the attacker will deal
// less damage than expected
if (null != blocker) {
if (ComputerUtilCombat.dealsFirstStrikeDamage(blocker, withoutAbilities, combat)
if (dealsFirstStrikeDamage(blocker, withoutAbilities, combat)
&& (blocker.hasKeyword(Keyword.WITHER) || blocker.hasKeyword(Keyword.INFECT))
&& !ComputerUtilCombat.dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
&& !dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
&& !attacker.canReceiveCounters(CounterEnumType.M1M1)) {
power -= blocker.getNetCombatDamage();
}
@@ -1250,7 +1250,7 @@ public class ComputerUtilCombat {
for (final Trigger trigger : theTriggers) {
final Card source = trigger.getHostCard();
if (!ComputerUtilCombat.combatTriggerWillTrigger(attacker, blocker, trigger, combat)) {
if (!combatTriggerWillTrigger(attacker, blocker, trigger, combat)) {
continue;
}
@@ -1451,7 +1451,7 @@ public class ComputerUtilCombat {
for (final Trigger trigger : theTriggers) {
final Card source = trigger.getHostCard();
if (!ComputerUtilCombat.combatTriggerWillTrigger(attacker, blocker, trigger, combat)) {
if (!combatTriggerWillTrigger(attacker, blocker, trigger, combat)) {
continue;
}
@@ -1472,7 +1472,7 @@ public class ComputerUtilCombat {
}
int damage = AbilityUtils.calculateAmount(source, sa.getParam("NumDmg"), sa);
toughness -= predictDamageTo(attacker, damage, 0, source, false);
toughness -= predictDamageTo(attacker, damage, source, false);
continue;
} else if (ApiType.Pump.equals(sa.getApi())) {
if (sa.hasParam("Cost")) {
@@ -1600,8 +1600,8 @@ public class ComputerUtilCombat {
}
//Check triggers that deal damage or shrink the attacker
if (ComputerUtilCombat.getDamageToKill(attacker)
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities) <= 0) {
if (getDamageToKill(attacker)
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities) <= 0) {
return true;
}
@@ -1613,7 +1613,7 @@ public class ComputerUtilCombat {
for (Trigger trigger : theTriggers) {
final Card source = trigger.getHostCard();
if (!ComputerUtilCombat.combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
if (!combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
continue;
}
SpellAbility sa = trigger.ensureAbility();
@@ -1735,17 +1735,17 @@ public class ComputerUtilCombat {
int attackerDamage;
if (blocker.toughnessAssignsDamage()) {
defenderDamage = blocker.getNetToughness()
+ ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
} else {
defenderDamage = blocker.getNetPower()
+ ComputerUtilCombat.predictPowerBonusOfBlocker(attacker, blocker, withoutAbilities);
+ predictPowerBonusOfBlocker(attacker, blocker, withoutAbilities);
}
if (attacker.toughnessAssignsDamage()) {
attackerDamage = attacker.getNetToughness()
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
} else {
attackerDamage = attacker.getNetPower()
+ ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
+ predictPowerBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
}
int possibleDefenderPrevention = 0;
@@ -1762,10 +1762,10 @@ public class ComputerUtilCombat {
return false;
}
final int defenderLife = ComputerUtilCombat.getDamageToKill(blocker)
+ ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
final int attackerLife = ComputerUtilCombat.getDamageToKill(attacker)
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
final int defenderLife = getDamageToKill(blocker)
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
final int attackerLife = getDamageToKill(attacker)
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
if (blocker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
if (defenderDamage > 0 && (hasKeyword(blocker, "Deathtouch", withoutAbilities, combat) || attacker.hasSVar("DestroyWhenDamaged"))) {
@@ -1832,7 +1832,7 @@ public class ComputerUtilCombat {
final List<Card> attackers = combat.getAttackersBlockedBy(blocker);
for (Card attacker : attackers) {
if (ComputerUtilCombat.canDestroyBlocker(ai, blocker, attacker, combat, true)
if (canDestroyBlocker(ai, blocker, attacker, combat, true)
&& !(attacker.hasKeyword(Keyword.WITHER) || attacker.hasKeyword(Keyword.INFECT))) {
return true;
}
@@ -1856,7 +1856,7 @@ public class ComputerUtilCombat {
if (flankingMagnitude >= blocker.getNetToughness()) {
return true;
}
if ((flankingMagnitude >= ComputerUtilCombat.getDamageToKill(blocker))
if ((flankingMagnitude >= getDamageToKill(blocker))
&& !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)) {
return true;
}
@@ -1867,8 +1867,8 @@ public class ComputerUtilCombat {
return false;
}
if (ComputerUtilCombat.getDamageToKill(blocker)
+ ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities) <= 0) {
if (getDamageToKill(blocker)
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities) <= 0) {
return true;
}
@@ -1880,7 +1880,7 @@ public class ComputerUtilCombat {
for (Trigger trigger : theTriggers) {
final Card source = trigger.getHostCard();
if (!ComputerUtilCombat.combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
if (!combatTriggerWillTrigger(attacker, blocker, trigger, null)) {
continue;
}
SpellAbility sa = trigger.ensureAbility();
@@ -1956,17 +1956,17 @@ public class ComputerUtilCombat {
int attackerDamage;
if (blocker.toughnessAssignsDamage()) {
defenderDamage = blocker.getNetToughness()
+ ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
} else {
defenderDamage = blocker.getNetPower()
+ ComputerUtilCombat.predictPowerBonusOfBlocker(attacker, blocker, withoutAbilities);
+ predictPowerBonusOfBlocker(attacker, blocker, withoutAbilities);
}
if (attacker.toughnessAssignsDamage()) {
attackerDamage = attacker.getNetToughness()
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
} else {
attackerDamage = attacker.getNetPower()
+ ComputerUtilCombat.predictPowerBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
+ predictPowerBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
}
int possibleDefenderPrevention = 0;
@@ -1991,15 +1991,15 @@ public class ComputerUtilCombat {
if (combat != null) {
for (Card atkr : combat.getAttackersBlockedBy(blocker)) {
if (!atkr.equals(attacker)) {
attackerDamage += predictDamageTo(blocker, atkr.getNetCombatDamage(), 0, atkr, true);
attackerDamage += predictDamageTo(blocker, atkr.getNetCombatDamage(), atkr, true);
}
}
}
final int defenderLife = ComputerUtilCombat.getDamageToKill(blocker)
+ ComputerUtilCombat.predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
final int attackerLife = ComputerUtilCombat.getDamageToKill(attacker)
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
final int defenderLife = getDamageToKill(blocker)
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
final int attackerLife = getDamageToKill(attacker)
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
if (attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
if (attackerDamage > 0 && (hasKeyword(attacker, "Deathtouch", withoutAbilities, combat) || blocker.hasSVar("DestroyWhenDamaged"))) {
@@ -2082,8 +2082,7 @@ public class ComputerUtilCombat {
// trample
if (hasTrample) {
int dmgToKill = ComputerUtilCombat.getEnoughDamageToKill(blocker, dmgCanDeal, attacker, true);
int dmgToKill = getEnoughDamageToKill(blocker, dmgCanDeal, attacker, true);
if (dmgCanDeal < dmgToKill) {
dmgToKill = Math.min(blocker.getLethalDamage(), dmgCanDeal);
@@ -2113,7 +2112,7 @@ public class ComputerUtilCombat {
Card lastBlocker = null;
for (final Card b : block) {
lastBlocker = b;
final int dmgToKill = ComputerUtilCombat.getEnoughDamageToKill(b, dmgCanDeal, attacker, true);
final int dmgToKill = getEnoughDamageToKill(b, dmgCanDeal, attacker, true);
if (dmgToKill <= dmgCanDeal) {
damageMap.put(b, dmgToKill);
dmgCanDeal -= dmgToKill;
@@ -2175,7 +2174,7 @@ public class ComputerUtilCombat {
*/
public static final int getEnoughDamageToKill(final Card c, final int maxDamage, final Card source, final boolean isCombat,
final boolean noPrevention) {
final int killDamage = c.isPlaneswalker() ? c.getCurrentLoyalty() : ComputerUtilCombat.getDamageToKill(c);
final int killDamage = c.isPlaneswalker() ? c.getCurrentLoyalty() : getDamageToKill(c);
if (c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.getShieldCount() > 0) {
if (!(source.hasKeyword(Keyword.WITHER) || source.hasKeyword(Keyword.INFECT))) {
@@ -2241,70 +2240,10 @@ public class ComputerUtilCombat {
* a boolean.
* @return a int.
*/
public final static int predictDamageTo(final Player target, final int damage, final Card source, final boolean isCombat) {
final Game game = target.getGame();
int restDamage = damage;
restDamage = target.staticReplaceDamage(restDamage, source, isCombat);
// Predict replacement effects
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final ReplacementEffect re : ca.getReplacementEffects()) {
if (!re.getMode().equals(ReplacementType.DamageDone) ||
(!re.hasParam("PreventionEffect") && !re.hasParam("Prevent"))) {
continue;
}
// Immortal Coil prevents the damage but has a similar negative effect
if ("Immortal Coil".equals(ca.getName())) {
continue;
}
if (!re.matchesValidParam("ValidSource", source)) {
continue;
}
if (!re.matchesValidParam("ValidTarget", target)) {
continue;
}
if (re.hasParam("IsCombat")) {
if (re.getParam("IsCombat").equals("True") != isCombat) {
continue;
}
}
if (re.hasParam("Prevent")) {
return 0;
} else if (re.getOverridingAbility() != null) {
SpellAbility repSA = re.getOverridingAbility();
if (repSA.getApi() == ApiType.ReplaceDamage) {
return Math.max(0, restDamage - AbilityUtils.calculateAmount(ca, repSA.getParam("Amount"), repSA));
}
}
return 0;
}
}
restDamage = target.staticDamagePrevention(restDamage, 0, source, isCombat);
return restDamage;
}
/**
* <p>
* predictDamage.
* </p>
*
* @param damage
* a int.
* @param source
* a {@link forge.game.card.Card} object.
* @param isCombat
* a boolean.
* @return a int.
*/
public final static int predictDamageTo(final Card target, final int damage, final Card source, final boolean isCombat) {
public final static int predictDamageTo(final GameEntity target, final int damage, final Card source, final boolean isCombat) {
return predictDamageTo(target, damage, 0, source, isCombat);
}
// This function helps the AI calculate the actual amount of damage an
// effect would deal
/**
@@ -2322,7 +2261,7 @@ public class ComputerUtilCombat {
* a boolean.
* @return a int.
*/
public final static int predictDamageTo(final Card target, final int damage, final int possiblePrevention, final Card source, final boolean isCombat) {
public final static int predictDamageTo(final GameEntity target, final int damage, final int possiblePrevention, final Card source, final boolean isCombat) {
int restDamage = damage;
restDamage = target.staticReplaceDamage(restDamage, source, isCombat);
@@ -2529,13 +2468,13 @@ public class ComputerUtilCombat {
if (combat.isBlocked(c)) {
for (Card blk : combat.getBlockers(c)) {
if (ComputerUtilCombat.blockerWouldBeDestroyed(ai, blk, combat)) {
if (blockerWouldBeDestroyed(ai, blk, combat)) {
return true;
}
}
} else if (combat.isBlocking(c)) {
for (Card atk : combat.getAttackersBlockedBy(c)) {
if (ComputerUtilCombat.attackerWouldBeDestroyed(ai, atk, combat)) {
if (attackerWouldBeDestroyed(ai, atk, combat)) {
return true;
}
}

View File

@@ -63,7 +63,7 @@ public class ComputerUtilMana {
return payManaCost(sa, ai, false, 0, true);
}
private static boolean payManaCost(final SpellAbility sa, final Player ai, final boolean test, final int extraMana, boolean checkPlayable) {
ManaCostBeingPaid cost = ComputerUtilMana.calculateManaCost(sa, test, extraMana);
ManaCostBeingPaid cost = calculateManaCost(sa, test, extraMana);
return payManaCost(cost, sa, ai, test, checkPlayable);
}
@@ -81,7 +81,7 @@ public class ComputerUtilMana {
* Return the number of colors used for payment for Converge
*/
public static int getConvergeCount(final SpellAbility sa, final Player ai) {
ManaCostBeingPaid cost = ComputerUtilMana.calculateManaCost(sa, true, 0);
ManaCostBeingPaid cost = calculateManaCost(sa, true, 0);
if (payManaCost(cost, sa, ai, true, true)) {
return cost.getSunburst();
}
@@ -608,7 +608,7 @@ public class ComputerUtilMana {
}
// arrange all mana abilities by color produced.
final ListMultimap<Integer, SpellAbility> manaAbilityMap = ComputerUtilMana.groupSourcesByManaColor(ai, true);
final ListMultimap<Integer, SpellAbility> manaAbilityMap = groupSourcesByManaColor(ai, true);
if (manaAbilityMap.isEmpty()) {
refundMana(manaSpentToPay, ai, sa);
@@ -617,7 +617,7 @@ public class ComputerUtilMana {
}
// select which abilities may be used for each shard
Multimap<ManaCostShard, SpellAbility> sourcesForShards = ComputerUtilMana.groupAndOrderToPayShards(ai, manaAbilityMap, cost);
Multimap<ManaCostShard, SpellAbility> sourcesForShards = groupAndOrderToPayShards(ai, manaAbilityMap, cost);
sortManaAbilities(sourcesForShards, sa);
@@ -919,7 +919,7 @@ public class ComputerUtilMana {
final SpellAbility sa, final Player ai, final boolean test, final boolean checkPlayable,
List<Mana> manaSpentToPay, final boolean hasConverge, final boolean ignoreColor, final boolean ignoreType) {
// arrange all mana abilities by color produced.
final ListMultimap<Integer, SpellAbility> manaAbilityMap = ComputerUtilMana.groupSourcesByManaColor(ai, checkPlayable);
final ListMultimap<Integer, SpellAbility> manaAbilityMap = groupSourcesByManaColor(ai, checkPlayable);
if (manaAbilityMap.isEmpty()) {
// no mana abilities, bailing out
refundMana(manaSpentToPay, ai, sa);
@@ -931,7 +931,7 @@ public class ComputerUtilMana {
}
// select which abilities may be used for each shard
ListMultimap<ManaCostShard, SpellAbility> sourcesForShards = ComputerUtilMana.groupAndOrderToPayShards(ai, manaAbilityMap, cost);
ListMultimap<ManaCostShard, SpellAbility> sourcesForShards = groupAndOrderToPayShards(ai, manaAbilityMap, cost);
if (hasConverge) {
// add extra colors for paying converge
final int unpaidColors = cost.getUnpaidColors() + cost.getColorsPaid() ^ ManaCostShard.COLORS_SUPERPOSITION;
@@ -1540,7 +1540,7 @@ public class ComputerUtilMana {
for (int i = 0; i < 10; i++) {
mCost = ManaCost.combine(mCost, mkCost);
ManaCostBeingPaid mcbp = new ManaCostBeingPaid(mCost);
if (!ComputerUtilMana.canPayManaCost(mcbp, sa, sa.getActivatingPlayer())) {
if (!canPayManaCost(mcbp, sa, sa.getActivatingPlayer())) {
sa.getHostCard().setSVar("NumTimes", "Number$" + i);
break;
}

View File

@@ -26,7 +26,6 @@ public class CreatureEvaluator implements Function<Card, Integer> {
public int evaluateCreature(final Card c) {
return evaluateCreature(c, true, true);
}
public int evaluateCreature(final Card c, final boolean considerPT, final boolean considerCMC) {
int value = 80;
if (!c.isToken()) {

View File

@@ -157,7 +157,7 @@ public class DamageAllAi extends SpellAbilityAi {
// || (ai.sa.getPayCosts(). ??? )
{
// would take zero damage, and hurt opponent, do it!
if (ComputerUtilCombat.predictDamageTo(ai, dmg, source, false)<1) {
if (ComputerUtilCombat.predictDamageTo(ai, dmg, source, false) < 1) {
return 1;
}
// enemy is expected to die faster than AI from damage if repeated

View File

@@ -70,7 +70,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
// This should be also usable by the AI to forecast an effect (so it must
// not change the game state)
public int staticDamagePrevention(final int damage, final int possiblePrevention, final Card source, final boolean isCombat) {
public int staticDamagePrevention(int damage, final int possiblePrevention, final Card source, final boolean isCombat) {
if (damage <= 0) {
return 0;
}
@@ -88,6 +88,10 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
(!re.hasParam("PreventionEffect") && !re.hasParam("Prevent"))) {
continue;
}
// Immortal Coil prevents the damage but has a similar negative effect
if ("Immortal Coil".equals(ca.getName())) {
continue;
}
if (!re.matchesValidParam("ValidSource", source)) {
continue;
}
@@ -104,10 +108,11 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
} else if (re.getOverridingAbility() != null) {
SpellAbility repSA = re.getOverridingAbility();
if (repSA.getApi() == ApiType.ReplaceDamage) {
return Math.max(0, damage - AbilityUtils.calculateAmount(ca, repSA.getParam("Amount"), repSA));
damage = Math.max(0, damage - AbilityUtils.calculateAmount(ca, repSA.getParam("Amount"), repSA));
}
} else {
return 0;
}
return 0;
}
}

View File

@@ -5239,13 +5239,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
} else if (c.getName().equals("Furnace of Rath")) {
if (isCreature()) {
restDamage += restDamage;
restDamage *= 2;
}
} else if (c.getName().equals("Dictate of the Twin Gods")) {
restDamage += restDamage;
} else if (c.getName().equals("Gratuitous Violence")) {
if (c.getController().equals(source.getController()) && source.isCreature() && isCreature()) {
restDamage += restDamage;
restDamage *= 2;
}
} else if (c.getName().equals("Fire Servant")) {
if (c.getController().equals(source.getController()) && source.isRed()
@@ -5419,7 +5419,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return (c != null ? c.getImageKey() : "");
}
public final boolean isTributed() { return tributed; }
public final void setTributed(final boolean b) {

View File

@@ -742,10 +742,10 @@ public class Player extends GameEntity implements Comparable<Player> {
restDamage += 2;
}
} else if (c.getName().equals("Furnace of Rath") || c.getName().equals("Dictate of the Twin Gods")) {
restDamage += restDamage;
restDamage *= 2;
} else if (c.getName().equals("Gratuitous Violence")) {
if (c.getController().equals(source.getController()) && source.isCreature()) {
restDamage += restDamage;
restDamage *= 2;
}
} else if (c.getName().equals("Fire Servant")) {
if (c.getController().equals(source.getController()) && source.isRed()

View File

@@ -139,7 +139,6 @@ public class ReplaceDamage extends ReplacementEffect {
return true;
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/

View File

@@ -66,8 +66,6 @@ public class ReplaceDraw extends ReplacementEffect {
return true;
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/

View File

@@ -61,8 +61,6 @@ public class ReplaceDrawCards extends ReplacementEffect {
return true;
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/

View File

@@ -51,8 +51,6 @@ public class ReplaceMill extends ReplacementEffect {
return true;
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/