mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-14 01:38:13 +00:00
Merge pull request #2100 from tool4ever/somefixes
Improve damage check logic for losing + performance
This commit is contained in:
@@ -814,9 +814,6 @@ public class AiController {
|
||||
}
|
||||
|
||||
public AiPlayDecision canPlaySa(SpellAbility sa) {
|
||||
final Card card = sa.getHostCard();
|
||||
final boolean isRightTiming = sa.canCastTiming(player);
|
||||
|
||||
if (!checkAiSpecificRestrictions(sa)) {
|
||||
return AiPlayDecision.CantPlayAi;
|
||||
}
|
||||
@@ -824,6 +821,12 @@ public class AiController {
|
||||
return canPlaySa(((WrappedAbility) sa).getWrappedAbility());
|
||||
}
|
||||
|
||||
if (!sa.canCastTiming(player)) {
|
||||
return AiPlayDecision.AnotherTime;
|
||||
}
|
||||
|
||||
final Card card = sa.getHostCard();
|
||||
|
||||
// Trying to play a card that has Buyback without a Buyback cost, look for possible additional considerations
|
||||
if (getBooleanProperty(AiProps.TRY_TO_PRESERVE_BUYBACK_SPELLS)) {
|
||||
if (card.hasKeyword(Keyword.BUYBACK) && !sa.isBuyBackAbility() && !canPlaySpellWithoutBuyback(card, sa)) {
|
||||
@@ -898,9 +901,6 @@ public class AiController {
|
||||
return AiPlayDecision.AnotherTime;
|
||||
}
|
||||
if (sa instanceof SpellPermanent) {
|
||||
if (!isRightTiming) {
|
||||
return AiPlayDecision.AnotherTime;
|
||||
}
|
||||
return canPlayFromEffectAI((SpellPermanent)sa, false, true);
|
||||
}
|
||||
if (sa.usesTargeting()) {
|
||||
@@ -912,18 +912,13 @@ public class AiController {
|
||||
}
|
||||
}
|
||||
if (sa instanceof Spell) {
|
||||
if (ComputerUtil.getDamageForPlaying(player, sa) >= player.getLife()
|
||||
&& !player.cantLoseForZeroOrLessLife() && player.canLoseLife()) {
|
||||
if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife() &&
|
||||
ComputerUtil.getDamageForPlaying(player, sa) >= player.getLife()) {
|
||||
return AiPlayDecision.CurseEffects;
|
||||
}
|
||||
if (!isRightTiming) {
|
||||
return AiPlayDecision.AnotherTime;
|
||||
}
|
||||
return canPlaySpellBasic(card, sa);
|
||||
}
|
||||
if (!isRightTiming) {
|
||||
return AiPlayDecision.AnotherTime;
|
||||
}
|
||||
|
||||
return AiPlayDecision.WillPlay;
|
||||
}
|
||||
|
||||
@@ -1411,8 +1406,8 @@ public class AiController {
|
||||
if (!checkETBEffects(card, spell, null)) {
|
||||
return AiPlayDecision.BadEtbEffects;
|
||||
}
|
||||
if (damage + ComputerUtil.getDamageFromETB(player, card) >= player.getLife()
|
||||
&& !player.cantLoseForZeroOrLessLife() && player.canLoseLife()) {
|
||||
if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife()
|
||||
&& damage + ComputerUtil.getDamageFromETB(player, card) >= player.getLife()) {
|
||||
return AiPlayDecision.BadEtbEffects;
|
||||
}
|
||||
}
|
||||
@@ -1496,35 +1491,33 @@ public class AiController {
|
||||
if (landsWannaPlay != null && !landsWannaPlay.isEmpty()) {
|
||||
// TODO search for other land it might want to play?
|
||||
Card land = chooseBestLandToPlay(landsWannaPlay);
|
||||
if (ComputerUtil.getDamageFromETB(player, land) < player.getLife() || !player.canLoseLife()
|
||||
|| player.cantLoseForZeroOrLessLife() ) {
|
||||
if (!game.getPhaseHandler().is(PhaseType.MAIN1) || !isSafeToHoldLandDropForMain2(land)) {
|
||||
final List<SpellAbility> abilities = Lists.newArrayList();
|
||||
if ((!player.canLoseLife() || player.cantLoseForZeroOrLessLife() || ComputerUtil.getDamageFromETB(player, land) < player.getLife())
|
||||
&& (!game.getPhaseHandler().is(PhaseType.MAIN1) || !isSafeToHoldLandDropForMain2(land))) {
|
||||
final List<SpellAbility> abilities = Lists.newArrayList();
|
||||
|
||||
// TODO extend this logic to evaluate MDFC with both sides land
|
||||
// this can only happen if its a MDFC land
|
||||
if (!land.isLand()) {
|
||||
land.setState(CardStateName.Modal, true);
|
||||
land.setBackSide(true);
|
||||
}
|
||||
// TODO extend this logic to evaluate MDFC with both sides land
|
||||
// this can only happen if its a MDFC land
|
||||
if (!land.isLand()) {
|
||||
land.setState(CardStateName.Modal, true);
|
||||
land.setBackSide(true);
|
||||
}
|
||||
|
||||
LandAbility la = new LandAbility(land, player, null);
|
||||
LandAbility la = new LandAbility(land, player, null);
|
||||
la.setCardState(land.getCurrentState());
|
||||
if (la.canPlay()) {
|
||||
abilities.add(la);
|
||||
}
|
||||
|
||||
// add mayPlay option
|
||||
for (CardPlayOption o : land.mayPlay(player)) {
|
||||
la = new LandAbility(land, player, o.getAbility());
|
||||
la.setCardState(land.getCurrentState());
|
||||
if (la.canPlay()) {
|
||||
abilities.add(la);
|
||||
}
|
||||
|
||||
// add mayPlay option
|
||||
for (CardPlayOption o : land.mayPlay(player)) {
|
||||
la = new LandAbility(land, player, o.getAbility());
|
||||
la.setCardState(land.getCurrentState());
|
||||
if (la.canPlay()) {
|
||||
abilities.add(la);
|
||||
}
|
||||
}
|
||||
if (!abilities.isEmpty()) {
|
||||
return abilities;
|
||||
}
|
||||
}
|
||||
if (!abilities.isEmpty()) {
|
||||
return abilities;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,20 +100,19 @@ public abstract class DamageAiBase extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!enemy.canLoseLife()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!noPrevention) {
|
||||
restDamage = ComputerUtilCombat.predictDamageTo(enemy, restDamage, hostcard, false);
|
||||
} else {
|
||||
restDamage = enemy.staticReplaceDamage(restDamage, hostcard, false);
|
||||
}
|
||||
|
||||
if (restDamage == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!enemy.canLoseLife()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final CardCollectionView hand = comp.getCardsIn(ZoneType.Hand);
|
||||
|
||||
if ((enemy.getLife() - restDamage) < 5) {
|
||||
|
||||
@@ -1420,10 +1420,8 @@ public class GameAction {
|
||||
checkAgain = true;
|
||||
}
|
||||
}
|
||||
if (!spaceSculptors.isEmpty()) {
|
||||
for (Player p : spaceSculptors) {
|
||||
checkAgain |= stateBasedAction704_5u(p);
|
||||
}
|
||||
for (Player p : spaceSculptors) {
|
||||
checkAgain |= stateBasedAction704_5u(p);
|
||||
}
|
||||
// 704.5m World rule
|
||||
checkAgain |= handleWorldRule(noRegCreats);
|
||||
|
||||
@@ -80,8 +80,7 @@ public class RestartGameEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
// special handling for Karn to filter out non-cards
|
||||
CardCollection cmdCards = new CardCollection(p.getCardsIn(ZoneType.Command));
|
||||
for (Card c : cmdCards) {
|
||||
for (Card c : p.getCardsIn(ZoneType.Command)) {
|
||||
if (c.isCommander()) {
|
||||
newLibrary.add(c);
|
||||
}
|
||||
|
||||
@@ -124,13 +124,15 @@ public class RollDiceEffect extends SpellAbilityEffect {
|
||||
total += modifier;
|
||||
|
||||
// Run triggers
|
||||
int rollNum = 1;
|
||||
for (Integer roll : rolls) {
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(player);
|
||||
runParams.put(AbilityKey.Sides, sides);
|
||||
runParams.put(AbilityKey.Modifier, modifier);
|
||||
runParams.put(AbilityKey.Result, roll);
|
||||
runParams.put(AbilityKey.Number, player.getNumRollsThisTurn() + 1 - amount + rolls.indexOf(roll));
|
||||
runParams.put(AbilityKey.Number, player.getNumRollsThisTurn() - amount + rollNum);
|
||||
player.getGame().getTriggerHandler().runTrigger(TriggerType.RolledDie, runParams, false);
|
||||
rollNum++;
|
||||
}
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(player);
|
||||
runParams.put(AbilityKey.Sides, sides);
|
||||
|
||||
@@ -1921,7 +1921,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
public final boolean cantLoseForZeroOrLessLife() {
|
||||
return hasKeyword("You don't lose the game for having 0 or less life.");
|
||||
return cantLose() || hasKeyword("You don't lose the game for having 0 or less life.");
|
||||
}
|
||||
|
||||
public final boolean cantWin() {
|
||||
|
||||
@@ -585,7 +585,7 @@ public class TargetRestrictions {
|
||||
final Card srcCard = sa.getHostCard(); // should there be OrginalHost at any moment?
|
||||
|
||||
for (final Card c : game.getCardsIn(this.tgtZone)) {
|
||||
if (c.isValid(this.validTgts, srcCard.getController(), srcCard, sa)
|
||||
if (c.isValid(this.validTgts, sa.getActivatingPlayer(), srcCard, sa)
|
||||
&& (!isTargeted || sa.canTarget(c))
|
||||
&& !sa.getTargets().contains(c)) {
|
||||
candidates.add(c);
|
||||
|
||||
Reference in New Issue
Block a user