From 56b718bde5642c1cc0b892e87e64e5b08a0d56cd Mon Sep 17 00:00:00 2001 From: jendave Date: Sat, 6 Aug 2011 17:10:30 +0000 Subject: [PATCH] - Laying some groundwork for DoTriggerAI() functions that will be used by the Trigger Controller instead of canPlayAI(). --- src/forge/AbilityFactory_AlterLife.java | 162 ++++++++--- src/forge/AbilityFactory_ChangeZone.java | 24 ++ src/forge/AbilityFactory_Combat.java | 45 ++- src/forge/AbilityFactory_CounterMagic.java | 6 + src/forge/AbilityFactory_Counters.java | 290 +++++++++++++------ src/forge/AbilityFactory_DealDamage.java | 24 ++ src/forge/AbilityFactory_Destroy.java | 18 ++ src/forge/AbilityFactory_GainControl.java | 6 + src/forge/AbilityFactory_Mana.java | 36 +++ src/forge/AbilityFactory_PermanentState.java | 42 +++ src/forge/AbilityFactory_Pump.java | 25 ++ src/forge/AbilityFactory_Regenerate.java | 6 + src/forge/AbilityFactory_Sacrifice.java | 12 + src/forge/AbilityFactory_Token.java | 12 + src/forge/AbilityFactory_Turns.java | 12 + src/forge/AbilityFactory_ZoneAffecting.java | 48 +++ src/forge/Ability_Activated.java | 6 +- src/forge/Ability_Sub.java | 2 + src/forge/GameActionUtil.java | 2 +- src/forge/Phase.java | 4 + src/forge/PlayerZone_ComesIntoPlay.java | 24 -- src/forge/Target.java | 13 +- 22 files changed, 666 insertions(+), 153 deletions(-) diff --git a/src/forge/AbilityFactory_AlterLife.java b/src/forge/AbilityFactory_AlterLife.java index 88eb12a5933..9dfd9f92959 100644 --- a/src/forge/AbilityFactory_AlterLife.java +++ b/src/forge/AbilityFactory_AlterLife.java @@ -17,7 +17,6 @@ public class AbilityFactory_AlterLife { private static final long serialVersionUID = 8869422603616247307L; final AbilityFactory af = AF; - final HashMap params = af.getMapParams(); @Override public String getStackDescription(){ @@ -32,13 +31,17 @@ public class AbilityFactory_AlterLife { public boolean canPlayAI() { - return gainLifeCanPlayAI(af, this, params.get("LifeAmount")); + return gainLifeCanPlayAI(af, this); } @Override public void resolve() { - int amount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("LifeAmount"), this); - gainLifeResolve(af, this, amount); + gainLifeResolve(af, this); + } + + @Override + public boolean doTrigger(boolean mandatory) { + return gainLifeDoTriggerAI(af, this, mandatory); } }; @@ -50,7 +53,6 @@ public class AbilityFactory_AlterLife { private static final long serialVersionUID = 6631124959690157874L; final AbilityFactory af = AF; - final HashMap params = af.getMapParams(); @Override public String getStackDescription(){ @@ -68,13 +70,12 @@ public class AbilityFactory_AlterLife { // if X depends on abCost, the AI needs to choose which card he would sacrifice first // then call xCount with that card to properly calculate the amount // Or choosing how many to sacrifice - return gainLifeCanPlayAI(af, this, params.get("LifeAmount")); + return gainLifeCanPlayAI(af, this); } @Override public void resolve() { - int amount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("LifeAmount"), this); - gainLifeResolve(af, this, amount); + gainLifeResolve(af, this); } }; @@ -86,7 +87,6 @@ public class AbilityFactory_AlterLife { private static final long serialVersionUID = 6631124959690157874L; final AbilityFactory af = AF; - final HashMap params = af.getMapParams(); @Override public String getStackDescription(){ @@ -99,19 +99,23 @@ public class AbilityFactory_AlterLife { // if X depends on abCost, the AI needs to choose which card he would sacrifice first // then call xCount with that card to properly calculate the amount // Or choosing how many to sacrifice - return gainLifeCanPlayAI(af, this, params.get("LifeAmount")); + return gainLifeCanPlayAI(af, this); } @Override public void resolve() { - int amount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("LifeAmount"), this); - gainLifeResolve(af, this, amount); + gainLifeResolve(af, this); } @Override public boolean chkAI_Drawback() { return true; } + + @Override + public boolean doTrigger(boolean mandatory) { + return gainLifeDoTriggerAI(af, this, mandatory); + } }; return dbGainLife; @@ -147,11 +151,12 @@ public class AbilityFactory_AlterLife { return sb.toString(); } - public static boolean gainLifeCanPlayAI(final AbilityFactory af, final SpellAbility sa, final String amountStr){ + public static boolean gainLifeCanPlayAI(final AbilityFactory af, final SpellAbility sa){ Random r = new Random(); Ability_Cost abCost = sa.getPayCosts(); final Card source = sa.getSourceCard(); int life = AllZone.ComputerPlayer.getLife(); + String amountStr = af.getMapParams().get("LifeAmount"); if (abCost != null){ // AI currently disabled for these costs @@ -184,32 +189,57 @@ public class AbilityFactory_AlterLife { boolean chance = r.nextFloat() <= Math.pow(.6667, source.getAbilityUsed()); Target tgt = sa.getTarget(); - - if (sa.getTarget() != null){ + if (tgt != null){ tgt.resetTargets(); - sa.getTarget().addTarget(AllZone.ComputerPlayer); + if (tgt.canOnlyTgtOpponent()) + tgt.addTarget(AllZone.HumanPlayer); + else + tgt.addTarget(AllZone.ComputerPlayer); } return ((r.nextFloat() < .6667) && chance); } - public static void gainLifeResolve(final AbilityFactory af, final SpellAbility sa, int lifeAmount){ + public static boolean gainLifeDoTriggerAI(AbilityFactory af, SpellAbility sa, boolean mandatory){ + if (!ComputerUtil.canPayCost(sa) && !mandatory) // If there is a cost payment it's usually not mandatory + return false; + + // If the Target is gaining life, target self. + // if the Target is modifying how much life is gained, this needs to be handled better + Target tgt = sa.getTarget(); + if (tgt != null){ + tgt.resetTargets(); + if (tgt.canOnlyTgtOpponent()) + tgt.addTarget(AllZone.HumanPlayer); + else + tgt.addTarget(AllZone.ComputerPlayer); + } + + // check SubAbilities DoTrigger? + Ability_Sub abSub = sa.getSubAbility(); + if (abSub != null) { + return abSub.doTrigger(mandatory); + } + + return true; + } + + public static void gainLifeResolve(final AbilityFactory af, final SpellAbility sa){ HashMap params = af.getMapParams(); Card card = af.getHostCard(); - + int lifeAmount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("LifeAmount"), sa); ArrayList tgtPlayers; Target tgt = af.getAbTgt(); - if (tgt != null) + if (tgt != null && !params.containsKey("Defined")) tgtPlayers = tgt.getTargetPlayers(); else - tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), af.getMapParams().get("Defined"), sa); + tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa); for(Player p : tgtPlayers) if (tgt == null || p.canTarget(af.getHostCard())) p.gainLife(lifeAmount, sa.getSourceCard()); - if (af.hasSubAbility()){ Ability_Sub abSub = sa.getSubAbility(); if (abSub != null){ @@ -232,7 +262,6 @@ public class AbilityFactory_AlterLife { private static final long serialVersionUID = 1129762905315395160L; final AbilityFactory af = AF; - final HashMap params = af.getMapParams(); @Override public String getStackDescription(){ @@ -250,13 +279,17 @@ public class AbilityFactory_AlterLife { // if X depends on abCost, the AI needs to choose which card he would sacrifice first // then call xCount with that card to properly calculate the amount // Or choosing how many to sacrifice - return loseLifeCanPlayAI(af, this, params.get("LifeAmount")); + return loseLifeCanPlayAI(af, this); } @Override public void resolve() { - int amount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("LifeAmount"), this); - loseLifeResolve(af, this, amount); + loseLifeResolve(af, this); + } + + @Override + public boolean doTrigger(boolean mandatory) { + return loseLifeDoTriggerAI(af, this, mandatory); } }; return abLoseLife; @@ -267,7 +300,6 @@ public class AbilityFactory_AlterLife { private static final long serialVersionUID = -2966932725306192437L; final AbilityFactory af = AF; - final HashMap params = af.getMapParams(); @Override public String getStackDescription(){ @@ -285,13 +317,12 @@ public class AbilityFactory_AlterLife { // if X depends on abCost, the AI needs to choose which card he would sacrifice first // then call xCount with that card to properly calculate the amount // Or choosing how many to sacrifice - return loseLifeCanPlayAI(af, this, params.get("LifeAmount")); + return loseLifeCanPlayAI(af, this); } @Override public void resolve() { - int amount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("LifeAmount"), this); - loseLifeResolve(af, this, amount); + loseLifeResolve(af, this); } }; return spLoseLife; @@ -302,8 +333,7 @@ public class AbilityFactory_AlterLife { private static final long serialVersionUID = -2966932725306192437L; final AbilityFactory af = AF; - final HashMap params = af.getMapParams(); - + @Override public String getStackDescription(){ // when getStackDesc is called, just build exactly what is happening @@ -315,19 +345,23 @@ public class AbilityFactory_AlterLife { // if X depends on abCost, the AI needs to choose which card he would sacrifice first // then call xCount with that card to properly calculate the amount // Or choosing how many to sacrifice - return loseLifeCanPlayAI(af, this, params.get("LifeAmount")); + return loseLifeCanPlayAI(af, this); } @Override public void resolve() { - int amount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("LifeAmount"), this); - loseLifeResolve(af, this, amount); + loseLifeResolve(af, this); } @Override public boolean chkAI_Drawback() { return true; } + + @Override + public boolean doTrigger(boolean mandatory) { + return loseLifeDoTriggerAI(af, this, mandatory); + } }; return dbLoseLife; } @@ -361,13 +395,15 @@ public class AbilityFactory_AlterLife { return sb.toString(); } - public static boolean loseLifeCanPlayAI(final AbilityFactory af, final SpellAbility sa, final String amountStr){ + public static boolean loseLifeCanPlayAI(final AbilityFactory af, final SpellAbility sa){ Random r = new Random(); Ability_Cost abCost = sa.getPayCosts(); final Card source = sa.getSourceCard(); int humanLife = AllZone.HumanPlayer.getLife(); int aiLife = AllZone.ComputerPlayer.getLife(); + String amountStr = af.getMapParams().get("LifeAmount"); + // TODO handle proper calculation of X values based on Cost and what would be paid final int amount = AbilityFactory.calculateAmount(af.getHostCard(), amountStr, sa); @@ -406,9 +442,28 @@ public class AbilityFactory_AlterLife { return ((r.nextFloat() < .6667) && chance); } - public static void loseLifeResolve(final AbilityFactory af, final SpellAbility sa, int lifeAmount){ + public static boolean loseLifeDoTriggerAI(AbilityFactory af, SpellAbility sa, boolean mandatory){ + if (!ComputerUtil.canPayCost(sa) && !mandatory) // If there is a cost payment it's usually not mandatory + return false; + + Target tgt = sa.getTarget(); + if (tgt != null){ + tgt.addTarget(AllZone.HumanPlayer); + } + + // check SubAbilities DoTrigger? + Ability_Sub abSub = sa.getSubAbility(); + if (abSub != null) { + return abSub.doTrigger(mandatory); + } + + return true; + } + + public static void loseLifeResolve(final AbilityFactory af, final SpellAbility sa){ HashMap params = af.getMapParams(); Card card = af.getHostCard(); + int lifeAmount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("LifeAmount"), sa); ArrayList tgtPlayers; @@ -477,6 +532,11 @@ public class AbilityFactory_AlterLife { int amount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("Num"), this); poisonResolve(af, this, amount); } + + @Override + public boolean doTrigger(boolean mandatory) { + return poisonDoTriggerAI(af, this, mandatory); + } }; return abPoison; @@ -543,11 +603,41 @@ public class AbilityFactory_AlterLife { public boolean chkAI_Drawback() { return true; } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return poisonDoTriggerAI(af, this, mandatory); + } }; return dbPoison; } + public static boolean poisonDoTriggerAI(AbilityFactory af, SpellAbility sa, boolean mandatory){ + if (!ComputerUtil.canPayCost(sa) && !mandatory) // If there is a cost payment it's usually not mandatory + return false; + + Target tgt = sa.getTarget(); + if (tgt != null){ + tgt.addTarget(AllZone.HumanPlayer); + } + else{ + ArrayList players = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), af.getMapParams().get("Defined"), sa); + for(Player p : players) + if (!mandatory && p.isComputer() && p.getPoisonCounters() > p.getOpponent().getPoisonCounters()) + return false; + } + + // check SubAbilities DoTrigger? + Ability_Sub abSub = sa.getSubAbility(); + if (abSub != null) { + return abSub.doTrigger(mandatory); + } + + return true; + } + private static void poisonResolve(final AbilityFactory af, final SpellAbility sa, int num){ HashMap params = af.getMapParams(); Card card = af.getHostCard(); diff --git a/src/forge/AbilityFactory_ChangeZone.java b/src/forge/AbilityFactory_ChangeZone.java index c0c8911caaa..e45757ff49b 100644 --- a/src/forge/AbilityFactory_ChangeZone.java +++ b/src/forge/AbilityFactory_ChangeZone.java @@ -30,6 +30,12 @@ public class AbilityFactory_ChangeZone { return changeZoneDescription(AF, this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; setMiscellaneous(AF, abChangeZone); return abChangeZone; @@ -75,6 +81,12 @@ public class AbilityFactory_ChangeZone { public String getStackDescription(){ return changeZoneDescription(AF, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; setMiscellaneous(AF, dbChangeZone); return dbChangeZone; @@ -940,6 +952,12 @@ public class AbilityFactory_ChangeZone { return changeZoneAllDescription(AF, this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; setMiscellaneous(AF, abChangeZone); return abChangeZone; @@ -985,6 +1003,12 @@ public class AbilityFactory_ChangeZone { public String getStackDescription(){ return changeZoneAllDescription(AF, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; setMiscellaneous(AF, dbChangeZone); return dbChangeZone; diff --git a/src/forge/AbilityFactory_Combat.java b/src/forge/AbilityFactory_Combat.java index 7dfb4c3af86..a526d769193 100644 --- a/src/forge/AbilityFactory_Combat.java +++ b/src/forge/AbilityFactory_Combat.java @@ -28,6 +28,12 @@ public class AbilityFactory_Combat { public void resolve() { fogResolve(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abFog; @@ -74,6 +80,12 @@ public class AbilityFactory_Combat { public boolean chkAI_Drawback() { return fogPlayDrawbackAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbFog; @@ -100,8 +112,11 @@ public class AbilityFactory_Combat { public static boolean fogCanPlayAI(final AbilityFactory af, SpellAbility sa){ // AI should only activate this during Human's Declare Blockers phase - boolean chance = AllZone.Phase.is(Constant.Phase.Combat_Declare_Blockers_InstantAbility, sa.getActivatingPlayer().getOpponent()); - + boolean chance; + if (AllZone.Phase.isPlayerTurn(sa.getActivatingPlayer().getOpponent())) + chance = AllZone.Phase.isBefore(Constant.Phase.Combat_FirstStrikeDamage); + else + chance = AllZone.Phase.isAfter(Constant.Phase.Combat_Damage); // Only cast when Stack is empty, so Human uses spells/abilities first chance &= AllZone.Stack.size() == 0; @@ -116,8 +131,11 @@ public class AbilityFactory_Combat { public static boolean fogPlayDrawbackAI(final AbilityFactory af, SpellAbility sa){ // AI should only activate this during Human's turn - boolean chance = AllZone.Phase.isPlayerTurn(sa.getActivatingPlayer().getOpponent()) || - AllZone.Phase.isAfter(Constant.Phase.Combat_Damage); + boolean chance; + if (AllZone.Phase.isPlayerTurn(sa.getActivatingPlayer().getOpponent())) + chance = AllZone.Phase.isBefore(Constant.Phase.Combat_FirstStrikeDamage); + else + chance = AllZone.Phase.isAfter(Constant.Phase.Combat_Damage); Ability_Sub subAb = sa.getSubAbility(); if (subAb != null) @@ -126,6 +144,25 @@ public class AbilityFactory_Combat { return chance; } + public static boolean fogDoTriggerAI(AbilityFactory af, SpellAbility sa, boolean mandatory){ + if (!ComputerUtil.canPayCost(sa) && !mandatory) // If there is a cost payment it's usually not mandatory + return false; + + boolean chance; + if (AllZone.Phase.isPlayerTurn(sa.getActivatingPlayer().getOpponent())) + chance = AllZone.Phase.isBefore(Constant.Phase.Combat_FirstStrikeDamage); + else + chance = AllZone.Phase.isAfter(Constant.Phase.Combat_Damage); + + // check SubAbilities DoTrigger? + Ability_Sub abSub = sa.getSubAbility(); + if (abSub != null) { + return chance && abSub.doTrigger(mandatory); + } + + return chance; + } + public static void fogResolve(final AbilityFactory af, final SpellAbility sa){ HashMap params = af.getMapParams(); Card card = sa.getSourceCard(); diff --git a/src/forge/AbilityFactory_CounterMagic.java b/src/forge/AbilityFactory_CounterMagic.java index a055f158b2b..77e8412b339 100644 --- a/src/forge/AbilityFactory_CounterMagic.java +++ b/src/forge/AbilityFactory_CounterMagic.java @@ -80,6 +80,12 @@ public class AbilityFactory_CounterMagic { counterResolve(af, this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; return abCounter; } diff --git a/src/forge/AbilityFactory_Counters.java b/src/forge/AbilityFactory_Counters.java index 9af931d4a92..47d39ad1e69 100644 --- a/src/forge/AbilityFactory_Counters.java +++ b/src/forge/AbilityFactory_Counters.java @@ -34,6 +34,12 @@ public class AbilityFactory_Counters { public void resolve() { putResolve(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abPutCounter; @@ -87,6 +93,12 @@ public class AbilityFactory_Counters { public boolean chkAI_Drawback() { return putPlayDrawbackAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbPutCounter; @@ -135,17 +147,17 @@ public class AbilityFactory_Counters { Card choice = null; String type = af.getMapParams().get("CounterType"); String amountStr = af.getMapParams().get("CounterNum"); - + Player player = af.isCurse() ? AllZone.HumanPlayer : AllZone.ComputerPlayer; - + list = AllZoneUtil.getPlayerCardsInPlay(player); list = list.filter(new CardListFilter() { public boolean addCard(Card c) { return CardFactoryUtil.canTarget(source, c); } }); - + if (abTgt != null){ list = list.getValidCards(abTgt.getValidTgts(),source.getController(),source); @@ -158,7 +170,7 @@ public class AbilityFactory_Counters { if (!pZone.getPlayer().equals(player)) return false; } - + if (abCost != null){ // AI currently disabled for these costs if (abCost.getSacCost()){ @@ -166,7 +178,7 @@ public class AbilityFactory_Counters { } if (abCost.getLifeCost()) return false; if (abCost.getDiscardCost()) return false; - + if (abCost.getSubCounter()){ // A card has a 25% chance per counter to be able to pass through here // 4+ counters will always pass. 0 counters will never @@ -176,20 +188,20 @@ public class AbilityFactory_Counters { return false; } } - + if (!ComputerUtil.canPayCost(sa)) return false; - + // TODO handle proper calculation of X values based on Cost final int amount = AbilityFactory.calculateAmount(af.getHostCard(), amountStr, sa); - - // prevent run-away activations - first time will always return true - boolean chance = r.nextFloat() <= Math.pow(.6667, source.getAbilityUsed()); - - // Targeting - if (abTgt != null){ - abTgt.resetTargets(); - // target loop + + // prevent run-away activations - first time will always return true + boolean chance = r.nextFloat() <= Math.pow(.6667, source.getAbilityUsed()); + + // Targeting + if (abTgt != null){ + abTgt.resetTargets(); + // target loop while(abTgt.getNumTargeted() < abTgt.getMaxTargets(sa.getSourceCard(), sa)){ if (list.size() == 0){ if (abTgt.getNumTargeted() < abTgt.getMinTargets(sa.getSourceCard(), sa) || abTgt.getNumTargeted() == 0){ @@ -201,38 +213,14 @@ public class AbilityFactory_Counters { break; } } - - if (af.isCurse()){ - if (type.equals("M1M1")){ - // try to kill the best killable creature, or reduce the best one - CardList killable = list.filter(new CardListFilter() { - public boolean addCard(Card c) { - return c.getNetDefense() <= amount; - } - }); - if (killable.size() > 0) - choice = CardFactoryUtil.AI_getBestCreature(killable); - else - choice = CardFactoryUtil.AI_getBestCreature(list); - } - else{ - // improve random choice here - list.shuffle(); - choice = list.get(0); - } - } - else{ - if (type.equals("P1P1")){ - choice = CardFactoryUtil.AI_getBestCreature(list); - } - else{ - // The AI really should put counters on cards that can use it. - // Charge counters on things with Charge abilities, etc. Expand these above - list.shuffle(); - choice = list.get(0); - } - } - + + if (af.isCurse()){ + choice = chooseCursedTarget(list, type, amount); + } + else{ + choice = chooseBoonTarget(list, type, amount); + } + if (choice == null){ // can't find anything left if (abTgt.getNumTargeted() < abTgt.getMinTargets(sa.getSourceCard(), sa) || abTgt.getNumTargeted() == 0){ abTgt.resetTargets(); @@ -246,21 +234,21 @@ public class AbilityFactory_Counters { list.remove(choice); abTgt.addTarget(choice); } - } - else{ + } + else{ // Placeholder: No targeting necessary - int currCounters = sa.getSourceCard().getCounters(Counters.valueOf(type)); + int currCounters = sa.getSourceCard().getCounters(Counters.valueOf(type)); // each non +1/+1 counter on the card is a 10% chance of not activating this ability. - - if (!type.equals("P1P1") && r.nextFloat() < .1 * currCounters) - return false; - } - - Ability_Sub subAb = sa.getSubAbility(); - if (subAb != null) - chance &= subAb.chkAI_Drawback(); - - return ((r.nextFloat() < .6667) && chance); + + if (!type.equals("P1P1") && r.nextFloat() < .1 * currCounters) + return false; + } + + Ability_Sub subAb = sa.getSubAbility(); + if (subAb != null) + chance &= subAb.chkAI_Drawback(); + + return ((r.nextFloat() < .6667) && chance); } public static boolean putPlayDrawbackAI(final AbilityFactory af, final SpellAbility sa){ @@ -302,34 +290,10 @@ public class AbilityFactory_Counters { } if (af.isCurse()){ - if (type.equals("M1M1")){ - // try to kill the best killable creature, or reduce the best one - CardList killable = list.filter(new CardListFilter() { - public boolean addCard(Card c) { - return c.getNetDefense() <= amount; - } - }); - if (killable.size() > 0) - choice = CardFactoryUtil.AI_getBestCreature(killable); - else - choice = CardFactoryUtil.AI_getBestCreature(list); - } - else{ - // improve random choice here - list.shuffle(); - choice = list.get(0); - } + choice = chooseCursedTarget(list, type, amount); } else{ - if (type.equals("P1P1")){ - choice = CardFactoryUtil.AI_getBestCreature(list); - } - else{ - // The AI really should put counters on cards that can use it. - // Charge counters on things with Charge abilities, etc. Expand these above - list.shuffle(); - choice = list.get(0); - } + } if (choice == null){ // can't find anything left @@ -354,6 +318,124 @@ public class AbilityFactory_Counters { return chance; } + + public static boolean putDoTriggerAI(final AbilityFactory af, final SpellAbility sa, boolean mandatory){ + // if there is a cost, it's gotta be optional + if (!ComputerUtil.canPayCost(sa) && !mandatory) + return false; + + HashMap params = af.getMapParams(); + Target abTgt = sa.getTarget(); + final Card source = sa.getSourceCard(); + boolean chance = true; + boolean preferred = true; + CardList list; + Player player = af.isCurse() ? AllZone.HumanPlayer : AllZone.ComputerPlayer; + String type = af.getMapParams().get("CounterType"); + String amountStr = af.getMapParams().get("CounterNum"); + final int amount = AbilityFactory.calculateAmount(af.getHostCard(), amountStr, sa); + + if (abTgt == null){ + // No target. So must be defined + list = new CardList(AbilityFactory.getDefinedCards(source, params.get("Defined"), sa).toArray()); + + if (!mandatory){ + // todo: If Trigger isn't mandatory, when wouldn't we want to put a counter? + // things like Powder Keg, which are way too complex for the AI + } + } + else{ + list = AllZoneUtil.getPlayerCardsInPlay(player); + list = list.getTargetableCards(source); + if (abTgt != null){ + list = list.getValidCards(abTgt.getValidTgts(),source.getController(),source); + } + if (list.isEmpty() && mandatory){ + // If there isn't any prefered cards to target, gotta choose non-preferred ones + list = AllZoneUtil.getPlayerCardsInPlay(player.getOpponent()); + list = list.getTargetableCards(source); + if (abTgt != null){ + list = list.getValidCards(abTgt.getValidTgts(),source.getController(),source); + } + preferred = false; + } + // Not mandatory, or the the list was regenerated and is still empty, so return false since there are no targets + if (list.isEmpty()) + return false; + + Card choice = null; + + // Choose targets here: + if (af.isCurse()){ + if (preferred) + choice = chooseCursedTarget(list, type, amount); + + else{ + if (type.equals("M1M1")){ + choice = CardFactoryUtil.AI_getWorstCreature(list); + } + else{ + choice = CardFactoryUtil.getRandomCard(list); + } + } + } + else{ + if (preferred) + choice = chooseBoonTarget(list, type, amount); + + else{ + if (type.equals("P1P1")){ + choice = CardFactoryUtil.AI_getWorstCreature(list); + } + else{ + choice = CardFactoryUtil.getRandomCard(list); + } + } + } + + abTgt.addTarget(choice); + } + + Ability_Sub subAb = sa.getSubAbility(); + if (subAb != null) + chance &= subAb.doTrigger(mandatory); + + return true; + } + + public static Card chooseCursedTarget(CardList list, String type, final int amount){ + Card choice; + if (type.equals("M1M1")){ + // try to kill the best killable creature, or reduce the best one + CardList killable = list.filter(new CardListFilter() { + public boolean addCard(Card c) { + return c.getNetDefense() <= amount; + } + }); + if (killable.size() > 0) + choice = CardFactoryUtil.AI_getBestCreature(killable); + else + choice = CardFactoryUtil.AI_getBestCreature(list); + } + else{ + // improve random choice here + choice = CardFactoryUtil.getRandomCard(list); + } + return choice; + } + + public static Card chooseBoonTarget(CardList list, String type, final int amount){ + Card choice; + if (type.equals("P1P1")){ + choice = CardFactoryUtil.AI_getBestCreature(list); + } + else{ + // The AI really should put counters on cards that can use it. + // Charge counters on things with Charge abilities, etc. Expand these above + choice = CardFactoryUtil.getRandomCard(list); + } + return choice; + } public static void putResolve(final AbilityFactory af, final SpellAbility sa){ HashMap params = af.getMapParams(); @@ -414,6 +496,12 @@ public class AbilityFactory_Counters { public void resolve() { removeResolve(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abRemCounter; @@ -467,6 +555,12 @@ public class AbilityFactory_Counters { public boolean chkAI_Drawback() { return removePlayDrawbackAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return spRemoveCounter; @@ -656,6 +750,12 @@ public class AbilityFactory_Counters { public String getStackDescription(){ return proliferateStackDescription(this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abProliferate; @@ -713,6 +813,12 @@ public class AbilityFactory_Counters { public boolean chkAI_Drawback() { return shouldProliferateAI(this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbProliferate; @@ -919,6 +1025,12 @@ public class AbilityFactory_Counters { putAllResolve(af, this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; return abPutCounterAll; } @@ -967,6 +1079,12 @@ public class AbilityFactory_Counters { return putAllPlayDrawbackAI(af, this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; return dbPutCounterAll; } diff --git a/src/forge/AbilityFactory_DealDamage.java b/src/forge/AbilityFactory_DealDamage.java index 373cb1bdfb2..318d78cdb38 100644 --- a/src/forge/AbilityFactory_DealDamage.java +++ b/src/forge/AbilityFactory_DealDamage.java @@ -45,6 +45,12 @@ public class AbilityFactory_DealDamage { AF.getHostCard().setAbilityUsed(AF.getHostCard().getAbilityUsed() + 1); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } };// Ability_Activated return abDamage; @@ -77,6 +83,12 @@ public class AbilityFactory_DealDamage { damageAllResolve(af, this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; return abDamageAll; } @@ -165,6 +177,12 @@ public class AbilityFactory_DealDamage { doResolve(this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; // Drawback return dbDealDamage; @@ -191,6 +209,12 @@ public class AbilityFactory_DealDamage { return true; } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; return dbDamageAll; } diff --git a/src/forge/AbilityFactory_Destroy.java b/src/forge/AbilityFactory_Destroy.java index 67743322ebc..63bbfb39ab1 100644 --- a/src/forge/AbilityFactory_Destroy.java +++ b/src/forge/AbilityFactory_Destroy.java @@ -32,6 +32,12 @@ public class AbilityFactory_Destroy { public void resolve() { destroyResolve(af, this, noRegen); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abDestroy; @@ -259,6 +265,12 @@ public class AbilityFactory_Destroy { public void resolve() { destroyAllResolve(af, this, noRegen); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abDestroyAll; @@ -329,6 +341,12 @@ public class AbilityFactory_Destroy { public boolean chkAI_Drawback() { return true; } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbDestroyAll; diff --git a/src/forge/AbilityFactory_GainControl.java b/src/forge/AbilityFactory_GainControl.java index a98162f4068..7b778255039 100644 --- a/src/forge/AbilityFactory_GainControl.java +++ b/src/forge/AbilityFactory_GainControl.java @@ -121,6 +121,12 @@ public class AbilityFactory_GainControl { } return sb.toString(); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } };//Ability_Activated return abControl; diff --git a/src/forge/AbilityFactory_Mana.java b/src/forge/AbilityFactory_Mana.java index c627a2037e8..4bf4dbda391 100644 --- a/src/forge/AbilityFactory_Mana.java +++ b/src/forge/AbilityFactory_Mana.java @@ -22,6 +22,12 @@ public class AbilityFactory_Mana { public void resolve() { manaResolve(this, af); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abMana; @@ -36,6 +42,12 @@ public class AbilityFactory_Mana { Ability_Cost tmp = new Ability_Cost("0", AF.getHostCard().getName(), false); Ability_Mana tmpMana = new Ability_Mana(AF.getHostCard(), tmp, produced){ private static final long serialVersionUID = 1454043766057140491L; + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; @@ -69,6 +81,12 @@ public class AbilityFactory_Mana { Ability_Cost tmp = new Ability_Cost("0", AF.getHostCard().getName(), false); Ability_Mana tmpMana = new Ability_Mana(AF.getHostCard(), tmp, produced){ private static final long serialVersionUID = 1454043766057140491L; + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; @@ -88,6 +106,12 @@ public class AbilityFactory_Mana { // todo: AI shouldn't use this until he has a mana pool return false; } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbMana; @@ -198,6 +222,12 @@ public class AbilityFactory_Mana { public void resolve() { manaReflectedResolve(this, af); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; abMana.setReflectedMana(true); @@ -215,6 +245,12 @@ public class AbilityFactory_Mana { Ability_Mana tmpMana = new Ability_Mana(AF.getHostCard(), tmp, produced){ private static final long serialVersionUID = 1454043766057140491L; + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + // todo: maybe add can produce here, so old AI code can use reflected mana? }; //tmpMana.setReflectedMana(true); diff --git a/src/forge/AbilityFactory_PermanentState.java b/src/forge/AbilityFactory_PermanentState.java index c6a212ad203..ffca0677352 100644 --- a/src/forge/AbilityFactory_PermanentState.java +++ b/src/forge/AbilityFactory_PermanentState.java @@ -28,6 +28,12 @@ public class AbilityFactory_PermanentState { public void resolve() { untapResolve(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abUntap; @@ -78,6 +84,12 @@ public class AbilityFactory_PermanentState { public boolean chkAI_Drawback() { return untapPlayDrawbackAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbUntap; @@ -300,6 +312,12 @@ public class AbilityFactory_PermanentState { public void resolve() { tapResolve(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abTap; @@ -350,6 +368,12 @@ public class AbilityFactory_PermanentState { public boolean chkAI_Drawback() { return tapPlayDrawbackAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbTap; @@ -572,6 +596,12 @@ public class AbilityFactory_PermanentState { untapAllResolve(af, this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; return abUntap; } @@ -676,6 +706,12 @@ public class AbilityFactory_PermanentState { tapAllResolve(af, this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; return abUntap; } @@ -723,6 +759,12 @@ public class AbilityFactory_PermanentState { public boolean chkAI_Drawback() { return tapAllPlayDrawbackAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbTap; diff --git a/src/forge/AbilityFactory_Pump.java b/src/forge/AbilityFactory_Pump.java index 6bc32b161f4..d878e75fcd0 100644 --- a/src/forge/AbilityFactory_Pump.java +++ b/src/forge/AbilityFactory_Pump.java @@ -87,6 +87,12 @@ public class AbilityFactory_Pump { hostCard.setAbilityUsed(hostCard.getAbilityUsed() + 1); }//resolve() + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } };//SpellAbility @@ -116,6 +122,12 @@ public class AbilityFactory_Pump { public boolean chkAI_Drawback() { return doDrawbackAI(this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } };//SpellAbility return dbPump; @@ -512,6 +524,13 @@ public class AbilityFactory_Pump { doPumpAllResolve(this); hostCard.setAbilityUsed(hostCard.getAbilityUsed() + 1); }//resolve() + + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } };//SpellAbility @@ -630,6 +649,12 @@ public class AbilityFactory_Pump { public boolean chkAI_Drawback() { return chkPumpAllDrawbackAI(this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } };//SpellAbility return dbPumpAll; diff --git a/src/forge/AbilityFactory_Regenerate.java b/src/forge/AbilityFactory_Regenerate.java index 718a137d6b1..e260b46e0f3 100644 --- a/src/forge/AbilityFactory_Regenerate.java +++ b/src/forge/AbilityFactory_Regenerate.java @@ -34,6 +34,12 @@ public class AbilityFactory_Regenerate { public String getStackDescription(){ return regenerateStackDescription(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } };//Ability_Activated diff --git a/src/forge/AbilityFactory_Sacrifice.java b/src/forge/AbilityFactory_Sacrifice.java index 13fac62a0b7..00eab0b2fae 100644 --- a/src/forge/AbilityFactory_Sacrifice.java +++ b/src/forge/AbilityFactory_Sacrifice.java @@ -27,6 +27,12 @@ public class AbilityFactory_Sacrifice { public String getStackDescription(){ return sacrificeDescription(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abSacrifice; } @@ -73,6 +79,12 @@ public class AbilityFactory_Sacrifice { public String getStackDescription(){ return sacrificeDescription(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbSacrifice; } diff --git a/src/forge/AbilityFactory_Token.java b/src/forge/AbilityFactory_Token.java index 0832656a57f..abfa798f5b0 100644 --- a/src/forge/AbilityFactory_Token.java +++ b/src/forge/AbilityFactory_Token.java @@ -109,6 +109,12 @@ public class AbilityFactory_Token extends AbilityFactory { public String getStackDescription() { return doStackDescription(this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abToken; @@ -164,6 +170,12 @@ public class AbilityFactory_Token extends AbilityFactory { doResolve(this); } + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } + }; // Spell return dbDealDamage; diff --git a/src/forge/AbilityFactory_Turns.java b/src/forge/AbilityFactory_Turns.java index a1f03c3b41a..760f206b5cf 100644 --- a/src/forge/AbilityFactory_Turns.java +++ b/src/forge/AbilityFactory_Turns.java @@ -33,6 +33,12 @@ public class AbilityFactory_Turns { int amount = AbilityFactory.calculateAmount(af.getHostCard(), params.get("NumTurns"), this); addTurnResolve(af, this, amount); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abAddTurn; @@ -97,6 +103,12 @@ public class AbilityFactory_Turns { public boolean chkAI_Drawback() { return true; } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbAddTurn; diff --git a/src/forge/AbilityFactory_ZoneAffecting.java b/src/forge/AbilityFactory_ZoneAffecting.java index 5016b505dfd..e36e64e7140 100644 --- a/src/forge/AbilityFactory_ZoneAffecting.java +++ b/src/forge/AbilityFactory_ZoneAffecting.java @@ -37,6 +37,12 @@ public class AbilityFactory_ZoneAffecting { public void resolve() { drawResolve(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abDraw; @@ -94,6 +100,12 @@ public class AbilityFactory_ZoneAffecting { public boolean chkAI_Drawback() { return drawTargetAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbDraw; @@ -334,6 +346,12 @@ public class AbilityFactory_ZoneAffecting { public void resolve() { millResolve(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abMill; @@ -394,6 +412,12 @@ public class AbilityFactory_ZoneAffecting { public boolean chkAI_Drawback() { return millTargetAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbMill; @@ -589,6 +613,12 @@ public class AbilityFactory_ZoneAffecting { public void resolve() { discardResolve(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abDraw; @@ -659,6 +689,12 @@ public class AbilityFactory_ZoneAffecting { discardTargetAI(af); return discardCheckDrawbackAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbDraw; @@ -939,6 +975,12 @@ public class AbilityFactory_ZoneAffecting { public boolean chkAI_Drawback() { return scryTargetAI(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return dbScry; @@ -1053,6 +1095,12 @@ public class AbilityFactory_ZoneAffecting { public void resolve() { scryResolve(af, this); } + + @Override + public boolean doTrigger(boolean mandatory) { + // TODO Auto-generated method stub + return false; + } }; return abScry; diff --git a/src/forge/Ability_Activated.java b/src/forge/Ability_Activated.java index 7d080ed6864..afdec68c75b 100644 --- a/src/forge/Ability_Activated.java +++ b/src/forge/Ability_Activated.java @@ -44,6 +44,10 @@ abstract public class Ability_Activated extends SpellAbility implements java.io. return false; return Cost_Payment.canPayAdditionalCosts(payCosts, this); - //TODO: make sure you can't play the Computer's activated abilities + } + + // This should be overridden by ALL AFs + public boolean doTrigger(boolean mandatory){ + return false; } } diff --git a/src/forge/Ability_Sub.java b/src/forge/Ability_Sub.java index 0bc3c1f0786..fe649a1ded7 100644 --- a/src/forge/Ability_Sub.java +++ b/src/forge/Ability_Sub.java @@ -18,6 +18,8 @@ abstract public class Ability_Sub extends SpellAbility implements java.io.Serial abstract public boolean chkAI_Drawback(); + abstract public boolean doTrigger(boolean mandatory); + public void setParent(SpellAbility parent) { this.parent = parent; } diff --git a/src/forge/GameActionUtil.java b/src/forge/GameActionUtil.java index b44cdb6f74d..2294fdb412a 100644 --- a/src/forge/GameActionUtil.java +++ b/src/forge/GameActionUtil.java @@ -3536,7 +3536,7 @@ public class GameActionUtil { } public static void showInfoDialg(String message) { - AllZone.Display.setCard(c); + //AllZone.Display.setCard(c); // c doesn't exist here! JOptionPane.showMessageDialog(null, message); } diff --git a/src/forge/Phase.java b/src/forge/Phase.java index f0a0965b211..0a5b68f09b7 100644 --- a/src/forge/Phase.java +++ b/src/forge/Phase.java @@ -418,6 +418,10 @@ public class Phase extends MyObservable public boolean isAfter(String phase) { return phaseIndex > findIndex(phase); } + + public boolean isBefore(String phase) { + return phaseIndex < findIndex(phase); + } private int findIndex(String phase) { for(int i = 0; i < phaseOrder.length; i++) { diff --git a/src/forge/PlayerZone_ComesIntoPlay.java b/src/forge/PlayerZone_ComesIntoPlay.java index 7f8b9c60912..5ebc6a8fd18 100644 --- a/src/forge/PlayerZone_ComesIntoPlay.java +++ b/src/forge/PlayerZone_ComesIntoPlay.java @@ -68,7 +68,6 @@ public class PlayerZone_ComesIntoPlay extends DefaultPlayerZone { AllZone.GameAction.checkWheneverKeyword(c,"EntersBattleField",null); PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, c.getController()); - PlayerZone grave = AllZone.getZone(Constant.Zone.Graveyard, c.getController()); //Amulet of Vigor if(c.isTapped()) { @@ -99,7 +98,6 @@ public class PlayerZone_ComesIntoPlay extends DefaultPlayerZone { //System.out.println("A land was just put onto the battlefield: " + c.getName()); CardList list = new CardList(play.getCards()); - CardList graveList = new CardList(grave.getCards()); CardList listValakut = list.filter(new CardListFilter() { public boolean addCard(Card c) { @@ -128,28 +126,6 @@ public class PlayerZone_ComesIntoPlay extends DefaultPlayerZone { } } } - /* - CardList ankhs = AllZoneUtil.getCardsInPlay("Ankh of Mishra"); - // - //ankhs.add(AllZoneUtil.getCardsInPlay("Zo-Zu the Punisher")); - // - final Card ankhLand = c; - for(Card ankh:ankhs) { - final Card source = ankh; - SpellAbility ability = new Ability(source, "") { - @Override - public void resolve() { - ankhLand.getController().addDamage(2, source); - } - }; - StringBuilder sb = new StringBuilder(); - sb.append(source).append(" - deals 2 damage to ").append(ankhLand.getController()); - ability.setStackDescription(sb.toString()); - - AllZone.Stack.add(ability); - } - - */ CardList seeds = AllZoneUtil.getCardsInPlay("Seed the Land"); final Card seedLand = c; diff --git a/src/forge/Target.java b/src/forge/Target.java index 2e2faaf89ff..c4b7cedebb3 100644 --- a/src/forge/Target.java +++ b/src/forge/Target.java @@ -171,8 +171,19 @@ public class Target { return sb.toString(); } + + public boolean canOnlyTgtOpponent() { + boolean player = false; + boolean opponent = false; + for(String s: ValidTgts){ + if (s.equals("Opponent")) + opponent = true; + else if (s.equals("Player")) + player = true; + } + return opponent && !player; + } - // These below functions are quite limited to the damage classes, we should find a way to move them into AF_DealDamage public boolean canTgtPlayer() { for(String s: ValidTgts){ if (s.equals("Player") || s.equals("Opponent"))