From f9d481d5a69f5f0eb6d956746c240effe9684434 Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 08:57:11 +0000 Subject: [PATCH] Third draft of AbilityFactory. Overwrites changes in AbilityFactory from r2620. Renamed DealDamage to AbilityFactory_DealDamage. Now supports the spell version. (Shock) All static modifiers removed. Added support for Buyback in the CardFactory handler for AbilityFactory cards. --- .gitattributes | 1 + res/cardsfolder/prodigal_pyromancer.txt | 2 +- res/cardsfolder/shock.txt | 3 +- src/forge/AbilityFactory.java | 101 +++++----- src/forge/AbilityFactory_DealDamage.java | 233 +++++++++++++++++++++++ src/forge/CardFactory.java | 26 ++- 6 files changed, 306 insertions(+), 60 deletions(-) create mode 100644 src/forge/AbilityFactory_DealDamage.java diff --git a/.gitattributes b/.gitattributes index ffbac47e602..b5db6f0c0ec 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5053,6 +5053,7 @@ src/com/esotericsoftware/minlog/Log.java svneol=native#text/plain src/forge/Ability.java svneol=native#text/plain src/forge/AbilityFactory.java -text svneol=native#text/plain src/forge/AbilityFactory_Counters.java -text svneol=native#text/plain +src/forge/AbilityFactory_DealDamage.java -text svneol=native#text/plain src/forge/Ability_Activated.java svneol=native#text/plain src/forge/Ability_Cost.java -text svneol=native#text/plain src/forge/Ability_Hand.java svneol=native#text/plain diff --git a/res/cardsfolder/prodigal_pyromancer.txt b/res/cardsfolder/prodigal_pyromancer.txt index b508c508385..10a48bd288c 100644 --- a/res/cardsfolder/prodigal_pyromancer.txt +++ b/res/cardsfolder/prodigal_pyromancer.txt @@ -4,7 +4,7 @@ Types:Creature Human Wizard Text:no text PT:1/1 # K:abDamageTgtCP T:1 -A:AB$DealDamage|Cost$T|Tgt$TgtCP|NumDmg$1|SpellDescription$Deal 1 damage to target creature or player. +A:AB$DealDamage|Cost$T|Tgt$TgtCP|NumDmg$1|SpellDescription$Prodigal Pyromancer deals 1 damage to target creature or player. SVar:Rarity:Common SVar:Picture:http://resources.wizards.com/magic/cards/plc/en-us/card122338.jpg End diff --git a/res/cardsfolder/shock.txt b/res/cardsfolder/shock.txt index 5ac72942c79..a5ddc917eb4 100644 --- a/res/cardsfolder/shock.txt +++ b/res/cardsfolder/shock.txt @@ -2,7 +2,8 @@ Name:Shock ManaCost:R Types:Instant Text:no text -K:spDamageTgtCP:2 +# K:spDamageTgtCP:2 +A:SP$DealDamage|Cost$R|Tgt$TgtCP|NumDmg$2|SpellDescription$Shock deals 2 damage to target creature or player. SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/shock.jpg End diff --git a/src/forge/AbilityFactory.java b/src/forge/AbilityFactory.java index ddefbbde1fc..1c700f0a374 100644 --- a/src/forge/AbilityFactory.java +++ b/src/forge/AbilityFactory.java @@ -10,7 +10,7 @@ public class AbilityFactory { { return hostC; } - + private HashMap mapParams = new HashMap(); public HashMap getMapParams() @@ -57,11 +57,6 @@ public class AbilityFactory { return abTgt; } - private boolean isCurse = false; - public boolean isCurse(){ - return isCurse; - } - private boolean hasSubAb = false; public boolean hasSubAbility() @@ -69,14 +64,17 @@ public class AbilityFactory { return hasSubAb; } - private static boolean hasSpDesc = false; + private boolean hasSpDesc = false; public boolean hasSpDescription() { return hasSpDesc; } - public SpellAbility getAbility(String abString, final Card hostCard){ + //******************************************************* + + public SpellAbility getAbility(String abString, Card hostCard){ + SpellAbility SA = null; hostC = hostCard; @@ -99,19 +97,18 @@ public class AbilityFactory { mapParams.put(aa[0], aa[1]); } - String abAPI = ""; - String spAPI = ""; + // parse universal parameters - // additional ability types here + String API = ""; if (mapParams.containsKey("AB")) { isAb = true; - abAPI = mapParams.get("AB"); + API = mapParams.get("AB"); } else if (mapParams.containsKey("SP")) { isSp = true; - spAPI = mapParams.get("SP"); + API = mapParams.get("SP"); } else throw new RuntimeException("AbilityFactory : getAbility -- no API in " + hostCard.getName()); @@ -121,10 +118,14 @@ public class AbilityFactory { throw new RuntimeException("AbilityFactory : getAbility -- no Cost in " + hostCard.getName()); abCost = new Ability_Cost(mapParams.get("Cost"), hostCard.getName(), isAb); + if (mapParams.containsKey("ValidTgts")) { hasValid = true; isTargeted = true; + abTgt = new Target("TgtV"); + abTgt.setValidTgts(mapParams.get("ValidTgts").split(",")); + abTgt.setVTSelection(mapParams.get("TgtPrompt")); } if (mapParams.containsKey("ValidCards")) @@ -133,31 +134,18 @@ public class AbilityFactory { if (mapParams.containsKey("Tgt")) { isTargeted = true; + abTgt = new Target(mapParams.get("Tgt")); } - if (isTargeted) - { - if (hasValid) - abTgt = new Target("TgtV", mapParams.get("TgtPrompt"), mapParams.get("ValidTgts").split(",")); - else - abTgt = new Target(mapParams.get("Tgt")); - } - else{ - abTgt = null; - } - if (mapParams.containsKey("IsCurse")){ - isCurse = true; - } + hasSubAb = mapParams.containsKey("SubAbility"); - if (mapParams.containsKey("SubAbility")) - hasSubAb = true; - - if (mapParams.containsKey("SpellDescription")) - hasSpDesc = true; + hasSpDesc = mapParams.containsKey("SpellDescription"); - - if (abAPI.equals("DealDamage")) + // *********************************** + // Match API keywords + + if (API.equals("DealDamage")) { final int NumDmg[] = {-1}; final String NumDmgX[] = {"none"}; @@ -171,37 +159,42 @@ public class AbilityFactory { NumDmg[0] = Integer.parseInt(tmpND); } - if (isAb) - SA = DealDamage.getAbility(this, NumDmg[0], NumDmgX[0]); + AbilityFactory_DealDamage dd = new AbilityFactory_DealDamage(); + + if (isAb) + SA = dd.getAbility(this, NumDmg[0], NumDmgX[0]); else if (isSp) - SA = DealDamage.getSpell(this); + SA = dd.getSpell(this, NumDmg[0], NumDmgX[0]); } - // additional keywords here - if (abAPI.equals("PutCounter")){ - if (isAb) - SA = AbilityFactory_Counters.createAbilityPutCounters(this); - if (isSp){ - // todo: createSpellPutCounters - } - } + // additional API keywords here + + // ********************************************* // set universal properties of the SpellAbility - if (isSp){ - // Ability_Activated sets abTgt and abCost in the constructor so this only needs to be set for Spells - // Once Spells are more compatible with Tgt and abCost this block should be removed - if (isTargeted) - SA.setTarget(abTgt); - - SA.setPayCosts(abCost); - } + if (isTargeted) + { + //if (isAb) + SA.setTarget(abTgt); + + } + + //if (isAb) + SA.setPayCosts(abCost); if (hasSpDesc) - SA.setDescription(abCost.toString() + mapParams.get("SpellDescription")); + { + String desc = mapParams.get("SpellDescription"); + if (isAb) + desc = abCost.toString() + desc; + + SA.setDescription(desc); + } - return SA; + + return SA; } diff --git a/src/forge/AbilityFactory_DealDamage.java b/src/forge/AbilityFactory_DealDamage.java new file mode 100644 index 00000000000..46d91aa342a --- /dev/null +++ b/src/forge/AbilityFactory_DealDamage.java @@ -0,0 +1,233 @@ +package forge; + +import java.util.Random; + +public class AbilityFactory_DealDamage { + + private AbilityFactory AF = null; + + private AbilityFactory getAF(){ + return AF; + } + private int nDamage = -1; + + private String XDamage = "none"; + + private boolean TgtOpp = false; + + public SpellAbility getAbility(final AbilityFactory af, final int NumDmg, final String NumDmgX) + { + AF = af; + nDamage = NumDmg; + XDamage = NumDmgX; + + if (AF.getMapParams().get("Tgt").equals("TgtOpp")) + TgtOpp = true; + + final SpellAbility abDamage = new Ability_Activated(AF.getHostCard(), AF.getAbCost(), AF.getAbTgt()) + { + private static final long serialVersionUID = -7560349014757367722L; + + @Override + public boolean canPlay(){ + return (Cost_Payment.canPayAdditionalCosts(AF.getAbCost(), this) + && CardFactoryUtil.canUseAbility(AF.getHostCard()) + && super.canPlay()); + } + + @Override + public boolean canPlayAI() { + return doCanPlayAI(this); + + } + + @Override + public void resolve() { + doResolve(this); + AF.getHostCard().setAbilityUsed(AF.getHostCard().getAbilityUsed() + 1); + + } + };//Ability_Activated + + return abDamage; + } + + public SpellAbility getSpell(final AbilityFactory af, final int NumDmg, final String NumDmgX) + { + AF = af; + nDamage = NumDmg; + XDamage = NumDmgX; + + if (AF.getMapParams().get("Tgt").equals("TgtOpp")) + TgtOpp = true; + + final SpellAbility spDealDamage = new Spell(AF.getHostCard()) { + private static final long serialVersionUID = 7239608350643325111L; + + @Override + public boolean canPlay(){ + return (Cost_Payment.canPayAdditionalCosts(AF.getAbCost(), this) + && super.canPlay()); + } + + @Override + public boolean canPlayAI() { + return doCanPlayAI(this); + + } + + @Override + public void resolve() { + doResolve(this); + + } + + + }; // Spell + + return spDealDamage; + } + + private int getNumDamage() { + if(nDamage != -1) return nDamage; + + if(!XDamage.equals("none")) + return CardFactoryUtil.xCount(AF.getHostCard(), XDamage); + + return 0; + } + + private boolean shouldTgtP(int d) { + PlayerZone compHand = AllZone.getZone(Constant.Zone.Hand, Constant.Player.Computer); + CardList hand = new CardList(compHand.getCards()); + + if(AF.isSpell() && hand.size() > 7) // anti-discard-at-EOT + return true; + + if(AllZone.Human_Life.getLife() - d < 10) // if damage from this spell would drop the human to less than 10 life + return true; + + return false; + } + + private Card chooseTgtC(final int d) { + // Combo alert!! + PlayerZone compy = AllZone.getZone(Constant.Zone.Play, Constant.Player.Computer); + CardList cPlay = new CardList(compy.getCards()); + if(cPlay.size() > 0) for(int i = 0; i < cPlay.size(); i++) + if(cPlay.get(i).getName().equals("Stuffy Doll")) return cPlay.get(i); + + PlayerZone human = AllZone.getZone(Constant.Zone.Play, Constant.Player.Human); + CardList hPlay = new CardList(human.getCards()); + hPlay = hPlay.filter(new CardListFilter() { + public boolean addCard(Card c) { + // will include creatures already dealt damage + return c.isCreature() && ((c.getNetDefense() + c.getDamage()) <= d) + && CardFactoryUtil.canTarget(AF.getHostCard(), c); + } + }); + + if(hPlay.size() > 0) { + Card best = hPlay.get(0); + + if(hPlay.size() > 1) { + for(int i = 1; i < hPlay.size(); i++) { + Card b = hPlay.get(i); + // choose best overall creature? + if(b.getSpellAbility().length > best.getSpellAbility().length + || b.getKeyword().size() > best.getKeyword().size() + || b.getNetAttack() > best.getNetAttack()) best = b; + } + } + return best; + } + return null; + } + + private boolean doCanPlayAI(SpellAbility saMe) + { + // temporarily disabled until better AI + if (AF.getAbCost().getSacCost()) return false; + if (AF.getAbCost().getSubCounter()) return false; + if (AF.getAbCost().getLifeCost()) return false; + + if (!ComputerUtil.canPayCost(saMe)) + return false; + + int damage = getNumDamage(); + + boolean rr = false; + + if (AF.isAbility()) + { + Random r = new Random(); // prevent run-away activations + if(r.nextFloat() <= Math.pow(.6667, AF.getHostCard().getAbilityUsed())) + rr = true; + } + else if (AF.isSpell()) + rr = true; + + if(AF.getAbTgt().canTgtCreaturePlayer()) { + if(shouldTgtP(damage)) { + saMe.setTargetPlayer(Constant.Player.Human); + return rr; + } + + Card c = chooseTgtC(damage); + if(c != null) { + saMe.setTargetCard(c); + return rr; + } + } + + if(AF.getAbTgt().canTgtPlayer() || TgtOpp == true) { + saMe.setTargetPlayer(Constant.Player.Human); + return rr; + } + + if(AF.getAbTgt().canTgtCreature()) { + Card c = chooseTgtC(damage); + if(c != null) { + saMe.setTargetCard(c); + return rr; + } + } + return false; + + } + + private void doResolve(SpellAbility saMe) + { + int damage = getNumDamage(); + String tgtP = ""; + + if(TgtOpp == true) { + tgtP = AllZone.GameAction.getOpponent(AF.getHostCard().getController()); + saMe.setTargetPlayer(tgtP); + } + + Card c = saMe.getTargetCard(); + if(c != null) { + if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(AF.getHostCard(), c)) { + AllZone.GameAction.addDamage(c, AF.getHostCard(), damage); + tgtP = c.getController(); + + if(AF.hasSubAbility()) + CardFactoryUtil.doDrawBack(AF.getMapParams().get("SubAbility"), damage, + AF.getHostCard().getController(), AllZone.GameAction.getOpponent(AF.getHostCard().getController()), + tgtP, AF.getHostCard(), c, saMe); + + } + } else { + tgtP = saMe.getTargetPlayer(); + AllZone.GameAction.addDamage(tgtP, AF.getHostCard(), damage); + + if(AF.hasSubAbility()) + CardFactoryUtil.doDrawBack(AF.getMapParams().get("SubAbility"), damage, + AF.getHostCard().getController(), AllZone.GameAction.getOpponent(AF.getHostCard().getController()), + tgtP, AF.getHostCard(), null, saMe); + + } + + } +} diff --git a/src/forge/CardFactory.java b/src/forge/CardFactory.java index 76dc224ea08..639bc839e4f 100644 --- a/src/forge/CardFactory.java +++ b/src/forge/CardFactory.java @@ -6093,14 +6093,32 @@ public class CardFactory implements NewConstants { // AbilityFactory cards ArrayList IA = card.getIntrinsicAbilities(); if (IA.size() > 0) - { + { if (card.isInstant() || card.isSorcery()) card.clearSpellAbility(); - for (int i=0; i