Lots of code cleanup, including removing some useless null checks,

preventing some NPE's before they ever occur, and clean up some
of the inheritance hierarchy.
This commit is contained in:
elcnesh
2015-04-13 14:29:01 +00:00
parent 19ccab3d00
commit 6dacb83c37
19 changed files with 322 additions and 262 deletions

View File

@@ -1209,7 +1209,7 @@ public class ComputerUtilMana {
* @return map between creatures and shards to convoke
*/
public static Map<Card, ManaCostShard> getConvokeFromList(final ManaCost cost, List<Card> list) {
HashMap<Card, ManaCostShard> convoke = new HashMap<Card, ManaCostShard>();
final Map<Card, ManaCostShard> convoke = new HashMap<Card, ManaCostShard>();
Card convoked = null;
for (ManaCostShard toPay : cost) {
for (Card c : list) {
@@ -1219,9 +1219,6 @@ public class ComputerUtilMana {
convoke.put(c, toPay);
break;
}
if (convoked != null){
break;
}
}
if (convoked != null) {
list.remove(convoked);

View File

@@ -1,10 +1,11 @@
package forge.ai;
import java.util.Collection;
import java.util.List;
import com.google.common.collect.Iterables;
import forge.game.GameEntity;
import forge.game.ability.SaTargetRoutines;
import forge.game.card.Card;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -14,10 +15,7 @@ import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import java.util.Collection;
import java.util.List;
public abstract class SpellAbilityAi extends SaTargetRoutines {
public abstract class SpellAbilityAi {
public final boolean canPlayAIWithSubs(final Player aiPlayer, final SpellAbility sa) {
if (!canPlayAI(aiPlayer, sa)) {

View File

@@ -1,6 +1,10 @@
package forge.ai;
import java.util.EnumMap;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import forge.ai.ability.*;
import forge.game.ability.ApiType;
@@ -8,149 +12,148 @@ import forge.util.ReflectionUtil;
public enum SpellApiToAi {
Converter;
private final static EnumMap<ApiType, Class<? extends SpellAbilityAi>> apiToClass = new EnumMap<>(ApiType.class);
private final EnumMap<ApiType, SpellAbilityAi> apiToInstance = new EnumMap<>(ApiType.class);
static {
apiToClass.put(ApiType.Abandon, AlwaysPlayAi.class);
apiToClass.put(ApiType.ActivateAbility, ActivateAbilityAi.class);
apiToClass.put(ApiType.AddOrRemoveCounter, CountersPutOrRemoveAi.class);
apiToClass.put(ApiType.AddPhase, AddPhaseAi.class);
apiToClass.put(ApiType.AddTurn, AddTurnAi.class);
apiToClass.put(ApiType.Animate, AnimateAi.class);
apiToClass.put(ApiType.AnimateAll, AnimateAllAi.class);
apiToClass.put(ApiType.Attach, AttachAi.class);
apiToClass.put(ApiType.Balance, BalanceAi.class);
apiToClass.put(ApiType.BecomesBlocked, BecomesBlockedAi.class);
apiToClass.put(ApiType.BidLife, BidLifeAi.class);
apiToClass.put(ApiType.Bond, BondAi.class);
apiToClass.put(ApiType.ChangeTargets, ChangeTargetsAi.class);
apiToClass.put(ApiType.ChangeZone, ChangeZoneAi.class);
apiToClass.put(ApiType.ChangeZoneAll, ChangeZoneAllAi.class);
apiToClass.put(ApiType.Charm, CharmAi.class);
apiToClass.put(ApiType.ChooseCard, ChooseCardAi.class);
apiToClass.put(ApiType.ChooseColor, ChooseColorAi.class);
apiToClass.put(ApiType.ChooseDirection, ChooseDirectionAi.class);
apiToClass.put(ApiType.ChooseNumber, ChooseNumberAi.class);
apiToClass.put(ApiType.ChoosePlayer, ChoosePlayerAi.class);
apiToClass.put(ApiType.ChooseSource, ChooseSourceAi.class);
apiToClass.put(ApiType.ChooseType, ChooseTypeAi.class);
apiToClass.put(ApiType.Clash, ClashAi.class);
apiToClass.put(ApiType.Cleanup, AlwaysPlayAi.class);
apiToClass.put(ApiType.Clone, CloneAi.class);
apiToClass.put(ApiType.CopyPermanent, CopyPermanentAi.class);
apiToClass.put(ApiType.CopySpellAbility, CanPlayAsDrawbackAi.class);
apiToClass.put(ApiType.ControlPlayer, CannotPlayAi.class);
apiToClass.put(ApiType.ControlSpell, CannotPlayAi.class);
apiToClass.put(ApiType.Counter, CounterAi.class);
apiToClass.put(ApiType.DamageAll, DamageAllAi.class);
apiToClass.put(ApiType.DealDamage, DamageDealAi.class);
apiToClass.put(ApiType.Debuff, DebuffAi.class);
apiToClass.put(ApiType.DeclareCombatants, CannotPlayAi.class);
apiToClass.put(ApiType.DelayedTrigger, DelayedTriggerAi.class);
apiToClass.put(ApiType.Destroy, DestroyAi.class);
apiToClass.put(ApiType.DestroyAll, DestroyAllAi.class);
apiToClass.put(ApiType.Dig, DigAi.class);
apiToClass.put(ApiType.DigUntil, DigUntilAi.class);
apiToClass.put(ApiType.Discard, DiscardAi.class);
apiToClass.put(ApiType.DrainMana, DrainManaAi.class);
apiToClass.put(ApiType.Draw, DrawAi.class);
apiToClass.put(ApiType.EachDamage, DamageEachAi.class);
apiToClass.put(ApiType.Effect, EffectAi.class);
apiToClass.put(ApiType.Encode, EncodeAi.class);
apiToClass.put(ApiType.EndTurn, EndTurnAi.class);
apiToClass.put(ApiType.ExchangeLife, LifeExchangeAi.class);
apiToClass.put(ApiType.ExchangeControl, ControlExchangeAi.class);
apiToClass.put(ApiType.ExchangeControlVariant, CannotPlayAi.class);
apiToClass.put(ApiType.ExchangePower, PowerExchangeAi.class);
apiToClass.put(ApiType.ExchangeZone, ZoneExchangeAi.class);
apiToClass.put(ApiType.Fight, FightAi.class);
apiToClass.put(ApiType.FlipACoin, FlipACoinAi.class);
apiToClass.put(ApiType.Fog, FogAi.class);
apiToClass.put(ApiType.GainControl, ControlGainAi.class);
apiToClass.put(ApiType.GainLife, LifeGainAi.class);
apiToClass.put(ApiType.GainOwnership, CannotPlayAi.class);
apiToClass.put(ApiType.GenericChoice, ChooseGenericEffectAi.class);
apiToClass.put(ApiType.LoseLife, LifeLoseAi.class);
apiToClass.put(ApiType.LosesGame, GameLossAi.class);
apiToClass.put(ApiType.Mana, ManaEffectAi.class);
apiToClass.put(ApiType.ManaReflected, CannotPlayAi.class);
apiToClass.put(ApiType.Manifest, ManifestAi.class);
apiToClass.put(ApiType.Mill, MillAi.class);
apiToClass.put(ApiType.MoveCounter, CountersMoveAi.class);
apiToClass.put(ApiType.MultiplePiles, CannotPlayAi.class);
apiToClass.put(ApiType.MustAttack, MustAttackAi.class);
apiToClass.put(ApiType.MustBlock, MustBlockAi.class);
apiToClass.put(ApiType.NameCard, ChooseCardNameAi.class);
apiToClass.put(ApiType.PeekAndReveal, PeekAndRevealAi.class);
apiToClass.put(ApiType.PermanentCreature, PermanentCreatureAi.class);
apiToClass.put(ApiType.PermanentNoncreature, PermanentNoncreatureAi.class);
apiToClass.put(ApiType.Phases, PhasesAi.class);
apiToClass.put(ApiType.Planeswalk, AlwaysPlayAi.class);
apiToClass.put(ApiType.Play, PlayAi.class);
apiToClass.put(ApiType.PlayLandVariant, CannotPlayAi.class);
apiToClass.put(ApiType.Poison, PoisonAi.class);
apiToClass.put(ApiType.PreventDamage, DamagePreventAi.class);
apiToClass.put(ApiType.PreventDamageAll, DamagePreventAllAi.class);
apiToClass.put(ApiType.Proliferate, CountersProliferateAi.class);
apiToClass.put(ApiType.Protection, ProtectAi.class);
apiToClass.put(ApiType.ProtectionAll, ProtectAllAi.class);
apiToClass.put(ApiType.Pump, PumpAi.class);
apiToClass.put(ApiType.PumpAll, PumpAllAi.class);
apiToClass.put(ApiType.PutCounter, CountersPutAi.class);
apiToClass.put(ApiType.PutCounterAll, CountersPutAllAi.class);
apiToClass.put(ApiType.RearrangeTopOfLibrary, RearrangeTopOfLibraryAi.class);
apiToClass.put(ApiType.Regenerate, RegenerateAi.class);
apiToClass.put(ApiType.RegenerateAll, RegenerateAllAi.class);
apiToClass.put(ApiType.RemoveCounter, CountersRemoveAi.class);
apiToClass.put(ApiType.RemoveCounterAll, CannotPlayAi.class);
apiToClass.put(ApiType.RemoveFromCombat, RemoveFromCombatAi.class);
apiToClass.put(ApiType.ReorderZone, AlwaysPlayAi.class);
apiToClass.put(ApiType.Repeat, RepeatAi.class);
apiToClass.put(ApiType.RepeatEach, RepeatEachAi.class);
apiToClass.put(ApiType.RestartGame, RestartGameAi.class);
apiToClass.put(ApiType.Reveal, RevealAi.class);
apiToClass.put(ApiType.RevealHand, RevealHandAi.class);
apiToClass.put(ApiType.ReverseTurnOrder, AlwaysPlayAi.class);
apiToClass.put(ApiType.RollPlanarDice, RollPlanarDiceAi.class);
apiToClass.put(ApiType.RunSVarAbility, AlwaysPlayAi.class);
apiToClass.put(ApiType.Sacrifice, SacrificeAi.class);
apiToClass.put(ApiType.SacrificeAll, SacrificeAllAi.class);
apiToClass.put(ApiType.Scry, ScryAi.class);
apiToClass.put(ApiType.SetInMotion, AlwaysPlayAi.class);
apiToClass.put(ApiType.SetLife, LifeSetAi.class);
apiToClass.put(ApiType.SetState, SetStateAi.class);
apiToClass.put(ApiType.Shuffle, ShuffleAi.class);
apiToClass.put(ApiType.SkipTurn, SkipTurnAi.class);
apiToClass.put(ApiType.StoreMap, StoreMapAi.class);
apiToClass.put(ApiType.StoreSVar, StoreSVarAi.class);
apiToClass.put(ApiType.Tap, TapAi.class);
apiToClass.put(ApiType.TapAll, TapAllAi.class);
apiToClass.put(ApiType.TapOrUntap, TapOrUntapAi.class);
apiToClass.put(ApiType.TapOrUntapAll, TapOrUntapAllAi.class);
apiToClass.put(ApiType.Token, TokenAi.class);
apiToClass.put(ApiType.TwoPiles, TwoPilesAi.class);
apiToClass.put(ApiType.Unattach, CannotPlayAi.class);
apiToClass.put(ApiType.UnattachAll, UnattachAllAi.class);
apiToClass.put(ApiType.Untap, UntapAi.class);
apiToClass.put(ApiType.UntapAll, UntapAllAi.class);
apiToClass.put(ApiType.Vote, VoteAi.class);
apiToClass.put(ApiType.WinsGame, GameWinAi.class);
private final Map<ApiType, SpellAbilityAi> apiToInstance = new EnumMap<>(ApiType.class);
apiToClass.put(ApiType.InternalEtbReplacement, CanPlayAsDrawbackAi.class);
apiToClass.put(ApiType.InternalLegendaryRule, LegendaryRuleAi.class);
apiToClass.put(ApiType.InternalHaunt, HauntAi.class);
apiToClass.put(ApiType.InternalIgnoreEffect, CannotPlayAi.class);
}
public SpellAbilityAi get(ApiType api) {
// Do the extra copy to make an actual EnumMap (faster)
private final Map<ApiType, Class<? extends SpellAbilityAi>> apiToClass = Maps.newEnumMap(ImmutableMap
.<ApiType, Class<? extends SpellAbilityAi>>builder()
.put(ApiType.Abandon, AlwaysPlayAi.class)
.put(ApiType.ActivateAbility, ActivateAbilityAi.class)
.put(ApiType.AddOrRemoveCounter, CountersPutOrRemoveAi.class)
.put(ApiType.AddPhase, AddPhaseAi.class)
.put(ApiType.AddTurn, AddTurnAi.class)
.put(ApiType.Animate, AnimateAi.class)
.put(ApiType.AnimateAll, AnimateAllAi.class)
.put(ApiType.Attach, AttachAi.class)
.put(ApiType.Balance, BalanceAi.class)
.put(ApiType.BecomesBlocked, BecomesBlockedAi.class)
.put(ApiType.BidLife, BidLifeAi.class)
.put(ApiType.Bond, BondAi.class)
.put(ApiType.ChangeTargets, ChangeTargetsAi.class)
.put(ApiType.ChangeZone, ChangeZoneAi.class)
.put(ApiType.ChangeZoneAll, ChangeZoneAllAi.class)
.put(ApiType.Charm, CharmAi.class)
.put(ApiType.ChooseCard, ChooseCardAi.class)
.put(ApiType.ChooseColor, ChooseColorAi.class)
.put(ApiType.ChooseDirection, ChooseDirectionAi.class)
.put(ApiType.ChooseNumber, ChooseNumberAi.class)
.put(ApiType.ChoosePlayer, ChoosePlayerAi.class)
.put(ApiType.ChooseSource, ChooseSourceAi.class)
.put(ApiType.ChooseType, ChooseTypeAi.class)
.put(ApiType.Clash, ClashAi.class)
.put(ApiType.Cleanup, AlwaysPlayAi.class)
.put(ApiType.Clone, CloneAi.class)
.put(ApiType.CopyPermanent, CopyPermanentAi.class)
.put(ApiType.CopySpellAbility, CanPlayAsDrawbackAi.class)
.put(ApiType.ControlPlayer, CannotPlayAi.class)
.put(ApiType.ControlSpell, CannotPlayAi.class)
.put(ApiType.Counter, CounterAi.class)
.put(ApiType.DamageAll, DamageAllAi.class)
.put(ApiType.DealDamage, DamageDealAi.class)
.put(ApiType.Debuff, DebuffAi.class)
.put(ApiType.DeclareCombatants, CannotPlayAi.class)
.put(ApiType.DelayedTrigger, DelayedTriggerAi.class)
.put(ApiType.Destroy, DestroyAi.class)
.put(ApiType.DestroyAll, DestroyAllAi.class)
.put(ApiType.Dig, DigAi.class)
.put(ApiType.DigUntil, DigUntilAi.class)
.put(ApiType.Discard, DiscardAi.class)
.put(ApiType.DrainMana, DrainManaAi.class)
.put(ApiType.Draw, DrawAi.class)
.put(ApiType.EachDamage, DamageEachAi.class)
.put(ApiType.Effect, EffectAi.class)
.put(ApiType.Encode, EncodeAi.class)
.put(ApiType.EndTurn, EndTurnAi.class)
.put(ApiType.ExchangeLife, LifeExchangeAi.class)
.put(ApiType.ExchangeControl, ControlExchangeAi.class)
.put(ApiType.ExchangeControlVariant, CannotPlayAi.class)
.put(ApiType.ExchangePower, PowerExchangeAi.class)
.put(ApiType.ExchangeZone, ZoneExchangeAi.class)
.put(ApiType.Fight, FightAi.class)
.put(ApiType.FlipACoin, FlipACoinAi.class)
.put(ApiType.Fog, FogAi.class)
.put(ApiType.GainControl, ControlGainAi.class)
.put(ApiType.GainLife, LifeGainAi.class)
.put(ApiType.GainOwnership, CannotPlayAi.class)
.put(ApiType.GenericChoice, ChooseGenericEffectAi.class)
.put(ApiType.LoseLife, LifeLoseAi.class)
.put(ApiType.LosesGame, GameLossAi.class)
.put(ApiType.Mana, ManaEffectAi.class)
.put(ApiType.ManaReflected, CannotPlayAi.class)
.put(ApiType.Manifest, ManifestAi.class)
.put(ApiType.Mill, MillAi.class)
.put(ApiType.MoveCounter, CountersMoveAi.class)
.put(ApiType.MultiplePiles, CannotPlayAi.class)
.put(ApiType.MustAttack, MustAttackAi.class)
.put(ApiType.MustBlock, MustBlockAi.class)
.put(ApiType.NameCard, ChooseCardNameAi.class)
.put(ApiType.PeekAndReveal, PeekAndRevealAi.class)
.put(ApiType.PermanentCreature, PermanentCreatureAi.class)
.put(ApiType.PermanentNoncreature, PermanentNoncreatureAi.class)
.put(ApiType.Phases, PhasesAi.class)
.put(ApiType.Planeswalk, AlwaysPlayAi.class)
.put(ApiType.Play, PlayAi.class)
.put(ApiType.PlayLandVariant, CannotPlayAi.class)
.put(ApiType.Poison, PoisonAi.class)
.put(ApiType.PreventDamage, DamagePreventAi.class)
.put(ApiType.PreventDamageAll, DamagePreventAllAi.class)
.put(ApiType.Proliferate, CountersProliferateAi.class)
.put(ApiType.Protection, ProtectAi.class)
.put(ApiType.ProtectionAll, ProtectAllAi.class)
.put(ApiType.Pump, PumpAi.class)
.put(ApiType.PumpAll, PumpAllAi.class)
.put(ApiType.PutCounter, CountersPutAi.class)
.put(ApiType.PutCounterAll, CountersPutAllAi.class)
.put(ApiType.RearrangeTopOfLibrary, RearrangeTopOfLibraryAi.class)
.put(ApiType.Regenerate, RegenerateAi.class)
.put(ApiType.RegenerateAll, RegenerateAllAi.class)
.put(ApiType.RemoveCounter, CountersRemoveAi.class)
.put(ApiType.RemoveCounterAll, CannotPlayAi.class)
.put(ApiType.RemoveFromCombat, RemoveFromCombatAi.class)
.put(ApiType.ReorderZone, AlwaysPlayAi.class)
.put(ApiType.Repeat, RepeatAi.class)
.put(ApiType.RepeatEach, RepeatEachAi.class)
.put(ApiType.RestartGame, RestartGameAi.class)
.put(ApiType.Reveal, RevealAi.class)
.put(ApiType.RevealHand, RevealHandAi.class)
.put(ApiType.ReverseTurnOrder, AlwaysPlayAi.class)
.put(ApiType.RollPlanarDice, RollPlanarDiceAi.class)
.put(ApiType.RunSVarAbility, AlwaysPlayAi.class)
.put(ApiType.Sacrifice, SacrificeAi.class)
.put(ApiType.SacrificeAll, SacrificeAllAi.class)
.put(ApiType.Scry, ScryAi.class)
.put(ApiType.SetInMotion, AlwaysPlayAi.class)
.put(ApiType.SetLife, LifeSetAi.class)
.put(ApiType.SetState, SetStateAi.class)
.put(ApiType.Shuffle, ShuffleAi.class)
.put(ApiType.SkipTurn, SkipTurnAi.class)
.put(ApiType.StoreMap, StoreMapAi.class)
.put(ApiType.StoreSVar, StoreSVarAi.class)
.put(ApiType.Tap, TapAi.class)
.put(ApiType.TapAll, TapAllAi.class)
.put(ApiType.TapOrUntap, TapOrUntapAi.class)
.put(ApiType.TapOrUntapAll, TapOrUntapAllAi.class)
.put(ApiType.Token, TokenAi.class)
.put(ApiType.TwoPiles, TwoPilesAi.class)
.put(ApiType.Unattach, CannotPlayAi.class)
.put(ApiType.UnattachAll, UnattachAllAi.class)
.put(ApiType.Untap, UntapAi.class)
.put(ApiType.UntapAll, UntapAllAi.class)
.put(ApiType.Vote, VoteAi.class)
.put(ApiType.WinsGame, GameWinAi.class)
.put(ApiType.InternalEtbReplacement, CanPlayAsDrawbackAi.class)
.put(ApiType.InternalLegendaryRule, LegendaryRuleAi.class)
.put(ApiType.InternalHaunt, HauntAi.class)
.put(ApiType.InternalIgnoreEffect, CannotPlayAi.class)
.build());
public SpellAbilityAi get(final ApiType api) {
SpellAbilityAi result = apiToInstance.get(api);
if( null == result ) {
if (null == result) {
Class<? extends SpellAbilityAi> clz = apiToClass.get(api);
if(null == clz) {
if (null == clz) {
System.err.println("No AI assigned for API: " + api);
clz = CannotPlayAi.class;
}

View File

@@ -738,9 +738,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (source.isInZone(ZoneType.Hand)) {
list = CardLists.filter(list, Predicates.not(CardPredicates.nameEquals(source.getName()))); // Don't get the same card back.
}
System.out.println("isPreferredTarget " + list);
//System.out.println("isPreferredTarget " + list);
if (sa.hasParam("AttachedTo")) {
System.out.println("isPreferredTarget att " + list);
//System.out.println("isPreferredTarget att " + list);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
@@ -752,7 +752,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
return false;
}
});
System.out.println("isPreferredTarget ok " + list);
//System.out.println("isPreferredTarget ok " + list);
}
if (list.size() < tgt.getMinTargets(sa.getHostCard(), sa)) {

View File

@@ -1,6 +1,9 @@
package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
@@ -22,8 +25,6 @@ import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.List;
public class ChooseSourceAi extends SpellAbilityAi {
/* (non-Javadoc)
@@ -184,4 +185,10 @@ public class ChooseSourceAi extends SpellAbilityAi {
}
return null;
}
private static List<GameObject> getTargets(final SpellAbility sa) {
return sa.usesTargeting() && (!sa.hasParam("Defined"))
? Lists.newArrayList(sa.getTargets().getTargets())
: AbilityUtils.getDefinedObjects(sa.getHostCard(), sa.getParam("Defined"), sa);
}
}

View File

@@ -146,7 +146,7 @@ public class DamagePreventAi extends SpellAbilityAi {
}
}
}
if (sa.hasParam("DividedAsYouChoose") && sa.getTargets() != null && !sa.getTargets().getTargets().isEmpty()) {
if (tgt != null && sa.hasParam("DividedAsYouChoose") && sa.getTargets() != null && !sa.getTargets().getTargets().isEmpty()) {
tgt.addDividedAllocation(sa.getTargets().getTargets().get(0), AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Amount"), sa));
}

View File

@@ -11,6 +11,7 @@ import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.util.FCollection;
import java.util.List;
@@ -19,7 +20,9 @@ public class LifeLoseAi extends SpellAbilityAi {
@Override
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
List<Player> tgtPlayers = getTargetPlayers(sa);
final List<Player> tgtPlayers = sa.usesTargeting() && !sa.hasParam("Defined")
? new FCollection<Player>(sa.getTargets().getTargetPlayers())
: AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Defined"), sa);
final Card source = sa.getHostCard();
final String amountStr = sa.getParam("LifeAmount");
@@ -158,7 +161,9 @@ public class LifeLoseAi extends SpellAbilityAi {
amount = AbilityUtils.calculateAmount(source, amountStr, sa);
}
List<Player> tgtPlayers = getTargetPlayers(sa);
final List<Player> tgtPlayers = sa.usesTargeting() && !sa.hasParam("Defined")
? new FCollection<Player>(sa.getTargets().getTargetPlayers())
: AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Defined"), sa);
if (!mandatory && tgtPlayers.contains(ai) && amount > 0 && amount + 3 > ai.getLife()) {
// For cards like Foul Imp, ETB you lose life

View File

@@ -1,5 +1,7 @@
package forge.ai.ability;
import java.util.List;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
@@ -9,8 +11,7 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.List;
import forge.util.FCollection;
public class TwoPilesAi extends SpellAbilityAi {
@Override
@@ -37,7 +38,9 @@ public class TwoPilesAi extends SpellAbilityAi {
}
}
List<Player> tgtPlayers = getTargetPlayers(sa);
final List<Player> tgtPlayers = sa.usesTargeting() && !sa.hasParam("Defined")
? new FCollection<Player>(sa.getTargets().getTargetPlayers())
: AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Defined"), sa);
final Player p = tgtPlayers.get(0);
CardCollectionView pool;