mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Fix miscalculation of damage shields
This commit is contained in:
@@ -1063,7 +1063,7 @@ public class AiAttackController {
|
|||||||
final Card attacker = attackersLeft.get(i);
|
final Card attacker = attackersLeft.get(i);
|
||||||
if (this.aiAggression < 5 && !attacker.hasFirstStrike() && !attacker.hasDoubleStrike()
|
if (this.aiAggression < 5 && !attacker.hasFirstStrike() && !attacker.hasDoubleStrike()
|
||||||
&& ComputerUtilCombat.getTotalFirstStrikeBlockPower(attacker, this.defendingOpponent)
|
&& ComputerUtilCombat.getTotalFirstStrikeBlockPower(attacker, this.defendingOpponent)
|
||||||
>= ComputerUtilCombat.getDamageToKill(attacker)) {
|
>= ComputerUtilCombat.getDamageToKill(attacker, false)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1086,7 +1086,7 @@ public class AiAttackController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if enough damage: switch to next planeswalker
|
// if enough damage: switch to next planeswalker
|
||||||
if (damage >= ComputerUtilCombat.getDamageToKill((Card) defender)) {
|
if (damage >= ComputerUtilCombat.getDamageToKill((Card) defender, true)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ public class AiBlockController {
|
|||||||
if (firstStrikeBlockers.size() > 1) {
|
if (firstStrikeBlockers.size() > 1) {
|
||||||
CardLists.sortByPowerDesc(firstStrikeBlockers);
|
CardLists.sortByPowerDesc(firstStrikeBlockers);
|
||||||
for (final Card blocker : firstStrikeBlockers) {
|
for (final Card blocker : firstStrikeBlockers) {
|
||||||
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker)
|
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker, false)
|
||||||
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false);
|
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false);
|
||||||
// if the total damage of the blockgang was not enough
|
// if the total damage of the blockgang was not enough
|
||||||
// without but is enough with this blocker finish the blockgang
|
// without but is enough with this blocker finish the blockgang
|
||||||
@@ -446,7 +446,7 @@ public class AiBlockController {
|
|||||||
final int additionalDamage = ComputerUtilCombat.dealsDamageAsBlocker(attacker, blocker);
|
final int additionalDamage = ComputerUtilCombat.dealsDamageAsBlocker(attacker, blocker);
|
||||||
final int absorbedDamage2 = ComputerUtilCombat.getEnoughDamageToKill(blocker, attacker.getNetCombatDamage(), attacker, true);
|
final int absorbedDamage2 = ComputerUtilCombat.getEnoughDamageToKill(blocker, attacker.getNetCombatDamage(), attacker, true);
|
||||||
final int addedValue = ComputerUtilCard.evaluateCreature(blocker);
|
final int addedValue = ComputerUtilCard.evaluateCreature(blocker);
|
||||||
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker)
|
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker, false)
|
||||||
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false);
|
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false);
|
||||||
if ((damageNeeded > currentDamage || CombatUtil.getMinNumBlockersForAttacker(attacker, ai) > blockGang.size())
|
if ((damageNeeded > currentDamage || CombatUtil.getMinNumBlockersForAttacker(attacker, ai) > blockGang.size())
|
||||||
&& !(damageNeeded > currentDamage + additionalDamage)
|
&& !(damageNeeded > currentDamage + additionalDamage)
|
||||||
@@ -486,7 +486,7 @@ public class AiBlockController {
|
|||||||
final int additionalDamage2 = ComputerUtilCombat.dealsDamageAsBlocker(attacker, secondBlocker);
|
final int additionalDamage2 = ComputerUtilCombat.dealsDamageAsBlocker(attacker, secondBlocker);
|
||||||
final int absorbedDamage2 = ComputerUtilCombat.getEnoughDamageToKill(secondBlocker, attacker.getNetCombatDamage(), attacker, true);
|
final int absorbedDamage2 = ComputerUtilCombat.getEnoughDamageToKill(secondBlocker, attacker.getNetCombatDamage(), attacker, true);
|
||||||
final int addedValue2 = ComputerUtilCard.evaluateCreature(secondBlocker);
|
final int addedValue2 = ComputerUtilCard.evaluateCreature(secondBlocker);
|
||||||
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker)
|
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker, false)
|
||||||
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, secondBlocker, combat, false);
|
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, secondBlocker, combat, false);
|
||||||
|
|
||||||
List<Card> usableBlockersAsThird = new ArrayList<>(usableBlockers);
|
List<Card> usableBlockersAsThird = new ArrayList<>(usableBlockers);
|
||||||
@@ -774,7 +774,7 @@ public class AiBlockController {
|
|||||||
if (blockers.size() > 0) {
|
if (blockers.size() > 0) {
|
||||||
safeBlockers = getSafeBlockers(combat, attacker, blockers);
|
safeBlockers = getSafeBlockers(combat, attacker, blockers);
|
||||||
for (final Card blocker : safeBlockers) {
|
for (final Card blocker : safeBlockers) {
|
||||||
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker)
|
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker, false)
|
||||||
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false);
|
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false);
|
||||||
// Add an additional blocker if the current blockers are not
|
// Add an additional blocker if the current blockers are not
|
||||||
// enough and the new one would deal additional damage
|
// enough and the new one would deal additional damage
|
||||||
@@ -801,7 +801,7 @@ public class AiBlockController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final Card blocker : safeBlockers) {
|
for (final Card blocker : safeBlockers) {
|
||||||
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker)
|
final int damageNeeded = ComputerUtilCombat.getDamageToKill(attacker, false)
|
||||||
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false);
|
+ ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, blocker, combat, false);
|
||||||
// Add an additional blocker if the current blockers are not
|
// Add an additional blocker if the current blockers are not
|
||||||
// enough and the new one would deal the remaining damage
|
// enough and the new one would deal the remaining damage
|
||||||
|
|||||||
@@ -1687,7 +1687,7 @@ public class ComputerUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) {
|
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) {
|
||||||
boolean canSave = ComputerUtilCombat.predictDamageTo(c, dmg - toughness, source, false) < ComputerUtilCombat.getDamageToKill(c);
|
boolean canSave = ComputerUtilCombat.predictDamageTo(c, dmg - toughness, source, false) < ComputerUtilCombat.getDamageToKill(c, false);
|
||||||
if ((!topStack.usesTargeting() && !grantIndestructible && !canSave)
|
if ((!topStack.usesTargeting() && !grantIndestructible && !canSave)
|
||||||
|| (!grantIndestructible && !grantShroud && !canSave)) {
|
|| (!grantIndestructible && !grantShroud && !canSave)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -1695,14 +1695,14 @@ public class ComputerUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (saviourApi == ApiType.PutCounter || saviourApi == ApiType.PutCounterAll) {
|
if (saviourApi == ApiType.PutCounter || saviourApi == ApiType.PutCounterAll) {
|
||||||
boolean canSave = ComputerUtilCombat.predictDamageTo(c, dmg - toughness, source, false) < ComputerUtilCombat.getDamageToKill(c);
|
boolean canSave = ComputerUtilCombat.predictDamageTo(c, dmg - toughness, source, false) < ComputerUtilCombat.getDamageToKill(c, false);
|
||||||
if (!canSave) {
|
if (!canSave) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cannot protect against source
|
// cannot protect against source
|
||||||
if (saviourApi == ApiType.Protection && (ProtectAi.toProtectFrom(source, saviour) == null)) {
|
if (saviourApi == ApiType.Protection && ProtectAi.toProtectFrom(source, saviour) == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1712,7 +1712,7 @@ public class ComputerUtil {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c)) {
|
if (ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c, false)) {
|
||||||
threatened.add(c);
|
threatened.add(c);
|
||||||
}
|
}
|
||||||
} else if (o instanceof Player) {
|
} else if (o instanceof Player) {
|
||||||
@@ -1739,7 +1739,7 @@ public class ComputerUtil {
|
|||||||
if (o instanceof Card) {
|
if (o instanceof Card) {
|
||||||
final Card c = (Card) o;
|
final Card c = (Card) o;
|
||||||
final boolean canRemove = (c.getNetToughness() <= dmg)
|
final boolean canRemove = (c.getNetToughness() <= dmg)
|
||||||
|| (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && c.getShieldCount() == 0 && (dmg >= ComputerUtilCombat.getDamageToKill(c)));
|
|| (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && c.getShieldCount() == 0 && (dmg >= ComputerUtilCombat.getDamageToKill(c, false)));
|
||||||
if (!canRemove) {
|
if (!canRemove) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1747,7 +1747,7 @@ public class ComputerUtil {
|
|||||||
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) {
|
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) {
|
||||||
final boolean cantSave = c.getNetToughness() + toughness <= dmg
|
final boolean cantSave = c.getNetToughness() + toughness <= dmg
|
||||||
|| (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && c.getShieldCount() == 0 && !grantIndestructible
|
|| (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && c.getShieldCount() == 0 && !grantIndestructible
|
||||||
&& (dmg >= toughness + ComputerUtilCombat.getDamageToKill(c)));
|
&& (dmg >= toughness + ComputerUtilCombat.getDamageToKill(c, false)));
|
||||||
if (cantSave && (!topStack.usesTargeting() || !grantShroud)) {
|
if (cantSave && (!topStack.usesTargeting() || !grantShroud)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1498,7 +1498,7 @@ public class ComputerUtilCard {
|
|||||||
}
|
}
|
||||||
if (c.hasKeyword(Keyword.TRAMPLE) || keywords.contains("Trample")) {
|
if (c.hasKeyword(Keyword.TRAMPLE) || keywords.contains("Trample")) {
|
||||||
for (Card b : combat.getBlockers(c)) {
|
for (Card b : combat.getBlockers(c)) {
|
||||||
pumpedDmg -= ComputerUtilCombat.getDamageToKill(b);
|
pumpedDmg -= ComputerUtilCombat.getDamageToKill(b, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pumpedDmg = 0;
|
pumpedDmg = 0;
|
||||||
@@ -1526,7 +1526,7 @@ public class ComputerUtilCard {
|
|||||||
if (combat.isBlocked(atk)) {
|
if (combat.isBlocked(atk)) {
|
||||||
// consider Trample damage properly for a blocked creature
|
// consider Trample damage properly for a blocked creature
|
||||||
for (Card blk : combat.getBlockers(atk)) {
|
for (Card blk : combat.getBlockers(atk)) {
|
||||||
totalPowerUnblocked -= ComputerUtilCombat.getDamageToKill(blk);
|
totalPowerUnblocked -= ComputerUtilCombat.getDamageToKill(blk, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return totalDamageOfBlockers(attacker, list);
|
return totalFirstStrikeDamageOfBlockers(attacker, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function takes Doran and Double Strike into account
|
// This function takes Doran and Double Strike into account
|
||||||
@@ -619,7 +619,7 @@ public class ComputerUtilCombat {
|
|||||||
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(Keyword.INDESTRUCTIBLE)) {
|
&& !defender.hasKeyword(Keyword.INDESTRUCTIBLE)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -698,7 +698,7 @@ public class ComputerUtilCombat {
|
|||||||
|
|
||||||
final int defBushidoMagnitude = blocker.getKeywordMagnitude(Keyword.BUSHIDO);
|
final int defBushidoMagnitude = blocker.getKeywordMagnitude(Keyword.BUSHIDO);
|
||||||
|
|
||||||
final int defenderDefense = (blocker.getLethalDamage() - flankingMagnitude) + defBushidoMagnitude;
|
final int defenderDefense = blocker.getLethalDamage() - flankingMagnitude + defBushidoMagnitude;
|
||||||
|
|
||||||
return defenderDefense;
|
return defenderDefense;
|
||||||
} // shieldDamage
|
} // shieldDamage
|
||||||
@@ -751,10 +751,10 @@ public class ComputerUtilCombat {
|
|||||||
|
|
||||||
// Consider first strike and double strike
|
// Consider first strike and double strike
|
||||||
if (attacker.hasKeyword(Keyword.FIRST_STRIKE) || attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
if (attacker.hasKeyword(Keyword.FIRST_STRIKE) || attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
||||||
return firstStrikeBlockerDmg >= getDamageToKill(attacker);
|
return firstStrikeBlockerDmg >= getDamageToKill(attacker, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalDamageOfBlockers(attacker, blockers) >= getDamageToKill(attacker);
|
return totalDamageOfBlockers(attacker, blockers) >= getDamageToKill(attacker, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will this trigger trigger?
|
// Will this trigger trigger?
|
||||||
@@ -1611,7 +1611,7 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Check triggers that deal damage or shrink the attacker
|
//Check triggers that deal damage or shrink the attacker
|
||||||
if (getDamageToKill(attacker)
|
if (getDamageToKill(attacker, false)
|
||||||
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities) <= 0) {
|
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities) <= 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1763,9 +1763,9 @@ public class ComputerUtilCombat {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int defenderLife = getDamageToKill(blocker)
|
final int defenderLife = getDamageToKill(blocker, false)
|
||||||
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
|
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
|
||||||
final int attackerLife = getDamageToKill(attacker)
|
final int attackerLife = getDamageToKill(attacker, false)
|
||||||
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
|
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
|
||||||
|
|
||||||
if (blocker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
if (blocker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
||||||
@@ -1790,13 +1790,11 @@ public class ComputerUtilCombat {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // defender double strike
|
} // defender double strike
|
||||||
|
|
||||||
else { // no double strike for defender
|
else { // no double strike for defender
|
||||||
// Attacker may kill the blocker before he can deal any damage
|
// Attacker may kill the blocker before he can deal any damage
|
||||||
if (dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
|
if (dealsFirstStrikeDamage(attacker, withoutAbilities, combat)
|
||||||
&& !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)
|
&& !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)
|
||||||
&& !dealsFirstStrikeDamage(blocker, withoutAbilities, combat)) {
|
&& !dealsFirstStrikeDamage(blocker, withoutAbilities, combat)) {
|
||||||
|
|
||||||
if (attackerDamage >= defenderLife) {
|
if (attackerDamage >= defenderLife) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1810,7 +1808,6 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return defenderDamage >= attackerLife;
|
return defenderDamage >= attackerLife;
|
||||||
|
|
||||||
} // defender no double strike
|
} // defender no double strike
|
||||||
return false;// should never arrive here
|
return false;// should never arrive here
|
||||||
} // canDestroyAttacker
|
} // canDestroyAttacker
|
||||||
@@ -1856,7 +1853,7 @@ public class ComputerUtilCombat {
|
|||||||
if (flankingMagnitude >= blocker.getNetToughness()) {
|
if (flankingMagnitude >= blocker.getNetToughness()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((flankingMagnitude >= getDamageToKill(blocker))
|
if (flankingMagnitude >= getDamageToKill(blocker, false)
|
||||||
&& !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)) {
|
&& !blocker.hasKeyword(Keyword.INDESTRUCTIBLE)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1867,7 +1864,7 @@ public class ComputerUtilCombat {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getDamageToKill(blocker)
|
if (getDamageToKill(blocker, false)
|
||||||
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities) <= 0) {
|
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities) <= 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1996,9 +1993,9 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final int defenderLife = getDamageToKill(blocker)
|
final int defenderLife = getDamageToKill(blocker, false)
|
||||||
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
|
+ predictToughnessBonusOfBlocker(attacker, blocker, withoutAbilities);
|
||||||
final int attackerLife = getDamageToKill(attacker)
|
final int attackerLife = getDamageToKill(attacker, false)
|
||||||
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
|
+ predictToughnessBonusOfAttacker(attacker, blocker, combat, withoutAbilities, withoutAttackerStaticAbilities);
|
||||||
|
|
||||||
if (attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
if (attacker.hasKeyword(Keyword.DOUBLE_STRIKE)) {
|
||||||
@@ -2128,7 +2125,7 @@ public class ComputerUtilCombat {
|
|||||||
if (dmgCanDeal > 0 ) { // if any damage left undistributed,
|
if (dmgCanDeal > 0 ) { // if any damage left undistributed,
|
||||||
if (hasTrample && isAttacking) // if you have trample, deal damage to defending entity
|
if (hasTrample && isAttacking) // if you have trample, deal damage to defending entity
|
||||||
damageMap.put(null, dmgCanDeal);
|
damageMap.put(null, dmgCanDeal);
|
||||||
else if ( lastBlocker != null ) { // otherwise flush it into last blocker
|
else if (lastBlocker != null) { // otherwise flush it into last blocker
|
||||||
damageMap.put(lastBlocker, dmgCanDeal + damageMap.get(lastBlocker));
|
damageMap.put(lastBlocker, dmgCanDeal + damageMap.get(lastBlocker));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2171,7 +2168,7 @@ public class ComputerUtilCombat {
|
|||||||
*/
|
*/
|
||||||
public static final int getEnoughDamageToKill(final Card c, final int maxDamage, final Card source, final boolean isCombat,
|
public static final int getEnoughDamageToKill(final Card c, final int maxDamage, final Card source, final boolean isCombat,
|
||||||
final boolean noPrevention) {
|
final boolean noPrevention) {
|
||||||
final int killDamage = getDamageToKill(c);
|
final int killDamage = getDamageToKill(c, false);
|
||||||
|
|
||||||
if (c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.getShieldCount() > 0) {
|
if (c.hasKeyword(Keyword.INDESTRUCTIBLE) || c.getShieldCount() > 0) {
|
||||||
if (!(source.hasKeyword(Keyword.WITHER) || source.hasKeyword(Keyword.INFECT))) {
|
if (!(source.hasKeyword(Keyword.WITHER) || source.hasKeyword(Keyword.INFECT))) {
|
||||||
@@ -2212,8 +2209,8 @@ public class ComputerUtilCombat {
|
|||||||
*
|
*
|
||||||
* @return a int.
|
* @return a int.
|
||||||
*/
|
*/
|
||||||
public final static int getDamageToKill(final Card c) {
|
public final static int getDamageToKill(final Card c, boolean withShields) {
|
||||||
int damageShield = c.getPreventNextDamageTotalShields();
|
int damageShield = withShields ? c.getPreventNextDamageTotalShields() : 0;
|
||||||
int killDamage = (c.isPlaneswalker() ? c.getCurrentLoyalty() : c.getLethalDamage()) + damageShield;
|
int killDamage = (c.isPlaneswalker() ? c.getCurrentLoyalty() : c.getLethalDamage()) + damageShield;
|
||||||
|
|
||||||
if (killDamage > damageShield
|
if (killDamage > damageShield
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ public class DamageAllAi extends SpellAbilityAi {
|
|||||||
final Predicate<Card> filterKillable = new Predicate<Card>() {
|
final Predicate<Card> filterKillable = new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(final Card c) {
|
public boolean apply(final Card c) {
|
||||||
return (ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c));
|
return (ComputerUtilCombat.predictDamageTo(c, dmg, source, false) >= ComputerUtilCombat.getDamageToKill(c, false));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -807,7 +807,7 @@ public class DamageDealAi extends DamageAiBase {
|
|||||||
if (o instanceof Card) {
|
if (o instanceof Card) {
|
||||||
Card c = (Card) o;
|
Card c = (Card) o;
|
||||||
final int restDamage = ComputerUtilCombat.predictDamageTo(c, dmg, saMe.getHostCard(), false);
|
final int restDamage = ComputerUtilCombat.predictDamageTo(c, dmg, saMe.getHostCard(), false);
|
||||||
if (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && ComputerUtilCombat.getDamageToKill(c) <= restDamage) {
|
if (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && ComputerUtilCombat.getDamageToKill(c, false) <= restDamage) {
|
||||||
if (c.getController().equals(ai)) {
|
if (c.getController().equals(ai)) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -70,14 +70,11 @@ public class FightAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
Card fighter1 = fighter1List.get(0);
|
Card fighter1 = fighter1List.get(0);
|
||||||
for (Card humanCreature : humCreatures) {
|
for (Card humanCreature : humCreatures) {
|
||||||
if (ComputerUtilCombat.getDamageToKill(humanCreature) <= fighter1.getNetPower()
|
if (canKill(fighter1, humanCreature, 0)
|
||||||
&& humanCreature.getNetPower() < ComputerUtilCombat.getDamageToKill(fighter1)) {
|
&& !canKill(humanCreature, fighter1, 0)) {
|
||||||
// todo: check min/max targets; see if we picked the best matchup
|
// todo: check min/max targets; see if we picked the best matchup
|
||||||
sa.getTargets().add(humanCreature);
|
sa.getTargets().add(humanCreature);
|
||||||
return true;
|
return true;
|
||||||
} else if (humanCreature.getSVar("Targeting").equals("Dies")) {
|
|
||||||
sa.getTargets().add(humanCreature);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false; // bail at this point, otherwise the AI will overtarget and waste the activation
|
return false; // bail at this point, otherwise the AI will overtarget and waste the activation
|
||||||
@@ -87,16 +84,12 @@ public class FightAi extends SpellAbilityAi {
|
|||||||
if (!(humCreatures.isEmpty() && aiCreatures.isEmpty())) {
|
if (!(humCreatures.isEmpty() && aiCreatures.isEmpty())) {
|
||||||
for (Card humanCreature : humCreatures) {
|
for (Card humanCreature : humCreatures) {
|
||||||
for (Card aiCreature : aiCreatures) {
|
for (Card aiCreature : aiCreatures) {
|
||||||
if (ComputerUtilCombat.getDamageToKill(humanCreature) <= aiCreature.getNetPower()
|
if (canKill(aiCreature, humanCreature, 0)
|
||||||
&& humanCreature.getNetPower() < ComputerUtilCombat.getDamageToKill(aiCreature)) {
|
&& !canKill(humanCreature, aiCreature, 0)) {
|
||||||
// todo: check min/max targets; see if we picked the best matchup
|
// todo: check min/max targets; see if we picked the best matchup
|
||||||
sa.getTargets().add(humanCreature);
|
sa.getTargets().add(humanCreature);
|
||||||
sa.getTargets().add(aiCreature);
|
sa.getTargets().add(aiCreature);
|
||||||
return true;
|
return true;
|
||||||
} else if (humanCreature.getSVar("Targeting").equals("Dies")) {
|
|
||||||
sa.getTargets().add(humanCreature);
|
|
||||||
sa.getTargets().add(aiCreature);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,8 +104,8 @@ public class FightAi extends SpellAbilityAi {
|
|||||||
if (sa.hasParam("TargetsWithoutSameCreatureType") && creature1.sharesCreatureTypeWith(creature2)) {
|
if (sa.hasParam("TargetsWithoutSameCreatureType") && creature1.sharesCreatureTypeWith(creature2)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ComputerUtilCombat.getDamageToKill(creature1) <= creature2.getNetPower()
|
if (canKill(creature1, creature2, 0)
|
||||||
&& creature1.getNetPower() >= ComputerUtilCombat.getDamageToKill(creature2)) {
|
&& canKill(creature2, creature1, 0)) {
|
||||||
// todo: check min/max targets; see if we picked the best matchup
|
// todo: check min/max targets; see if we picked the best matchup
|
||||||
sa.getTargets().add(creature1);
|
sa.getTargets().add(creature1);
|
||||||
sa.getTargets().add(creature2);
|
sa.getTargets().add(creature2);
|
||||||
@@ -152,14 +145,14 @@ public class FightAi extends SpellAbilityAi {
|
|||||||
if (sa.hasParam("Defined")) {
|
if (sa.hasParam("Defined")) {
|
||||||
Card aiCreature = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa).get(0);
|
Card aiCreature = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa).get(0);
|
||||||
for (Card humanCreature : humCreatures) {
|
for (Card humanCreature : humCreatures) {
|
||||||
if (ComputerUtilCombat.getDamageToKill(humanCreature) <= aiCreature.getNetPower()
|
if (canKill(aiCreature, humanCreature, 0)
|
||||||
&& ComputerUtilCard.evaluateCreature(humanCreature) > ComputerUtilCard.evaluateCreature(aiCreature)) {
|
&& ComputerUtilCard.evaluateCreature(humanCreature) > ComputerUtilCard.evaluateCreature(aiCreature)) {
|
||||||
sa.getTargets().add(humanCreature);
|
sa.getTargets().add(humanCreature);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Card humanCreature : humCreatures) {
|
for (Card humanCreature : humCreatures) {
|
||||||
if (ComputerUtilCombat.getDamageToKill(aiCreature) > humanCreature.getNetPower()) {
|
if (!canKill(humanCreature, aiCreature, 0)) {
|
||||||
sa.getTargets().add(humanCreature);
|
sa.getTargets().add(humanCreature);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -312,7 +305,7 @@ public class FightAi extends SpellAbilityAi {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (fighter.hasKeyword(Keyword.DEATHTOUCH)
|
if (fighter.hasKeyword(Keyword.DEATHTOUCH)
|
||||||
|| ComputerUtilCombat.getDamageToKill(opponent) <= fighter.getNetPower() + pumpAttack) {
|
|| ComputerUtilCombat.getDamageToKill(opponent, true) <= fighter.getNetPower() + pumpAttack) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ public class LifeSetAi extends SpellAbilityAi {
|
|||||||
if (tgt.canOnlyTgtOpponent()) {
|
if (tgt.canOnlyTgtOpponent()) {
|
||||||
sa.getTargets().add(opponent);
|
sa.getTargets().add(opponent);
|
||||||
} else {
|
} else {
|
||||||
if ((amount > myLife) && (myLife <= 10)) {
|
if (amount > myLife && myLife <= 10) {
|
||||||
sa.getTargets().add(ai);
|
sa.getTargets().add(ai);
|
||||||
} else if (hlife > amount) {
|
} else if (hlife > amount) {
|
||||||
sa.getTargets().add(opponent);
|
sa.getTargets().add(opponent);
|
||||||
|
|||||||
@@ -467,7 +467,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
|||||||
if (c.getSVar("Targeting").equals("Dies") || c.getNetToughness() <= -defense) {
|
if (c.getSVar("Targeting").equals("Dies") || c.getNetToughness() <= -defense) {
|
||||||
return true; // can kill indestructible creatures
|
return true; // can kill indestructible creatures
|
||||||
}
|
}
|
||||||
return (ComputerUtilCombat.getDamageToKill(c) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE));
|
return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE);
|
||||||
}
|
}
|
||||||
}); // leaves all creatures that will be destroyed
|
}); // leaves all creatures that will be destroyed
|
||||||
} // -X/-X end
|
} // -X/-X end
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public class PumpAllAi extends PumpAiBase {
|
|||||||
if (c.getNetToughness() <= -defense) {
|
if (c.getNetToughness() <= -defense) {
|
||||||
return true; // can kill indestructible creatures
|
return true; // can kill indestructible creatures
|
||||||
}
|
}
|
||||||
return ((ComputerUtilCombat.getDamageToKill(c) <= -defense) && !c.hasKeyword(Keyword.INDESTRUCTIBLE));
|
return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE);
|
||||||
}
|
}
|
||||||
}); // leaves all creatures that will be destroyed
|
}); // leaves all creatures that will be destroyed
|
||||||
human = CardLists.filter(human, new Predicate<Card>() {
|
human = CardLists.filter(human, new Predicate<Card>() {
|
||||||
@@ -99,7 +99,7 @@ public class PumpAllAi extends PumpAiBase {
|
|||||||
if (c.getNetToughness() <= -defense) {
|
if (c.getNetToughness() <= -defense) {
|
||||||
return true; // can kill indestructible creatures
|
return true; // can kill indestructible creatures
|
||||||
}
|
}
|
||||||
return ((ComputerUtilCombat.getDamageToKill(c) <= -defense) && !c.hasKeyword(Keyword.INDESTRUCTIBLE));
|
return ComputerUtilCombat.getDamageToKill(c, false) <= -defense && !c.hasKeyword(Keyword.INDESTRUCTIBLE);
|
||||||
}
|
}
|
||||||
}); // leaves all creatures that will be destroyed
|
}); // leaves all creatures that will be destroyed
|
||||||
} // -X/-X end
|
} // -X/-X end
|
||||||
|
|||||||
@@ -24,14 +24,14 @@ public class LifeSetEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
if (redistribute) {
|
if (redistribute) {
|
||||||
for (final Player p : getTargetPlayers(sa)) {
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
if (tgt == null || p.canBeTargetedBy(sa)) {
|
||||||
lifetotals.add(p.getLife());
|
lifetotals.add(p.getLife());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final Player p : getTargetPlayers(sa)) {
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
if (tgt == null || p.canBeTargetedBy(sa)) {
|
||||||
if (!redistribute) {
|
if (!redistribute) {
|
||||||
p.setLife(lifeAmount, sa.getHostCard());
|
p.setLife(lifeAmount, sa.getHostCard());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ ALTERNATE
|
|||||||
Name:Revenge
|
Name:Revenge
|
||||||
ManaCost:4 W B
|
ManaCost:4 W B
|
||||||
Types:Sorcery
|
Types:Sorcery
|
||||||
A:SP$ SetLife | LifeAmount$ X | SubAbility$ DBLoseHalf | SpellDescription$ Double your life total. Target opponent loses half their life, rounded up.
|
A:SP$ SetLife | LifeAmount$ X | Defined$ You | SubAbility$ DBLoseHalf | SpellDescription$ Double your life total. Target opponent loses half their life, rounded up.
|
||||||
SVar:DBLoseHalf:DB$ LoseLife | ValidTgts$ Opponent | LifeAmount$ Y
|
SVar:DBLoseHalf:DB$ LoseLife | ValidTgts$ Opponent | LifeAmount$ Y
|
||||||
SVar:X:Count$YourLifeTotal/Twice
|
SVar:X:Count$YourLifeTotal/Twice
|
||||||
SVar:Y:Count$TargetedLifeTotal/HalfUp
|
SVar:Y:Count$TargetedLifeTotal/HalfUp
|
||||||
|
|||||||
Reference in New Issue
Block a user