diff --git a/.gitattributes b/.gitattributes index 3780bd6b31d..8b307bca5f0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5898,6 +5898,7 @@ src/forge/AbilityFactory_GainControl.java -text svneol=native#text/plain src/forge/AbilityFactory_PermanentState.java -text svneol=native#text/plain src/forge/AbilityFactory_Pump.java -text svneol=native#text/plain src/forge/AbilityFactory_Regenerate.java -text svneol=native#text/plain +src/forge/AbilityFactory_Sacrifice.java -text svneol=native#text/plain src/forge/AbilityFactory_Token.java -text svneol=native#text/plain src/forge/AbilityFactory_ZoneAffecting.java -text svneol=native#text/plain src/forge/Ability_Activated.java svneol=native#text/plain diff --git a/res/cardsfolder/coastal_hornclaw.txt b/res/cardsfolder/coastal_hornclaw.txt index 6fa0a886b68..56f92b11d67 100644 --- a/res/cardsfolder/coastal_hornclaw.txt +++ b/res/cardsfolder/coastal_hornclaw.txt @@ -3,6 +3,7 @@ ManaCost:4 U Types:Creature Bird Text:no text PT:3/3 +A:AB$Pump | Cost$ Sac<1/Land> | KW$ Flying | SpellDescription$ CARDNAME gains flying until end of turn. SVar:Rarity:Common SVar:Picture:http://resources.wizards.com/magic/cards/pr/en-us/card24574.jpg SetInfo:8ED|Common|http://magiccards.info/scans/en/8e/66.jpg diff --git a/res/cardsfolder/diabolic_edict.txt b/res/cardsfolder/diabolic_edict.txt index f558a2401f8..1cea56082f6 100644 --- a/res/cardsfolder/diabolic_edict.txt +++ b/res/cardsfolder/diabolic_edict.txt @@ -1,7 +1,8 @@ Name:Diabolic Edict ManaCost:1 B Types:Instant -Text:Target player sacrifices a creature. +Text:no text +A:SP$Sacrifice | Cost$ 1 B | ValidTgts$ Player | SacValid$ Creature | SacMessage$ Creature | SpellDescription$ Target player sacrifices a creature. SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/diabolic_edict.jpg SetInfo:TMP|Common|http://magiccards.info/scans/en/tp/22.jpg diff --git a/src/forge/AbilityFactory.java b/src/forge/AbilityFactory.java index cd5fee1272c..1b6a17afada 100644 --- a/src/forge/AbilityFactory.java +++ b/src/forge/AbilityFactory.java @@ -106,8 +106,12 @@ public class AbilityFactory { for (int aaCnt = 0; aaCnt < aa.length; aaCnt ++) aa[aaCnt] = aa[aaCnt].trim(); - if (!(aa.length == 2)) - throw new RuntimeException("AbilityFactory : getAbility -- aa.length not 2 in " + hostCard.getName()); + if (aa.length != 2){ + StringBuilder sb = new StringBuilder(); + sb.append("AbilityFactory Parsing Error in getAbility() : Split length of "); + sb.append(a[i]).append(" in ").append(hostCard.getName()).append(" is not 2."); + throw new RuntimeException(sb.toString()); + } mapParams.put(aa[0], aa[1]); } @@ -321,6 +325,15 @@ public class AbilityFactory { SA = AbilityFactory_ZoneAffecting.createDrawbackMill(this); } + if (API.equals("Sacrifice")){ + if (isAb) + SA = AbilityFactory_Sacrifice.createAbilitySacrifice(this); + else if (isSp) + SA = AbilityFactory_Sacrifice.createSpellSacrifice(this); + else if (isDb) + SA = AbilityFactory_Sacrifice.createDrawbackSacrifice(this); + } + if (API.equals("Destroy")){ if (isAb) SA = AbilityFactory_Destroy.createAbilityDestroy(this); @@ -374,13 +387,14 @@ public class AbilityFactory { SA = c.getSpellCounter(this); } - if (SA != null){ - if(hasSubAbility()) - SA.setSubAbility(getSubAbility()); - } - + if (SA == null) + throw new RuntimeException("AbilityFactory : SpellAbility was not created. Did you add the API section?"); + // ********************************************* // set universal properties of the SpellAbility + if(hasSubAbility()) + SA.setSubAbility(getSubAbility()); + if (hasSpDesc) { StringBuilder sb = new StringBuilder(); @@ -391,7 +405,7 @@ public class AbilityFactory { sb.append(mapParams.get("CostDesc")).append(" "); else sb.append(abCost.toString()); - sb.append(mapParams.get("SpellDescription")); + sb.append(mapParams.get("SpellDescription")); SA.setDescription(sb.toString()); } diff --git a/src/forge/AbilityFactory_Sacrifice.java b/src/forge/AbilityFactory_Sacrifice.java new file mode 100644 index 00000000000..c4e5e2a0124 --- /dev/null +++ b/src/forge/AbilityFactory_Sacrifice.java @@ -0,0 +1,259 @@ +package forge; + +import java.util.ArrayList; +import java.util.HashMap; + +public class AbilityFactory_Sacrifice { + //************************************************************** + // ****************************** FOG ************************** + //************************************************************** + + public static SpellAbility createAbilitySacrifice(final AbilityFactory AF){ + final SpellAbility abSacrifice = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()){ + private static final long serialVersionUID = -1933592438783630254L; + + final AbilityFactory af = AF; + + public boolean canPlayAI() + { + return sacrificeCanPlayAI(af, this); + } + + @Override + public void resolve() { + sacrificeResolve(af, this); + } + + public String getStackDescription(){ + return sacrificeDescription(af, this); + } + }; + return abSacrifice; + } + + public static SpellAbility createSpellSacrifice(final AbilityFactory AF){ + final SpellAbility spSacrifice = new Spell(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()){ + private static final long serialVersionUID = -5141246507533353605L; + + final AbilityFactory af = AF; + + public boolean canPlayAI() + { + return sacrificeCanPlayAI(af, this); + } + + @Override + public void resolve() { + sacrificeResolve(af, this); + } + + public String getStackDescription(){ + return sacrificeDescription(af, this); + } + }; + return spSacrifice; + } + + public static SpellAbility createDrawbackSacrifice(final AbilityFactory AF){ + final SpellAbility dbSacrifice = new Ability_Sub(AF.getHostCard(), AF.getAbTgt()){ + private static final long serialVersionUID = -5141246507533353605L; + + final AbilityFactory af = AF; + + @Override + public void resolve() { + sacrificeResolve(af, this); + } + + @Override + public boolean chkAI_Drawback() { + return sacrificePlayDrawbackAI(af, this); + } + + public String getStackDescription(){ + return sacrificeDescription(af, this); + } + }; + return dbSacrifice; + } + + public static String sacrificeDescription(final AbilityFactory af, SpellAbility sa){ + StringBuilder sb = new StringBuilder(); + + if (sa instanceof Ability_Sub) + sb.append(" "); + else + sb.append(sa.getSourceCard().getName()).append(" - "); + + Target tgt = af.getAbTgt(); + if (tgt == null){ + return sa.toString(); + } + String valid = af.getMapParams().get("SacValid"); + String num = af.getMapParams().get("Amount"); + num = (num == null) ? "1" : num; + int amount = AbilityFactory.calculateAmount(sa.getSourceCard(), num, sa); + + + for(Player p : tgt.getTargetPlayers()) + sb.append(p.getName()).append(" "); + + String msg = af.getMapParams().get("SacMessage"); + if (msg == null) + msg = valid; + + sb.append("Sacrifices ").append(amount).append(" ").append(msg); + + return sb.toString(); + } + + public static boolean sacrificeCanPlayAI(final AbilityFactory af, SpellAbility sa){ + // AI should only activate this during Human's Declare Blockers phase + boolean chance = sacrificeTgtAI(af, sa); + + // Some additional checks based on what is being sacrificed, and who is sacrificing + Target tgt = af.getAbTgt(); + if (tgt != null){ + String valid = af.getMapParams().get("SacValid"); + String num = af.getMapParams().get("Amount"); + num = (num == null) ? "1" : num; + int amount = AbilityFactory.calculateAmount(sa.getSourceCard(), num, sa); + + CardList list = AllZoneUtil.getPlayerCardsInPlay(AllZone.HumanPlayer); + list = list.getValidCards(valid.split(","), sa.getActivatingPlayer(), sa.getSourceCard()); + + if (list.size() == 0) + return false; + + int half = amount / 2 + amount % 2; // Half of amount rounded up + + // If the Human has at least half rounded up of the amount to be sacrificed, cast the spell + if (list.size() < half) + return false; + + return true; + } + + Ability_Sub subAb = sa.getSubAbility(); + if (subAb != null) + chance &= subAb.chkAI_Drawback(); + + return chance; + } + + public static boolean sacrificePlayDrawbackAI(final AbilityFactory af, SpellAbility sa){ + // AI should only activate this during Human's turn + boolean chance = sacrificeTgtAI(af, sa); + + // todo: restrict the subAbility a bit + + Ability_Sub subAb = sa.getSubAbility(); + if (subAb != null) + chance &= subAb.chkAI_Drawback(); + + return chance; + } + + public static boolean sacrificeTgtAI(AbilityFactory af, SpellAbility sa){ + Target tgt = af.getAbTgt(); + if (tgt != null){ + tgt.resetTargets(); + if (AllZone.HumanPlayer.canTarget(sa.getSourceCard())) + tgt.addTarget(AllZone.HumanPlayer); + else + return false; + } + else{ + String defined = af.getMapParams().get("Defined"); + if (defined == null){ + // Self Sacrifice. + } + else if (defined.equals("Each")){ + // If Sacrifice hits both players: + // Don't cast it if Human doesn't have any of valid + // Definitely cast it if AI doesn't have any of Valid + // Cast if the type is favorable: my "worst" valid is worse than his "worst" valid + } + } + + return true; + } + + public static void sacrificeResolve(final AbilityFactory af, final SpellAbility sa){ + HashMap params = af.getMapParams(); + Card card = sa.getSourceCard(); + String DrawBack = params.get("SubAbility"); + + // Expand Fog keyword here depending on what we need out of it. + String num = params.containsKey("Amount") ? params.get("Amount") : "1"; + int amount = AbilityFactory.calculateAmount(card, num, sa); + + Target tgt = af.getAbTgt(); + ArrayList tgts; + if (tgt != null){ + tgts = tgt.getTargets(); + } + else{ + tgts = new ArrayList(); + String defined = params.get("Defined"); + if (defined == null) // Self + tgts.add(sa.getActivatingPlayer()); + else{ + if (defined.equals("Each")){ + tgts.add(sa.getActivatingPlayer()); + tgts.add(sa.getActivatingPlayer().getOpponent()); + } + else if (defined.equals("Targeted")){ + SpellAbility parent; + do{ + parent = ((Ability_Sub)sa).getParent(); + }while(parent.getTarget() == null && parent.getTarget().getTargetPlayers().size() == 0); + + tgts.addAll(parent.getTarget().getTargetPlayers()); + } + } + } + + String valid = params.get("SacValid"); + + String msg = params.get("SacMessage"); + if (msg == null) + msg = valid; + + msg = "Sacrifice a " + msg; + + for(Object o : tgts){ + Player p = (Player)o; + if (p.isComputer()) + sacrificeAI(p, amount, valid, sa); + else + sacrificeHuman(p, amount, valid, sa, msg); + } + + + if (af.hasSubAbility()){ + Ability_Sub abSub = sa.getSubAbility(); + if (abSub != null){ + abSub.resolve(); + } + else + CardFactoryUtil.doDrawBack(DrawBack, 0, card.getController(), card.getController().getOpponent(), card.getController(), card, null, sa); + } + } + + + private static void sacrificeAI(Player p, int amount, String valid, SpellAbility sa){ + CardList list = AllZoneUtil.getPlayerCardsInPlay(p); + list = list.getValidCards(valid.split(","), sa.getActivatingPlayer(), sa.getSourceCard()); + + ComputerUtil.sacrificePermanents(amount, list); + } + + private static void sacrificeHuman(Player p, int amount, String valid, SpellAbility sa, String message){ + CardList list = AllZoneUtil.getPlayerCardsInPlay(p); + list = list.getValidCards(valid.split(","), sa.getActivatingPlayer(), sa.getSourceCard()); + + AllZone.InputControl.setInput(CardFactoryUtil.input_sacrificePermanentsFromList(amount, list, message)); + } + +} \ No newline at end of file diff --git a/src/forge/CardFactoryUtil.java b/src/forge/CardFactoryUtil.java index 04795b3012c..df36d3988ca 100644 --- a/src/forge/CardFactoryUtil.java +++ b/src/forge/CardFactoryUtil.java @@ -757,105 +757,29 @@ public class CardFactoryUtil { }; return target; }//input_targetPermanent() - - //CardList choices are the only cards the user can successful select - //sacrifices one of the CardList choices - public static Input input_sacrifice(final SpellAbility spell, final CardList choices, final String message) { + + public static Input input_destroyNoRegeneration(final CardList choices, final String message) { Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - - @Override + private static final long serialVersionUID = -6637588517573573232L; + + @Override public void showMessage() { AllZone.Display.showMessage(message); - ButtonUtil.enableOnlyCancel(); - } - - @Override - public void selectButtonCancel() { - stop(); + ButtonUtil.disableAll(); } @Override public void selectCard(Card card, PlayerZone zone) { if(choices.contains(card)) { - AllZone.getZone(card).remove(card); - AllZone.GameAction.moveToGraveyard(card); - - if(spell.getManaCost().equals("0") || this.isFree()) { - this.setFree(false); - AllZone.Stack.add(spell, spell.getSourceCard().getManaCost().contains("X")); - stop(); - } else stopSetNext(new Input_PayManaCost(spell)); + AllZone.GameAction.destroyNoRegeneration(card); + stop(); } } }; return target; - }//input_sacrifice() - - public static Input input_sacrificeThis(final SpellAbility spell) { - Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - - @Override - public void showMessage() { - Card card = spell.getSourceCard(); - String[] choices = {"Yes", "No"}; - if(card.getController().equals(AllZone.HumanPlayer)) { - Object o = AllZone.Display.getChoice("Sacrifice " + card.getName() + " ?", choices); - if(o.equals("Yes")) { - sacrifice(card); - } - else{ - //undo? - stop(); - } - } - } - - public void sacrifice(Card card) - { - AllZone.GameAction.sacrifice(card); - stop(); - AllZone.Stack.add(spell); - } - }; - return target; - }//input_sacrifice() - - public static Input input_sacrificeType(final SpellAbility spell, final String type, final String message) { - // This input should be setAfterManaPaid so it can add the spell to the stack - Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - private CardList typeList; - - @Override - public void showMessage() { - PlayerZone play = AllZone.getZone(Constant.Zone.Play, spell.getSourceCard().getController()); - typeList = new CardList(play.getCards()); - typeList = typeList.getType(type); - AllZone.Display.showMessage(message); - ButtonUtil.enableOnlyCancel(); - } - - @Override - public void selectButtonCancel() { - stop(); - } - - @Override - public void selectCard(Card card, PlayerZone zone) { - if(typeList.contains(card)) { - AllZone.GameAction.sacrifice(card); - AllZone.Stack.add(spell); - stop(); - } - } - }; - return target; - }//input_sacrificeType() - - + }//input_destroyNoRegeneration() + public static Input Wheneverinput_sacrifice(final SpellAbility spell, final CardList choices, final String message, final Command Paid) { Input target = new Input() { private static final long serialVersionUID = 2685832214519141903L; @@ -883,43 +807,7 @@ public class CardFactoryUtil { }; return target; }//Wheneverinput_sacrifice() - - public static Input input_sacrifice(final SpellAbility spell, final CardList choices, final String message, final boolean free) { - Input target = new Input() { - private static final long serialVersionUID = 3391527854483291332L; - - @Override - public void showMessage() { - AllZone.Display.showMessage(message); - ButtonUtil.enableOnlyCancel(); - } - - @Override - public void selectButtonCancel() { - stop(); - } - - @Override - public void selectCard(Card card, PlayerZone zone) { - if(choices.contains(card)) { - AllZone.getZone(card).remove(card); - AllZone.GameAction.moveToGraveyard(card); - - if (free) - this.setFree(true); - - if(spell.getManaCost().equals("0") || this.isFree()) { - this.setFree(false); - AllZone.Stack.add(spell, spell.getSourceCard().getManaCost().contains("X")); - stop(); - } else stopSetNext(new Input_PayManaCost(spell)); - } - } - }; - return target; - }//input_sacrifice() - //this one is used for Phyrexian War Beast: public static Input input_sacrificePermanent(final SpellAbility spell, final CardList choices, final String message) { Input target = new Input() { @@ -954,94 +842,25 @@ public class CardFactoryUtil { return target; }//input_sacrifice() - public static Input input_sacrificePermanent(final CardList choices, final String message) { - Input target = new Input() { - private static final long serialVersionUID = 2685832214519141903L; - - @Override - public void showMessage() { - if(choices.size() == 0) stop(); - AllZone.Display.showMessage(message); - ButtonUtil.disableAll(); - } - - @Override - public void selectCard(Card card, PlayerZone zone) { - if(choices.contains(card)) { - AllZone.GameAction.sacrifice(card); - stop(); - } - } - }; - return target; + return input_sacrificePermanentsFromList(1, choices, "Select a permanent to sacrifice"); }//input_sacrifice() - public static Input input_destroyNoRegeneration(final CardList choices, final String message) { - Input target = new Input() { - private static final long serialVersionUID = -6637588517573573232L; - - @Override - public void showMessage() { - AllZone.Display.showMessage(message); - ButtonUtil.disableAll(); - } - - @Override - public void selectCard(Card card, PlayerZone zone) { - if(choices.contains(card)) { - AllZone.GameAction.destroyNoRegeneration(card); - stop(); - } - } - }; - return target; - }//input_destroyNoRegeneration() - public static Input input_sacrificePermanents(final int nCards) { - Input target = new Input() { - private static final long serialVersionUID = -8149416676562317629L; - int n = 0; - - @Override - public void showMessage() { - CardList list = new CardList(AllZone.Human_Play.getCards()); - list = list.filter(new CardListFilter(){ - public boolean addCard(Card c) - { - return c.isPermanent() && !c.getName().equals("Mana Pool"); - } - }); - if(n == nCards || list.size() == 0) stop(); - - AllZone.Display.showMessage("Select a permanent to sacrifice (" +(nCards-n) +" left)"); - ButtonUtil.disableAll(); - } - - @Override - public void selectCard(Card card, PlayerZone zone) { - if(zone.equals(AllZone.Human_Play) && !card.getName().equals("Mana Pool")) { - AllZone.GameAction.sacrifice(card); - n++; - - //in case no more {type}s in play - CardList list = new CardList(AllZone.Human_Play.getCards()); - list = list.filter(new CardListFilter(){ - public boolean addCard(Card c) - { - return c.isPermanent() && !c.getName().equals("Mana Pool"); - } - }); - if(n == nCards || list.size() == 0) stop(); - else - showMessage(); - } - } - }; - return target; + CardList list = AllZoneUtil.getPlayerCardsInPlay(AllZone.HumanPlayer); + list.remove("Mana Pool"); // is this needed? + return input_sacrificePermanentsFromList(nCards, list, "Select a permanent to sacrifice"); }//input_sacrificePermanents() public static Input input_sacrificePermanents(final int nCards, final String type) { + CardList list = AllZoneUtil.getPlayerCardsInPlay(AllZone.HumanPlayer); + list.remove("Mana Pool"); // is this needed? + + list = list.getType(type); + return input_sacrificePermanentsFromList(nCards, list, "Select a " +type +" to sacrifice"); + }//input_sacrificePermanents() + + public static Input input_sacrificePermanentsFromList(final int nCards, final CardList list, final String message) { Input target = new Input() { private static final long serialVersionUID = 1981791992623774490L; int n = 0; @@ -1049,23 +868,20 @@ public class CardFactoryUtil { @Override public void showMessage() { //in case no more {type}s in play - CardList list = new CardList(AllZone.Human_Play.getCards()); - list = list.getType(type); if(n == nCards || list.size() == 0) stop(); - AllZone.Display.showMessage("Select a " +type +" to sacrifice (" +(nCards-n) +" left)"); + AllZone.Display.showMessage(message + " (" +(nCards-n) +" left)"); ButtonUtil.disableAll(); } @Override public void selectCard(Card card, PlayerZone zone) { - if(zone.equals(AllZone.Human_Play) && card.getType().contains(type)) { + if(zone.equals(AllZone.Human_Play) && list.contains(card)) { AllZone.GameAction.sacrifice(card); n++; + list.remove(card); //in case no more {type}s in play - CardList list = new CardList(AllZone.Human_Play.getCards()); - list = list.getType(type); if(n == nCards || list.size() == 0) stop(); else showMessage(); diff --git a/src/forge/CardFactory_Creatures.java b/src/forge/CardFactory_Creatures.java index 7843a19247b..14bd6bc7c28 100644 --- a/src/forge/CardFactory_Creatures.java +++ b/src/forge/CardFactory_Creatures.java @@ -7064,76 +7064,14 @@ public class CardFactory_Creatures { }//*************** END ************ END ************************** - //*************** START *********** START ************************** - else if(cardName.equals("Coastal Hornclaw")) { - //sacrifice ability - targets itself - until EOT - final Command untilEOT = new Command() { - private static final long serialVersionUID = 7538741250040204529L; - - public void execute() { - card.removeIntrinsicKeyword("Flying"); - } - }; - - //mana tap ability - final Ability ability = new Ability(card, "0") { - @Override - public boolean canPlayAI() { - CardList land = new CardList(AllZone.Computer_Play.getCards()); - land = land.getType("Land"); - - return (land.size() != 0) && (!card.getKeyword().contains("Flying")) - && CardFactoryUtil.AI_getHumanCreature("Flying", card, false).isEmpty() - && (!card.hasSickness()) && (AllZone.Phase.getPhase().equals(Constant.Phase.Main1)); - } - - @Override - public void chooseTargetAI() { - CardList land = new CardList(AllZone.Computer_Play.getCards()); - land = land.getType("Land"); - land.shuffle(); - AllZone.GameAction.sacrifice(land.get(0)); - } - - @Override - public void resolve() { - if(AllZone.GameAction.isCardInPlay(card)) { - card.addIntrinsicKeyword("Flying"); - AllZone.EndOfTurn.addUntil(untilEOT); - } - }//resolve() - };//SpellAbility - - - Input runtime = new Input() { - private static final long serialVersionUID = 4874019210748846864L; - - @Override - public void showMessage() { - StringBuilder sb = new StringBuilder(); - sb.append(card).append(" gains flying until EOT."); - ability.setStackDescription(sb.toString()); - - PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController()); - CardList choice = new CardList(play.getCards()); - choice = choice.getType("Land"); - stopSetNext(CardFactoryUtil.input_sacrifice(ability, choice, "Select a land to sacrifice.")); - } - }; - StringBuilder sb = new StringBuilder(); - sb.append(card).append(" gains flying until end of turn."); - ability.setStackDescription(sb.toString()); - - ability.setDescription("Sacrifice a land: Coastal Hornclaw gains flying until end of turn."); - card.addSpellAbility(ability); - ability.setBeforePayMana(runtime); - }//*************** END ************ END ************************** - - //*************** START *********** START ************************** else if(cardName.equals("Spitting Spider")) { - final Ability ability = new Ability(card, "0") { - @Override + // temporary fix until DamageAll is created + Ability_Cost abCost = new Ability_Cost("Sac<1/Land>", cardName, true); + final SpellAbility ability = new Ability_Activated(card, abCost, null) { + private static final long serialVersionUID = 2560268493829888869L; + + @Override public boolean canPlayAI() { return false; } @@ -7147,25 +7085,12 @@ public class CardFactory_Creatures { }//resolve() };//SpellAbility - Input runtime = new Input() { - private static final long serialVersionUID = 2004031367305867525L; - - @Override - public void showMessage() { - - PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController()); - CardList choice = new CardList(play.getCards()); - choice = choice.getType("Land"); - stopSetNext(CardFactoryUtil.input_sacrifice(ability, choice, "Select a land to sacrifice.")); - } - }; StringBuilder sb = new StringBuilder(); sb.append(card).append(" deals 1 damage to each creature with flying."); ability.setStackDescription(sb.toString()); - ability.setDescription("Sacrifice a land: Spitting Spider deals 1 damage to each creature with flying."); + card.addSpellAbility(ability); - ability.setBeforePayMana(runtime); }//*************** END ************ END ************************** diff --git a/src/forge/CardFactory_Instants.java b/src/forge/CardFactory_Instants.java index 6014634f831..dca739b1e1e 100644 --- a/src/forge/CardFactory_Instants.java +++ b/src/forge/CardFactory_Instants.java @@ -3146,35 +3146,6 @@ public class CardFactory_Instants { return card; }//*************** END ************ END ************************** - - - //*************** START *********** START ************************** - else if(cardName.equals("Diabolic Edict") ) { - final SpellAbility spell = new Spell(card) { - - private static final long serialVersionUID = 1593405082929818055L; - - @Override - public void resolve() { - getTargetPlayer().sacrificeCreature(); - } - - @Override - public boolean canPlayAI() { - PlayerZone hPlay = AllZone.getZone(Constant.Zone.Play, AllZone.HumanPlayer); - CardList hList = new CardList(hPlay.getCards()); - hList = hList.getType("Creature"); - return hList.size() > 0; - } - }; - spell.setChooseTargetAI(CardFactoryUtil.AI_targetHuman()); - spell.setBeforePayMana(CardFactoryUtil.input_targetPlayer(spell)); - - card.clearSpellAbility(); - card.addSpellAbility(spell); - - }//*************** END ************ END ************************** - //*************** START *********** START ************************** else if(cardName.equals("Path to Exile")) { diff --git a/src/forge/CombatUtil.java b/src/forge/CombatUtil.java index ce3e04f3743..bde2c742d80 100644 --- a/src/forge/CombatUtil.java +++ b/src/forge/CombatUtil.java @@ -1009,14 +1009,7 @@ public class CombatUtil { if (crd.getController().isHuman()) { CardList list = new CardList(AllZone.Computer_Play.getCards()); - CardListUtil.sortCMC(list); - list.reverse(); - int max = list.size(); - if (max>a) - max = a; - - for (int i=0;i amount) + max = amount; + + CardListUtil.sortCMC(list); + list.reverse(); + + for (int i = 0; i < max; i++) { + // todo: use getWorstPermanent() would be wayyyy better + + Card c; + if (list.getNotType("Creature").size() == 0) { + c = CardFactoryUtil.AI_getWorstCreature(list); + } else if (list.getNotType("Land").size() == 0) { + c = CardFactoryUtil.getWorstLand(AllZone.ComputerPlayer); + } else { + c = list.get(0); + } + + ArrayList auras = c.getEnchantedBy(); + + if (auras.size() > 0){ + // todo: choose "worst" controlled enchanting Aura + for(int j = 0; j < auras.size(); j++){ + Card aura = auras.get(j); + if (aura.getController().isPlayer(c.getController()) && list.contains(aura)){ + c = aura; + break; + } + } + } + + list.remove(c); + AllZone.GameAction.sacrifice(c); + } + } } \ No newline at end of file