diff --git a/.gitattributes b/.gitattributes index 97f8138d898..1b3bf8f54f6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2761,6 +2761,7 @@ res/cardsfolder/lure.txt -text svneol=native#text/plain res/cardsfolder/lurking_informant.txt -text svneol=native#text/plain res/cardsfolder/lurking_nightstalker.txt -text svneol=native#text/plain res/cardsfolder/lux_cannon.txt -text svneol=native#text/plain +res/cardsfolder/lymph_sliver.txt -text svneol=native#text/plain res/cardsfolder/lynx.txt -text svneol=native#text/plain res/cardsfolder/lys_alana_huntmaster.txt -text svneol=native#text/plain res/cardsfolder/ma_chao_western_warrior.txt -text svneol=native#text/plain diff --git a/res/cardsfolder/lymph_sliver.txt b/res/cardsfolder/lymph_sliver.txt new file mode 100644 index 00000000000..0088ca74eb8 --- /dev/null +++ b/res/cardsfolder/lymph_sliver.txt @@ -0,0 +1,9 @@ +Name:Lymph Sliver +ManaCost:4 W +Types:Creature Sliver +Text:no text +PT:3/3 +K:stPumpAll:Creature.Sliver:0/0/Absorb 1:no Condition:All Sliver creatures have absorb 1. (If a source would deal damage to a Sliver, prevent 1 of that damage.) +SVar:Rarity:Common +SVar:Picture:http://www.wizards.com/global/images/magic/general/lymph_sliver.jpg +End diff --git a/src/forge/AbilityFactory_DealDamage.java b/src/forge/AbilityFactory_DealDamage.java index ff82afa5b59..eb8029ad062 100644 --- a/src/forge/AbilityFactory_DealDamage.java +++ b/src/forge/AbilityFactory_DealDamage.java @@ -175,9 +175,10 @@ import java.util.Random; } private boolean shouldTgtP(int d, final boolean noPrevention) { + int restDamage = d; - if (AllZone.HumanPlayer.preventAllDamageToPlayer(AF.getHostCard(), false) - || !AllZone.HumanPlayer.canTarget(AF.getHostCard())) return false; + if (!noPrevention) + restDamage = AllZone.HumanPlayer.staticDamagePrevention(restDamage,AF.getHostCard(),false); PlayerZone compHand = AllZone.getZone(Constant.Zone.Hand, AllZone.ComputerPlayer); CardList hand = new CardList(compHand.getCards()); @@ -197,10 +198,12 @@ import java.util.Random; CardList hPlay = new CardList(human.getCards()); hPlay = hPlay.filter(new CardListFilter() { public boolean addCard(Card c) { + int restDamage = d; + if (!noPrevention) + restDamage = c.staticDamagePrevention(d,AF.getHostCard(),false); // will include creatures already dealt damage - return c.isCreature() && (c.getKillDamage() <= d) + return c.isCreature() && (c.getKillDamage() <= restDamage) && CardFactoryUtil.canTarget(AF.getHostCard(), c) - && !(c.preventAllDamageToCard(AF.getHostCard(),false) && !noPrevention) && !c.getKeyword().contains("Indestructible") && !(c.getSVar("SacMe").length() > 0); } diff --git a/src/forge/Card.java b/src/forge/Card.java index dab46acbc7d..8a1968d7ba2 100644 --- a/src/forge/Card.java +++ b/src/forge/Card.java @@ -2216,11 +2216,11 @@ public class Card extends MyObservable { } // This is for keywords with a number like Bushido, Annihilator and Rampage. It returns the total. - public int getKeywordMagnitute(String k) { + public int getKeywordMagnitude(String k) { int count = 0; ArrayList keywords = getKeyword(); for(String kw:keywords) { - if(kw.contains(k)) { + if(kw.startsWith(k)) { String[] parse = kw.split(" "); String s = parse[1]; count += Integer.parseInt(s); @@ -2661,10 +2661,8 @@ public class Card extends MyObservable { return getNetDefense() + preventNextDamage - getDamage(); } - - public void setDamage(int n) { - if(this.getKeyword().contains("Prevent all damage that would be dealt to CARDNAME.")) n = 0; + //if(this.getKeyword().contains("Prevent all damage that would be dealt to CARDNAME.")) n = 0; damage = n; } @@ -2761,46 +2759,58 @@ public class Card extends MyObservable { } } - public boolean preventAllDamageToCard(Card source, boolean isCombat) { - boolean reduce = false; + //This should be also usable by the AI to forecast an effect (so it must not change the game state) + public int staticDamagePrevention(final int damage, final Card source, final boolean isCombat) { + int restDamage = damage; + if(isCombat) { - reduce = reduce || getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME."); - reduce = reduce || getKeyword().contains("Prevent all combat damage that would be dealt to CARDNAME."); - reduce = reduce || source.getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME."); - reduce = reduce || source.getKeyword().contains("Prevent all combat damage that would be dealt by CARDNAME."); + if(getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME."))return 0; + if(getKeyword().contains("Prevent all combat damage that would be dealt to CARDNAME."))return 0; + if(source.getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME."))return 0; + if(source.getKeyword().contains("Prevent all combat damage that would be dealt by CARDNAME."))return 0; + } + if(getKeyword().contains("Prevent all damage that would be dealt to CARDNAME."))return 0; + if(getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME."))return 0; + if(source.getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME."))return 0; + if(source.getKeyword().contains("Prevent all damage that would be dealt by CARDNAME."))return 0; + + if(hasStartOfKeyword("Absorb")) { + int absorbed = this.getKeywordMagnitude("Absorb"); + if (restDamage > absorbed) restDamage = restDamage - absorbed; + else return 0; } - reduce = reduce || getKeyword().contains("Prevent all damage that would be dealt to CARDNAME."); - reduce = reduce || getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME."); - reduce = reduce || source.getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME."); - reduce = reduce || source.getKeyword().contains("Prevent all damage that would be dealt by CARDNAME."); //more specific prevents here: - reduce = reduce || (getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by artifact creatures.") - && source.isCreature() && source.isArtifact()); - reduce = reduce || (getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by artifacts.") - && source.isArtifact()); - reduce = reduce || (getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by creatures.") - && source.isCreature()); + if((getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by artifact creatures.") + && source.isCreature() && source.isArtifact()))return 0; + if((getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by artifacts.") + && source.isArtifact()))return 0; + if((getKeyword().contains("Prevent all damage that would be dealt to CARDNAME by creatures.") + && source.isCreature()))return 0; // specific Cards - reduce = reduce || (this.isCreature() && source.isCreature() && - AllZoneUtil.isCardInPlay("Well-Laid Plans") && source.sharesColorWith(this)); - reduce = reduce || (!isCombat && AllZoneUtil.isCardInPlay("Mark of Asylum", getController())); - reduce = reduce || (source.getController() == getController() && AllZoneUtil.isCardInPlay("Light of Sanction", getController())); - return reduce; + if(!isCreature()) { //and not a planeswalker + if((this.isCreature() && source.isCreature() && + AllZoneUtil.isCardInPlay("Well-Laid Plans") && source.sharesColorWith(this)))return 0; + + if((!isCombat && AllZoneUtil.isCardInPlay("Mark of Asylum", getController())))return 0; + + if((source.getController().isPlayer(getController()) && AllZoneUtil.isCardInPlay("Light of Sanction", getController()))) + return 0; + + if (AllZoneUtil.isCardInPlay("Plated Pegasus") && source.isSpell() + && restDamage > 0) restDamage = restDamage - 1; + } //Creature end + + if (AllZoneUtil.isCardInPlay("Energy Storm") && source.isSpell()) return 0; + + return restDamage; } public int preventDamage(final int damage, Card source, boolean isCombat) { int restDamage = damage; - if (AllZoneUtil.isCardInPlay("Energy Storm") && source.isSpell()) return 0; - - if( preventAllDamageToCard(source, isCombat)) { - return 0; - } - - if (AllZoneUtil.isCardInPlay("Plated Pegasus") && source.isSpell() - && restDamage > 0) restDamage = restDamage - 1; + restDamage = staticDamagePrevention(restDamage, source, isCombat); if(restDamage >= preventNextDamage) { restDamage = restDamage - preventNextDamage; diff --git a/src/forge/CardFactoryUtil.java b/src/forge/CardFactoryUtil.java index 61fe0622afb..09e86a48dd5 100644 --- a/src/forge/CardFactoryUtil.java +++ b/src/forge/CardFactoryUtil.java @@ -454,7 +454,7 @@ public class CardFactoryUtil { //Battle stats increasing keywords if (c.hasKeyword("Double Strike")) value += power * 15; - value += c.getKeywordMagnitute("Bushido") * 20; + value += c.getKeywordMagnitude("Bushido") * 20; value += c.getAmountOfKeyword("Flanking") * 20; //Other good keywords @@ -465,8 +465,8 @@ public class CardFactoryUtil { if (c.hasKeyword("Trample")) value += power * 3; if (c.hasKeyword("Vigilance")) value += power * 5 + toughness * 5; if (c.hasKeyword("Wither")) value += power * 10; - value += c.getKeywordMagnitute("Rampage"); - value += c.getKeywordMagnitute("Annihilator") * 30; + value += c.getKeywordMagnitude("Rampage"); + value += c.getKeywordMagnitude("Annihilator") * 30; if (c.hasKeyword("Changeling")) value += 5; if (c.hasKeyword("Whenever CARDNAME becomes blocked by a creature, destroy that creature at end of combat") && power > 0) value += 15; if (c.hasKeyword("Whenever a creature dealt damage by CARDNAME this turn is put into a graveyard, put a +1/+1 counter on CARDNAME.") && power > 0) value += 2; @@ -4495,19 +4495,6 @@ public class CardFactoryUtil { return list; } - public static int getTotalBushidoMagnitude(Card c) { - int count = 0; - ArrayList keywords = c.getKeyword(); - for(String kw:keywords) { - if(kw.contains("Bushido")) { - String[] parse = kw.split(" "); - String s = parse[1]; - count += Integer.parseInt(s); - } - } - return count; - } - public static ArrayList getBushidoEffects(Card c) { ArrayList keywords = c.getKeyword(); ArrayList list = new ArrayList(); diff --git a/src/forge/CombatUtil.java b/src/forge/CombatUtil.java index 25a08e87dcb..a57b4c343ef 100644 --- a/src/forge/CombatUtil.java +++ b/src/forge/CombatUtil.java @@ -471,8 +471,8 @@ public class CombatUtil { if(!CardFactoryUtil.canDamage(defender, attacker)) return false; - int defBushidoMagnitude = CardFactoryUtil.getTotalBushidoMagnitude(defender); - int attBushidoMagnitude = CardFactoryUtil.getTotalBushidoMagnitude(attacker); + int defBushidoMagnitude = defender.getKeywordMagnitude("Bushido"); + int attBushidoMagnitude = attacker.getKeywordMagnitude("Bushido"); int defenderDamage = defender.getNetAttack() - flankingMagnitude + defBushidoMagnitude; int attackerDamage = attacker.getNetAttack() + attBushidoMagnitude; @@ -576,8 +576,8 @@ public class CombatUtil { if(!CardFactoryUtil.canDamage(attacker,defender)) return false; - int defBushidoMagnitude = CardFactoryUtil.getTotalBushidoMagnitude(defender); - int attBushidoMagnitude = CardFactoryUtil.getTotalBushidoMagnitude(attacker); + int defBushidoMagnitude = defender.getKeywordMagnitude("Bushido"); + int attBushidoMagnitude = attacker.getKeywordMagnitude("Bushido"); int defenderDamage = defender.getNetAttack() - flankingMagnitude + defBushidoMagnitude; int attackerDamage = attacker.getNetAttack() + attBushidoMagnitude; diff --git a/src/forge/Player.java b/src/forge/Player.java index 640df831e74..f5838551bb7 100644 --- a/src/forge/Player.java +++ b/src/forge/Player.java @@ -218,42 +218,22 @@ public abstract class Player extends MyObservable{ GameActionUtil.executePlayerDamageEffects(this, source, damageToDo, false); } - public boolean preventAllDamageToPlayer(final Card source, final boolean isCombat) { - boolean reduce = false; + //This should be also usable by the AI to forecast an effect (so it must not change the game state) + public int staticDamagePrevention(final int damage, final Card source, final boolean isCombat) { + int restDamage = damage; if(isCombat) { - reduce = reduce || source.getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME."); - reduce = reduce || source.getKeyword().contains("Prevent all combat damage that would be dealt by CARDNAME."); + if(source.getKeyword().contains("Prevent all combat damage that would be dealt to and dealt by CARDNAME.")) return 0; + if(source.getKeyword().contains("Prevent all combat damage that would be dealt by CARDNAME.")) return 0; + if (AllZoneUtil.isCardInPlay("Purity", this)) return 0; } - reduce = reduce || source.getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME."); - reduce = reduce || source.getKeyword().contains("Prevent all damage that would be dealt by CARDNAME."); - - //Spirit of Resistance - if(AllZoneUtil.isCardInPlay("Spirit of Resistance", this)) { - if( AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Black).size() > 0 - && AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Blue).size() > 0 - && AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Green).size() > 0 - && AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Red).size() > 0 - && AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.White).size() > 0) { - reduce = true; - } - } - return reduce; - } - - public int preventDamage(final int damage, Card source, boolean isCombat) { - int restDamage = damage; + if(source.getKeyword().contains("Prevent all damage that would be dealt to and dealt by CARDNAME.")) return 0; + if(source.getKeyword().contains("Prevent all damage that would be dealt by CARDNAME.")) return 0; - if (AllZoneUtil.isCardInPlay("Purity", this) && !isCombat) { - gainLife(restDamage,null); - return 0; - } + + //specific cards if (AllZoneUtil.isCardInPlay("Energy Storm") && source.isSpell()) return 0; - if( preventAllDamageToPlayer(source, isCombat)) { - return 0; - } - if (AllZoneUtil.isCardInPlay("Spirit of Resistance", this) && !source.getController().equals(this) && restDamage > 0) restDamage = restDamage - 1; @@ -283,6 +263,29 @@ public abstract class Player extends MyObservable{ else return 0; } if (AllZoneUtil.isCardInPlay("Urza's Armor", this) && restDamage > 0) restDamage = restDamage - 1; + + if(AllZoneUtil.isCardInPlay("Spirit of Resistance", this)) { + if( AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Black).size() > 0 + && AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Blue).size() > 0 + && AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Green).size() > 0 + && AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.Red).size() > 0 + && AllZoneUtil.getPlayerColorInPlay(this, Constant.Color.White).size() > 0) { + return 0; + } + } + return restDamage; + } + + public int preventDamage(final int damage, Card source, boolean isCombat) { + int restDamage = damage; + + // Purity has to stay here because it changes the game state + if (AllZoneUtil.isCardInPlay("Purity", this) && !isCombat) { + gainLife(restDamage,null); + return 0; + } + + restDamage = staticDamagePrevention(restDamage, source, isCombat); if(restDamage >= preventNextDamage) {