diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index 962779248f7..68b18be79b4 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -6489,7 +6489,8 @@ public class Card extends GameEntity implements Comparable { } else if (property.startsWith("notattacking")) { return null == combat || !combat.isAttacking(this); } else if (property.equals("attackedBySourceThisCombat")) { - final GameEntity defender = game.getCombat().getDefenderByAttacker(source); + if ( null == combat ) return false; + final GameEntity defender = combat.getDefenderByAttacker(source); if (defender instanceof Card) { if (!this.equals((Card) defender)) { return false; @@ -6554,7 +6555,7 @@ public class Card extends GameEntity implements Comparable { } } } else if (property.startsWith("unblocked")) { - if (!game.getCombat().isUnblocked(this)) { + if (game.getCombat() == null || !game.getCombat().isUnblocked(this)) { return false; } } else if (property.equals("attackersBandedWith")) { diff --git a/src/main/java/forge/card/ability/ai/PumpAiBase.java b/src/main/java/forge/card/ability/ai/PumpAiBase.java index 5b8f0278a24..79943b4f576 100644 --- a/src/main/java/forge/card/ability/ai/PumpAiBase.java +++ b/src/main/java/forge/card/ability/ai/PumpAiBase.java @@ -188,7 +188,7 @@ public abstract class PumpAiBase extends SpellAbilityAi { return true; } Predicate flyingOrReach = Predicates.or(CardPredicates.hasKeyword("Flying"), CardPredicates.hasKeyword("Reach")); - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || card.getNetCombatDamage() <= 0 || !Iterables.any(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), @@ -203,7 +203,7 @@ public abstract class PumpAiBase extends SpellAbilityAi { && ComputerUtilCombat.lifeInDanger(ai, game.getCombat())) { return true; } - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || card.getNetCombatDamage() <= 0 || CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), @@ -241,33 +241,33 @@ public abstract class PumpAiBase extends SpellAbilityAi { } return false; } else if (combatRelevant) { - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS) || (opp.getCreaturesInPlay().size() < 1) || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).isEmpty()) { return false; } } else if (keyword.equals("Double Strike")) { - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || card.getNetCombatDamage() <= 0 || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)) { return false; } } else if (keyword.startsWith("Rampage")) { - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)).size() < 2) { return false; } } else if (keyword.startsWith("Flanking")) { - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || CardLists.getNotKeyword(CardLists.filter(opp.getCreaturesInPlay(), CardPredicates.possibleBlockers(card)), "Flanking").isEmpty()) { return false; } } else if (keyword.startsWith("Trample")) { - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || !CombatUtil.canBeBlocked(card, opp) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || card.getNetCombatDamage() + attack <= 1 @@ -282,7 +282,7 @@ public abstract class PumpAiBase extends SpellAbilityAi { return true; } if ((ph.isPlayerTurn(opp)) - || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)) { return false; } @@ -290,7 +290,7 @@ public abstract class PumpAiBase extends SpellAbilityAi { if (card.getNetCombatDamage() <= 0) { return false; } - return combat != null && ( combat.isBlocking(card) || combat.isAttacking(card) && combat.isBlocked(card) ); + return combat != null && ( combat.isBlocking(card) || (combat.isAttacking(card) && combat.isBlocked(card)) ); } else if (keyword.equals("Lifelink")) { if (card.getNetCombatDamage() <= 0) { return false; @@ -333,7 +333,7 @@ public abstract class PumpAiBase extends SpellAbilityAi { return false; } } else if (keyword.equals("Islandwalk")) { - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || card.getNetCombatDamage() <= 0 || CardLists.getType(opp.getLandsInPlay(), "Island").isEmpty() @@ -341,7 +341,7 @@ public abstract class PumpAiBase extends SpellAbilityAi { return false; } } else if (keyword.equals("Swampwalk")) { - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || card.getNetCombatDamage() <= 0 || CardLists.getType(opp.getLandsInPlay(), "Swamp").isEmpty() @@ -349,7 +349,7 @@ public abstract class PumpAiBase extends SpellAbilityAi { return false; } } else if (keyword.equals("Mountainwalk")) { - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || card.getNetCombatDamage() <= 0 || CardLists.getType(opp.getLandsInPlay(), "Mountain").isEmpty() @@ -357,7 +357,7 @@ public abstract class PumpAiBase extends SpellAbilityAi { return false; } } else if (keyword.equals("Forestwalk")) { - if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || combat != null && combat.isAttacking(card)) + if (ph.isPlayerTurn(opp) || !(CombatUtil.canAttack(card, opp) || (combat != null && combat.isAttacking(card))) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) || card.getNetCombatDamage() <= 0 || CardLists.getType(opp.getLandsInPlay(), "Forest").isEmpty() diff --git a/src/main/java/forge/game/GameAction.java b/src/main/java/forge/game/GameAction.java index 4fd6f17597b..a31068cd137 100644 --- a/src/main/java/forge/game/GameAction.java +++ b/src/main/java/forge/game/GameAction.java @@ -1228,7 +1228,8 @@ public class GameAction { c.setDamage(0); c.tap(); c.addRegeneratedThisTurn(); - game.getCombat().removeFromCombat(c); + if (game.getCombat() != null) + game.getCombat().removeFromCombat(c); // Play the Regen sound game.fireEvent(new GameEventCardRegenerated()); diff --git a/src/main/java/forge/game/ai/ComputerUtilCombat.java b/src/main/java/forge/game/ai/ComputerUtilCombat.java index ebf78a4c802..9d32d23f2ff 100644 --- a/src/main/java/forge/game/ai/ComputerUtilCombat.java +++ b/src/main/java/forge/game/ai/ComputerUtilCombat.java @@ -300,7 +300,7 @@ public class ComputerUtilCombat { */ public static boolean lifeInDanger(final Player ai, final Combat combat) { // life in danger only cares about the player's life. Not Planeswalkers' life - if (ai.cantLose() || combat.getAttackingPlayer() == ai) { + if (ai.cantLose() || combat == null || combat.getAttackingPlayer() == ai) { return false; } diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java index dbe9688aaa6..5d332b6cd95 100644 --- a/src/main/java/forge/game/player/Player.java +++ b/src/main/java/forge/game/player/Player.java @@ -2328,7 +2328,7 @@ public class Player extends GameEntity implements Comparable { return false; } } else if (property.equals("attackedBySourceThisCombat")) { - if (!this.equals(game.getCombat().getDefenderPlayerByAttacker(source))) { + if (game.getCombat() == null || !this.equals(game.getCombat().getDefenderPlayerByAttacker(source))) { return false; } } else if (property.startsWith("wasDealtDamageThisTurn")) {