From e72f5f93a05455c9cb0bec556b5243327afbc96e Mon Sep 17 00:00:00 2001 From: Sloth Date: Fri, 24 Feb 2012 14:03:18 +0000 Subject: [PATCH] - The AI can now use spellAbilities giving shroud to creatures to protect them from spellAbilities on the stack. --- src/main/java/forge/ComputerUtil.java | 9 ++-- .../card/abilityfactory/AbilityFactory.java | 34 +++++++++++--- .../abilityfactory/AbilityFactoryPump.java | 45 ++++++++----------- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/main/java/forge/ComputerUtil.java b/src/main/java/forge/ComputerUtil.java index 4f0d276d693..e4447653744 100644 --- a/src/main/java/forge/ComputerUtil.java +++ b/src/main/java/forge/ComputerUtil.java @@ -1929,11 +1929,11 @@ public class ComputerUtil { */ public static boolean containsUsefulKeyword(final ArrayList keywords, final Card card) { for (final String keyword : keywords) { - if (ComputerUtil.isUsefulKeyword(keyword, card)) { - return true; + if (!ComputerUtil.isUsefulKeyword(keyword, card)) { + return false; } } - return false; + return true; } /** @@ -1978,9 +1978,6 @@ public class ComputerUtil { if (ph.isPlayerTurn(human) || !CombatUtil.canAttack(card) || !CombatUtil.canBeBlocked(card)) { return false; } - } else if (keyword.endsWith("Shroud")) { - // TODO: check stack for spells and abilities - return false; } else if (keyword.startsWith("Rampage")) { if (ph.isPlayerTurn(human) || !CombatUtil.canAttack(card) || !CombatUtil.canBeBlocked(card) || (AllZoneUtil.getCreaturesInPlay(human).size() < 2)) { diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactory.java b/src/main/java/forge/card/abilityfactory/AbilityFactory.java index ca43b027a31..0a7369d9c2a 100644 --- a/src/main/java/forge/card/abilityfactory/AbilityFactory.java +++ b/src/main/java/forge/card/abilityfactory/AbilityFactory.java @@ -2272,8 +2272,10 @@ public class AbilityFactory { ArrayList objects = new ArrayList(); final ArrayList threatened = new ArrayList(); String saviourApi = ""; + HashMap saviourParams = null; if (saviourAf != null) { saviourApi = saviourAf.getAPI(); + saviourParams = saviourAf.getMapParams(); } if (topStack == null) { @@ -2299,7 +2301,7 @@ public class AbilityFactory { final String threatApi = topAf.getAPI(); final HashMap threatParams = topAf.getMapParams(); - // Lethal Damage => prevent damage/regeneration/bounce + // Lethal Damage => prevent damage/regeneration/bounce/shroud if (threatApi.equals("DealDamage") || threatApi.equals("DamageAll")) { // If PredictDamage is >= Lethal Damage final int dmg = AbilityFactory.calculateAmount(topStack.getSourceCard(), @@ -2323,6 +2325,13 @@ public class AbilityFactory { continue; } + // give Shroud to targeted creatures + if (saviourApi.equals("Pump") && tgt == null && saviourParams.containsKey("KW") + && (saviourParams.get("KW").endsWith("Shroud") + || saviourParams.get("KW").endsWith("Hexproof"))) { + continue; + } + // don't bounce or blink a permanent that the human // player owns or is a token if (saviourApi.equals("ChangeZone") && (c.getOwner().isHuman() || c.isToken())) { @@ -2345,10 +2354,10 @@ public class AbilityFactory { } } } - // Destroy => regeneration/bounce + // Destroy => regeneration/bounce/shroud else if ((threatApi.equals("Destroy") || threatApi.equals("DestroyAll")) && ((saviourApi.equals("Regenerate") && !threatParams.containsKey("NoRegen")) || saviourApi - .equals("ChangeZone"))) { + .equals("ChangeZone") || saviourApi.equals("Pump"))) { for (final Object o : objects) { if (o instanceof Card) { final Card c = (Card) o; @@ -2362,6 +2371,13 @@ public class AbilityFactory { continue; } + // give Shroud to targeted creatures + if (saviourApi.equals("Pump") && tgt == null && saviourParams.containsKey("KW") + && (saviourParams.get("KW").endsWith("Shroud") + || saviourParams.get("KW").endsWith("Hexproof"))) { + continue; + } + // don't bounce or blink a permanent that the human // player owns or is a token if (saviourApi.equals("ChangeZone") && (c.getOwner().isHuman() || c.isToken())) { @@ -2376,13 +2392,21 @@ public class AbilityFactory { } } } - // Exiling => bounce + // Exiling => bounce/shroud else if ((threatApi.equals("ChangeZone") || threatApi.equals("ChangeZoneAll")) - && saviourApi.equals("ChangeZone") && threatParams.containsKey("Destination") + && (saviourApi.equals("ChangeZone") || saviourApi.equals("Pump")) + && threatParams.containsKey("Destination") && threatParams.get("Destination").equals("Exile")) { for (final Object o : objects) { if (o instanceof Card) { final Card c = (Card) o; + // give Shroud to targeted creatures + if (saviourApi.equals("Pump") && tgt == null && saviourParams.containsKey("KW") + && (saviourParams.get("KW").endsWith("Shroud") + || saviourParams.get("KW").endsWith("Hexproof"))) { + continue; + } + // don't bounce or blink a permanent that the human // player owns or is a token if (saviourApi.equals("ChangeZone") && (c.getOwner().isHuman() || c.isToken())) { diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java index ef6816d3e48..5aca57274da 100644 --- a/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java +++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java @@ -278,6 +278,11 @@ public class AbilityFactoryPump { return false; } + if ((keywords.contains("Shroud") || keywords.contains("Hexproof")) + && AbilityFactory.predictThreatenedObjects(sa.getAbilityFactory()).contains(this)) { + return true; + } + // will the creature attack (only relevant for sorcery speed)? if (CardFactoryUtil.doesCreatureAttackAI(c) && AllZone.getPhaseHandler().isBefore(Constant.Phase.COMBAT_DECLARE_ATTACKERS) @@ -372,15 +377,16 @@ public class AbilityFactoryPump { } // getCurseCreatures() private boolean containsCombatRelevantKeyword(final ArrayList keywords) { - boolean flag = false; for (final String keyword : keywords) { // since most keywords are combat relevant check for those that are // not - if (!keyword.equals("HIDDEN This card doesn't untap during your next untap step.")) { - flag = true; + if (keyword.equals("HIDDEN This card doesn't untap during your next untap step.") + || keyword.endsWith("Shroud") || keyword.endsWith("Hexproof")) { + continue; } + return true; } - return flag; + return false; } /** @@ -426,11 +432,9 @@ public class AbilityFactoryPump { return false; } } else if (AllZone.getStack().size() > 0) { - // TODO: pump something only if the top thing on the stack will kill - // it via damage - // or if top thing on stack will pump it/enchant it and I want to - // kill it - return false; + if (!this.keywords.contains("Shroud") && !this.keywords.contains("Hexproof")) { + return false; + } } final int activations = restrict.getNumberTurnActivations(); @@ -479,21 +483,12 @@ public class AbilityFactoryPump { return false; } - final boolean givesKws = !this.keywords.get(0).equals("none"); - String[] kwPump = { "none" }; - if (givesKws) { - kwPump = this.keywords.toArray(new String[this.keywords.size()]); - } - final String[] keywords = kwPump; - // when this happens we need to expand AI to consider if its ok for // everything? for (final Card card : cards) { final Random r = MyRandom.getRandom(); - // Don't add duplicate keywords - final boolean hKW = card.hasAnyKeyword(keywords); - if (givesKws && hKW) { + if (!ComputerUtil.containsUsefulKeyword(this.keywords, card)) { return false; } @@ -501,18 +496,14 @@ public class AbilityFactoryPump { if (card.getController().isComputer()) { return false; } - if (!ComputerUtil.containsUsefulKeyword(this.keywords, card)) { - return false; - } return (r.nextFloat() <= Math.pow(.6667, activations)); } if (((card.getNetDefense() + defense) > 0) && (!card.hasAnyKeyword(this.keywords))) { - if (card.hasSickness() && this.keywords.contains("Haste")) { - return true; - } else if (card.hasSickness() ^ this.keywords.contains("Haste")) { - return false; - } else if (this.hostCard.equals(card)) { + if ((keywords.contains("Shroud") || keywords.contains("Hexproof")) + && AbilityFactory.predictThreatenedObjects(sa.getAbilityFactory()).contains(card)) { + return (r.nextFloat() <= Math.pow(.6667, activations)); + } else if (this.hostCard.equals(card) && !this.keywords.contains("Haste")) { if (r.nextFloat() <= Math.pow(.6667, activations)) { return CardFactoryUtil.doesCreatureAttackAI(card) && !sa.getPayCosts().getTap(); }