diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 465f6c86b91..9c1cc7cd8aa 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -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 abilities = Lists.newArrayList(); + if ((!player.canLoseLife() || player.cantLoseForZeroOrLessLife() || ComputerUtil.getDamageFromETB(player, land) < player.getLife()) + && (!game.getPhaseHandler().is(PhaseType.MAIN1) || !isSafeToHoldLandDropForMain2(land))) { + final List 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; } } } diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageAiBase.java b/forge-ai/src/main/java/forge/ai/ability/DamageAiBase.java index 748cdb44d46..dc2a3632c1f 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageAiBase.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageAiBase.java @@ -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) { diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index b1ba74b841e..9d03a7a36be 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -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); diff --git a/forge-game/src/main/java/forge/game/ability/effects/RestartGameEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RestartGameEffect.java index 5eeac688763..97375d26c58 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RestartGameEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RestartGameEffect.java @@ -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); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java index 83971c0b5ff..9dc8daa1b08 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java @@ -124,13 +124,15 @@ public class RollDiceEffect extends SpellAbilityEffect { total += modifier; // Run triggers + int rollNum = 1; for (Integer roll : rolls) { final Map 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 runParams = AbilityKey.mapFromPlayer(player); runParams.put(AbilityKey.Sides, sides); diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 6525bbf7f30..50191ded7fd 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -1921,7 +1921,7 @@ public class Player extends GameEntity implements Comparable { } 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() { diff --git a/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java b/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java index 0f4c4a7cc12..a9f6a82cf6c 100644 --- a/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java +++ b/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java @@ -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);