remove AI class from ApiType

This commit is contained in:
Maxmtg
2014-02-09 21:01:34 +00:00
parent 0f37de9627
commit dd34a3aa9b
11 changed files with 273 additions and 160 deletions

1
.gitattributes vendored
View File

@@ -139,6 +139,7 @@ forge-game/src/main/java/forge/ai/ComputerUtilMana.java -text
forge-game/src/main/java/forge/ai/LobbyPlayerAi.java -text forge-game/src/main/java/forge/ai/LobbyPlayerAi.java -text
forge-game/src/main/java/forge/ai/PlayerControllerAi.java -text forge-game/src/main/java/forge/ai/PlayerControllerAi.java -text
forge-game/src/main/java/forge/ai/SpellAbilityAi.java -text forge-game/src/main/java/forge/ai/SpellAbilityAi.java -text
forge-game/src/main/java/forge/ai/SpellApiToAi.java -text
forge-game/src/main/java/forge/ai/ability/AddPhaseAi.java -text forge-game/src/main/java/forge/ai/ability/AddPhaseAi.java -text
forge-game/src/main/java/forge/ai/ability/AddTurnAi.java svneol=native#text/plain forge-game/src/main/java/forge/ai/ability/AddTurnAi.java svneol=native#text/plain
forge-game/src/main/java/forge/ai/ability/AlwaysPlayAi.java -text forge-game/src/main/java/forge/ai/ability/AlwaysPlayAi.java -text

View File

@@ -616,7 +616,7 @@ public class AiController {
return canPlaySa(((WrappedAbility) sa).getWrappedAbility()); return canPlaySa(((WrappedAbility) sa).getWrappedAbility());
} }
if( sa.getApi() != null ) { if( sa.getApi() != null ) {
boolean canPlay = sa.getApi().getAi().canPlayAIWithSubs(player, sa); boolean canPlay = SpellApiToAi.Converter.get(sa.getApi()).canPlayAIWithSubs(player, sa);
if(!canPlay) if(!canPlay)
return AiPlayDecision.CantPlayAi; return AiPlayDecision.CantPlayAi;
} }
@@ -876,7 +876,7 @@ public class AiController {
throw new IllegalArgumentException(exMsg); throw new IllegalArgumentException(exMsg);
} else } else
return api.getAi().confirmAction(player, sa, mode, message); return SpellApiToAi.Converter.get(api).confirmAction(player, sa, mode, message);
} }
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) { public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
@@ -940,9 +940,9 @@ public class AiController {
{ {
boolean chance = false; boolean chance = false;
if (withoutPayingManaCost) { if (withoutPayingManaCost) {
chance = spell.getApi().getAi().doTriggerNoCostWithSubs(player, spell, mandatory); chance = SpellApiToAi.Converter.get(spell.getApi()).doTriggerNoCostWithSubs(player, spell, mandatory);
} else { } else {
chance = spell.getApi().getAi().doTriggerAI(player, spell, mandatory); chance = SpellApiToAi.Converter.get(spell.getApi()).doTriggerAI(player, spell, mandatory);
} }
if (!chance) if (!chance)
return AiPlayDecision.TargetingFailed; return AiPlayDecision.TargetingFailed;
@@ -1148,7 +1148,7 @@ public class AiController {
public boolean doTrigger(SpellAbility spell, boolean mandatory) { public boolean doTrigger(SpellAbility spell, boolean mandatory) {
if ( spell.getApi() != null ) if ( spell.getApi() != null )
return spell.getApi().getAi().doTriggerAI(player, spell, mandatory); return SpellApiToAi.Converter.get(spell.getApi()).doTriggerAI(player, spell, mandatory);
if ( spell instanceof WrappedAbility ) if ( spell instanceof WrappedAbility )
return doTrigger(((WrappedAbility)spell).getWrappedAbility(), mandatory); return doTrigger(((WrappedAbility)spell).getWrappedAbility(), mandatory);

View File

@@ -3,6 +3,7 @@ package forge.ai;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaAtom; import forge.card.mana.ManaAtom;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
@@ -28,6 +29,7 @@ import forge.util.CollectionSuppliers;
import forge.util.TextUtil; import forge.util.TextUtil;
import forge.util.maps.EnumMapOfLists; import forge.util.maps.EnumMapOfLists;
import forge.util.maps.MapOfLists; import forge.util.maps.MapOfLists;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.*; import java.util.*;
@@ -630,7 +632,7 @@ public class ComputerUtilMana {
// don't use abilities with dangerous drawbacks // don't use abilities with dangerous drawbacks
AbilitySub sub = m.getSubAbility(); AbilitySub sub = m.getSubAbility();
if (sub != null && !card.getName().equals("Pristine Talisman") && !card.getName().equals("Zhur-Taa Druid")) { if (sub != null && !card.getName().equals("Pristine Talisman") && !card.getName().equals("Zhur-Taa Druid")) {
if (!sub.getApi().getAi().chkDrawbackWithSubs(ai, sub)) { if (!SpellApiToAi.Converter.get(sub.getApi()).chkDrawbackWithSubs(ai, sub)) {
continue; continue;
} }
needsLimitedResources = true; // TODO: check for good drawbacks (gainLife) needsLimitedResources = true; // TODO: check for good drawbacks (gainLife)
@@ -688,7 +690,7 @@ public class ComputerUtilMana {
// don't use abilities with dangerous drawbacks // don't use abilities with dangerous drawbacks
AbilitySub sub = m.getSubAbility(); AbilitySub sub = m.getSubAbility();
if (sub != null) { if (sub != null) {
if (!sub.getApi().getAi().chkDrawbackWithSubs(ai, sub)) { if (!SpellApiToAi.Converter.get(sub.getApi()).chkDrawbackWithSubs(ai, sub)) {
continue; continue;
} }
} }

View File

@@ -134,7 +134,7 @@ public class PlayerControllerAi extends PlayerController {
if (null == api) { if (null == api) {
throw new InvalidParameterException("SA is not api-based, this is not supported yet"); throw new InvalidParameterException("SA is not api-based, this is not supported yet");
} }
return api.getAi().chooseSingleEntity(player, sa, options, isOptional, targetedPlayer); return SpellApiToAi.Converter.get(api).chooseSingleEntity(player, sa, options, isOptional, targetedPlayer);
} }
@Override @Override
@@ -143,7 +143,7 @@ public class PlayerControllerAi extends PlayerController {
if (null == api) { if (null == api) {
throw new InvalidParameterException("SA is not api-based, this is not supported yet"); throw new InvalidParameterException("SA is not api-based, this is not supported yet");
} }
return api.getAi().chooseSingleSpellAbility(player, sa, spells); return SpellApiToAi.Converter.get(api).chooseSingleSpellAbility(player, sa, spells);
} }
@Override @Override

View File

@@ -2,6 +2,7 @@ package forge.ai;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.ability.SaTargetRoutines; import forge.game.ability.SaTargetRoutines;
import forge.game.card.Card; import forge.game.card.Card;
@@ -136,7 +137,7 @@ public abstract class SpellAbilityAi extends SaTargetRoutines {
*/ */
public boolean chkDrawbackWithSubs(Player aiPlayer, AbilitySub ab) { public boolean chkDrawbackWithSubs(Player aiPlayer, AbilitySub ab) {
final AbilitySub subAb = ab.getSubAbility(); final AbilitySub subAb = ab.getSubAbility();
return ab.getApi().getAi().chkAIDrawback(ab, aiPlayer) && (subAb == null || chkDrawbackWithSubs(aiPlayer, subAb)); return SpellApiToAi.Converter.get(ab.getApi()).chkAIDrawback(ab, aiPlayer) && (subAb == null || chkDrawbackWithSubs(aiPlayer, subAb));
} }
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) { public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {

View File

@@ -0,0 +1,122 @@
package forge.ai;
import java.util.EnumMap;
import forge.ai.ability.*;
import forge.game.ability.ApiType;
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.DamageAll, DamageAllAi.class);
apiToClass.put(ApiType.DealDamage, DamageDealAi.class);
apiToClass.put(ApiType.Debuff, DebuffAi.class);
apiToClass.put(ApiType.DebuffAll, DebuffAllAi.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.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.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.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.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, CannotPlayAi.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.UnattachAll, UnattachAllAi.class);
apiToClass.put(ApiType.Untap, UntapAi.class);
apiToClass.put(ApiType.UntapAll, UntapAllAi.class);
apiToClass.put(ApiType.WinsGame, GameWinAi.class);
apiToClass.put(ApiType.InternalEtbReplacement, CanPlayAsDrawbackAi.class);
apiToClass.put(ApiType.InternalLegendaryRule, LegendaryRuleAi.class);
apiToClass.put(ApiType.InternalHaunt, HauntAi.class);
}
public SpellAbilityAi get(ApiType api) {
SpellAbilityAi result = apiToInstance.get(api);
if( null == result ) {
Class<? extends SpellAbilityAi> clz = apiToClass.get(api);
if(null == clz) {
System.err.println("No AI assigned for API: " + api);
clz = CannotPlayAi.class;
}
result = ReflectionUtil.makeDefaultInstanceOf(clz);
apiToInstance.put(api, result);
}
return result;
}
}

View File

@@ -4,6 +4,7 @@ import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.ai.*; import forge.ai.*;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.game.Game; import forge.game.Game;
@@ -307,7 +308,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
final AbilitySub subAb = sa.getSubAbility(); final AbilitySub subAb = sa.getSubAbility();
return subAb == null || subAb.getApi().getAi().chkDrawbackWithSubs(ai, subAb); return subAb == null || SpellApiToAi.Converter.get(subAb.getApi()).chkDrawbackWithSubs(ai, subAb);
} }
/** /**
@@ -645,7 +646,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} }
final AbilitySub subAb = sa.getSubAbility(); final AbilitySub subAb = sa.getSubAbility();
chance &= subAb == null || subAb.getApi().getAi().chkDrawbackWithSubs(ai, subAb); chance &= subAb == null || SpellApiToAi.Converter.get(subAb.getApi()).chkDrawbackWithSubs(ai, subAb);
return chance; return chance;
} }

View File

@@ -4,6 +4,7 @@ import forge.ai.AiController;
import forge.ai.AiPlayDecision; import forge.ai.AiPlayDecision;
import forge.ai.PlayerControllerAi; import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.AbilitySub; import forge.game.spellability.AbilitySub;
@@ -18,7 +19,7 @@ public class DelayedTriggerAi extends SpellAbilityAi {
trigsa.setActivatingPlayer(ai); trigsa.setActivatingPlayer(ai);
if (trigsa instanceof AbilitySub) { if (trigsa instanceof AbilitySub) {
return ((AbilitySub) trigsa).getApi().getAi().chkDrawbackWithSubs(ai, (AbilitySub)trigsa); return SpellApiToAi.Converter.get(((AbilitySub) trigsa).getApi()).chkDrawbackWithSubs(ai, (AbilitySub)trigsa);
} else { } else {
return AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(trigsa); return AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(trigsa);
} }

View File

@@ -1,6 +1,7 @@
package forge.ai.ability; package forge.ai.ability;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode; import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.AbilityStatic; import forge.game.spellability.AbilityStatic;
@@ -32,7 +33,7 @@ public class PeekAndRevealAi extends SpellAbilityAi {
@Override @Override
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) { public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
AbilitySub subAb = sa.getSubAbility(); AbilitySub subAb = sa.getSubAbility();
return subAb != null && subAb.getApi().getAi().chkDrawbackWithSubs(player, subAb); return subAb != null && SpellApiToAi.Converter.get(subAb.getApi()).chkDrawbackWithSubs(player, subAb);
} }
} }

View File

@@ -1,8 +1,6 @@
package forge.game.ability; package forge.game.ability;
import forge.ai.SpellAbilityAi;
import forge.ai.ability.*;
import forge.game.ability.effects.*; import forge.game.ability.effects.*;
import forge.util.ReflectionUtil; import forge.util.ReflectionUtil;
@@ -14,156 +12,144 @@ import java.util.TreeMap;
* *
*/ */
public enum ApiType { public enum ApiType {
Abandon (AbandonEffect.class),
AddOrRemoveCounter (CountersPutOrRemoveEffect.class),
AddPhase (AddPhaseEffect.class),
AddTurn (AddTurnEffect.class),
Animate (AnimateEffect.class),
AnimateAll (AnimateAllEffect.class),
Attach (AttachEffect.class),
Balance (BalanceEffect.class),
BecomesBlocked (BecomesBlockedEffect.class),
Bond (BondEffect.class),
ChangeTargets (ChangeTargetsEffect.class),
ChangeZone (ChangeZoneEffect.class),
ChangeZoneAll (ChangeZoneAllEffect.class),
Charm (CharmEffect.class),
ChooseCard (ChooseCardEffect.class),
ChooseColor (ChooseColorEffect.class),
ChooseNumber (ChooseNumberEffect.class),
ChoosePlayer (ChoosePlayerEffect.class),
ChooseSource (ChooseSourceEffect.class),
ChooseType (ChooseTypeEffect.class),
Clash (ClashEffect.class),
Cleanup (CleanUpEffect.class),
Clone (CloneEffect.class),
CopyPermanent (CopyPermanentEffect.class),
CopySpellAbility (CopySpellAbilityEffect.class),
ControlPlayer (ControlPlayerEffect.class),
Counter (CounterEffect.class),
DamageAll (DamageAllEffect.class),
DealDamage (DamageDealEffect.class),
Debuff (DebuffEffect.class),
DebuffAll (DebuffAllEffect.class),
DeclareCombatants (DeclareCombatantsEffect.class),
DelayedTrigger (DelayedTriggerEffect.class),
Destroy (DestroyEffect.class),
DestroyAll (DestroyAllEffect.class),
Dig (DigEffect.class),
DigUntil (DigUntilEffect.class),
Discard (DiscardEffect.class),
DrainMana (DrainManaEffect.class),
Draw (DrawEffect.class),
EachDamage (DamageEachEffect.class),
Effect (EffectEffect.class),
Encode (EncodeEffect.class),
EndTurn (EndTurnEffect.class),
ExchangeLife (LifeExchangeEffect.class),
ExchangeControl (ControlExchangeEffect.class),
ExchangePower (PowerExchangeEffect.class),
ExchangeZone (ZoneExchangeEffect.class),
Fight (FightEffect.class),
FlipACoin (FlipCoinEffect.class),
Fog (FogEffect.class),
GainControl (ControlGainEffect.class),
GainLife (LifeGainEffect.class),
GainOwnership (OwnershipGainEffect.class),
GenericChoice (ChooseGenericEffect.class),
LoseLife (LifeLoseEffect.class),
LosesGame (GameLossEffect.class),
Mana (ManaEffect.class),
ManaReflected (ManaReflectedEffect.class),
Mill (MillEffect.class),
MoveCounter (CountersMoveEffect.class),
MultiplePiles (MultiplePilesEffect.class),
MustAttack (MustAttackEffect.class),
MustBlock (MustBlockEffect.class),
NameCard (ChooseCardNameEffect.class),
PeekAndReveal (PeekAndRevealEffect.class),
PermanentCreature (PermanentCreatureEffect.class),
PermanentNoncreature (PermanentNoncreatureEffect.class),
Phases (PhasesEffect.class),
Planeswalk (PlaneswalkEffect.class),
Play (PlayEffect.class),
Poison (PoisonEffect.class),
PreventDamage (DamagePreventEffect.class),
PreventDamageAll (DamagePreventAllEffect.class),
Proliferate (CountersProliferateEffect.class),
Protection (ProtectEffect.class),
ProtectionAll (ProtectAllEffect.class),
Pump (PumpEffect.class),
PumpAll (PumpAllEffect.class),
PutCounter (CountersPutEffect.class),
PutCounterAll (CountersPutAllEffect.class),
RearrangeTopOfLibrary (RearrangeTopOfLibraryEffect.class),
Regenerate (RegenerateEffect.class),
RegenerateAll (RegenerateAllEffect.class),
RemoveCounter (CountersRemoveEffect.class),
RemoveCounterAll (CountersRemoveAllEffect.class),
RemoveFromCombat (RemoveFromCombatEffect.class),
ReorderZone (ReorderZoneEffect.class),
Repeat (RepeatEffect.class),
RepeatEach (RepeatEachEffect.class),
RestartGame (RestartGameEffect.class),
Reveal (RevealEffect.class),
RevealHand (RevealHandEffect.class),
RollPlanarDice (RollPlanarDiceEffect.class),
RunSVarAbility (RunSVarAbilityEffect.class),
Sacrifice (SacrificeEffect.class),
SacrificeAll (SacrificeAllEffect.class),
Scry (ScryEffect.class),
SetInMotion (SetInMotionEffect.class),
SetLife (LifeSetEffect.class),
SetState (SetStateEffect.class),
Shuffle (ShuffleEffect.class),
SkipTurn (SkipTurnEffect.class),
StoreSVar (StoreSVarEffect.class),
Tap (TapEffect.class),
TapAll (TapAllEffect.class),
TapOrUntap (TapOrUntapEffect.class),
TapOrUntapAll (TapOrUntapAllEffect.class),
Token (TokenEffect.class, false),
TwoPiles (TwoPilesEffect.class),
UnattachAll (UnattachAllEffect.class),
Untap (UntapEffect.class),
UntapAll (UntapAllEffect.class),
WinsGame (GameWinEffect.class),
InternalEtbReplacement (ETBReplacementEffect.class),
InternalLegendaryRule (CharmEffect.class),
InternalHaunt (CharmEffect.class);
Abandon (AbandonEffect.class, AlwaysPlayAi.class),
AddOrRemoveCounter (CountersPutOrRemoveEffect.class, CountersPutOrRemoveAi.class),
AddPhase (AddPhaseEffect.class, AddPhaseAi.class),
AddTurn (AddTurnEffect.class, AddTurnAi.class),
Animate (AnimateEffect.class, AnimateAi.class),
AnimateAll (AnimateAllEffect.class, AnimateAllAi.class),
Attach (AttachEffect.class, AttachAi.class),
Balance (BalanceEffect.class, BalanceAi.class),
BecomesBlocked (BecomesBlockedEffect.class, BecomesBlockedAi.class),
Bond (BondEffect.class, BondAi.class),
ChangeTargets(ChangeTargetsEffect.class, ChangeTargetsAi.class),
ChangeZone(ChangeZoneEffect.class, ChangeZoneAi.class),
ChangeZoneAll(ChangeZoneAllEffect.class, ChangeZoneAllAi.class),
/** This is <b>Modal</b>, like 'choose one - ' or 'choose two - '. <br> Might be great to rename this api and update all scripts.*/
Charm(CharmEffect.class, CharmAi.class),
ChooseCard (ChooseCardEffect.class, ChooseCardAi.class),
ChooseColor (ChooseColorEffect.class, ChooseColorAi.class),
ChooseNumber (ChooseNumberEffect.class, CannotPlayAi.class),
ChoosePlayer (ChoosePlayerEffect.class, ChoosePlayerAi.class),
ChooseSource (ChooseSourceEffect.class, ChooseSourceAi.class),
ChooseType (ChooseTypeEffect.class, ChooseTypeAi.class),
Clash (ClashEffect.class, ClashAi.class),
Cleanup (CleanUpEffect.class, AlwaysPlayAi.class),
Clone (CloneEffect.class, CloneAi.class),
CopyPermanent (CopyPermanentEffect.class, CopyPermanentAi.class),
CopySpellAbility (CopySpellAbilityEffect.class, CanPlayAsDrawbackAi.class),
ControlPlayer(ControlPlayerEffect.class, CannotPlayAi.class),
Counter (CounterEffect.class, CounterAi.class),
DamageAll (DamageAllEffect.class, DamageAllAi.class),
DealDamage (DamageDealEffect.class, DamageDealAi.class),
Debuff (DebuffEffect.class, DebuffAi.class),
DebuffAll (DebuffAllEffect.class, DebuffAllAi.class),
DeclareCombatants(DeclareCombatantsEffect.class, CannotPlayAi.class),
DelayedTrigger (DelayedTriggerEffect.class, DelayedTriggerAi.class),
Destroy (DestroyEffect.class, DestroyAi.class),
DestroyAll (DestroyAllEffect.class, DestroyAllAi.class),
Dig (DigEffect.class, DigAi.class),
DigUntil (DigUntilEffect.class, DigUntilAi.class),
Discard (DiscardEffect.class, DiscardAi.class),
DrainMana (DrainManaEffect.class, DrainManaAi.class),
Draw (DrawEffect.class, DrawAi.class),
EachDamage (DamageEachEffect.class, DamageEachAi.class),
Effect (EffectEffect.class, EffectAi.class),
Encode (EncodeEffect.class, EncodeAi.class),
EndTurn (EndTurnEffect.class, EndTurnAi.class),
ExchangeLife (LifeExchangeEffect.class, LifeExchangeAi.class),
ExchangeControl (ControlExchangeEffect.class, ControlExchangeAi.class),
ExchangePower (PowerExchangeEffect.class, PowerExchangeAi.class),
ExchangeZone (ZoneExchangeEffect.class, ZoneExchangeAi.class),
Fight (FightEffect.class, FightAi.class),
FlipACoin (FlipCoinEffect.class, FlipACoinAi.class),
Fog (FogEffect.class, FogAi.class),
GainControl (ControlGainEffect.class, ControlGainAi.class),
GainLife (LifeGainEffect.class, LifeGainAi.class),
GainOwnership(OwnershipGainEffect.class, CannotPlayAi.class),
GenericChoice (ChooseGenericEffect.class, ChooseGenericEffectAi.class),
LoseLife (LifeLoseEffect.class, LifeLoseAi.class),
LosesGame (GameLossEffect.class, GameLossAi.class),
Mana (ManaEffect.class, ManaEffectAi.class),
ManaReflected (ManaReflectedEffect.class, CannotPlayAi.class),
Mill (MillEffect.class, MillAi.class),
MoveCounter (CountersMoveEffect.class, CountersMoveAi.class),
MultiplePiles (MultiplePilesEffect.class, CannotPlayAi.class),
MustAttack (MustAttackEffect.class, MustAttackAi.class),
MustBlock (MustBlockEffect.class, MustBlockAi.class),
NameCard (ChooseCardNameEffect.class, ChooseCardNameAi.class),
PeekAndReveal (PeekAndRevealEffect.class, PeekAndRevealAi.class),
PermanentCreature (PermanentCreatureEffect.class, PermanentCreatureAi.class),
PermanentNoncreature (PermanentNoncreatureEffect.class, PermanentNoncreatureAi.class),
Phases (PhasesEffect.class, PhasesAi.class),
Planeswalk(PlaneswalkEffect.class, AlwaysPlayAi.class),
Play (PlayEffect.class, PlayAi.class),
Poison (PoisonEffect.class, PoisonAi.class),
PreventDamage (DamagePreventEffect.class, DamagePreventAi.class),
PreventDamageAll (DamagePreventAllEffect.class, DamagePreventAllAi.class),
Proliferate (CountersProliferateEffect.class, CountersProliferateAi.class),
Protection (ProtectEffect.class, ProtectAi.class),
ProtectionAll (ProtectAllEffect.class, ProtectAllAi.class),
Pump (PumpEffect.class, PumpAi.class),
PumpAll (PumpAllEffect.class, PumpAllAi.class),
PutCounter (CountersPutEffect.class, CountersPutAi.class),
PutCounterAll (CountersPutAllEffect.class, CountersPutAllAi.class),
RearrangeTopOfLibrary (RearrangeTopOfLibraryEffect.class, RearrangeTopOfLibraryAi.class),
Regenerate (RegenerateEffect.class, RegenerateAi.class),
RegenerateAll (RegenerateAllEffect.class, RegenerateAllAi.class),
RemoveCounter (CountersRemoveEffect.class, CountersRemoveAi.class),
RemoveCounterAll (CountersRemoveAllEffect.class, CannotPlayAi.class),
RemoveFromCombat (RemoveFromCombatEffect.class, RemoveFromCombatAi.class),
ReorderZone (ReorderZoneEffect.class, AlwaysPlayAi.class),
Repeat (RepeatEffect.class, RepeatAi.class),
RepeatEach (RepeatEachEffect.class, RepeatEachAi.class),
RestartGame (RestartGameEffect.class, RestartGameAi.class),
Reveal (RevealEffect.class, RevealAi.class),
RevealHand (RevealHandEffect.class, RevealHandAi.class),
RollPlanarDice (RollPlanarDiceEffect.class, RollPlanarDiceAi.class),
RunSVarAbility (RunSVarAbilityEffect.class, AlwaysPlayAi.class),
Sacrifice (SacrificeEffect.class, SacrificeAi.class),
SacrificeAll (SacrificeAllEffect.class, SacrificeAllAi.class),
Scry (ScryEffect.class, ScryAi.class),
SetInMotion (SetInMotionEffect.class, AlwaysPlayAi.class),
SetLife (LifeSetEffect.class, LifeSetAi.class),
SetState (SetStateEffect.class, SetStateAi.class),
Shuffle (ShuffleEffect.class, ShuffleAi.class),
SkipTurn (SkipTurnEffect.class, CannotPlayAi.class),
StoreSVar (StoreSVarEffect.class, StoreSVarAi.class),
Tap (TapEffect.class, TapAi.class),
TapAll (TapAllEffect.class, TapAllAi.class),
TapOrUntap (TapOrUntapEffect.class, TapOrUntapAi.class),
TapOrUntapAll (TapOrUntapAllEffect.class, TapOrUntapAllAi.class),
Token (TokenEffect.class, TokenAi.class, false), // Token AI and effect classes have state, they have to be re-created on each request
TwoPiles (TwoPilesEffect.class, TwoPilesAi.class),
UnattachAll (UnattachAllEffect.class, UnattachAllAi.class),
Untap (UntapEffect.class, UntapAi.class),
UntapAll (UntapAllEffect.class, UntapAllAi.class),
WinsGame (GameWinEffect.class, GameWinAi.class),
InternalEtbReplacement(ETBReplacementEffect.class, CanPlayAsDrawbackAi.class),
InternalLegendaryRule(CharmEffect.class, LegendaryRuleAi.class), // Charm has empty resolve blocks, may act as a dummy
InternalHaunt(CharmEffect.class, HauntAi.class);
private final Class<? extends SpellAbilityEffect> clsEffect;
private final Class<? extends SpellAbilityAi> clsAi;
private final SpellAbilityEffect instanceEffect; private final SpellAbilityEffect instanceEffect;
private final SpellAbilityAi instanceAi; private final Class<? extends SpellAbilityEffect> clsEffect;
private static final Map<String, ApiType> allValues = new TreeMap<String, ApiType>(String.CASE_INSENSITIVE_ORDER); private static final Map<String, ApiType> allValues = new TreeMap<String, ApiType>(String.CASE_INSENSITIVE_ORDER);
ApiType(Class<? extends SpellAbilityEffect> clsEf, Class<? extends SpellAbilityAi> clsAi) { ApiType(Class<? extends SpellAbilityEffect> clsEf) { this(clsEf, true); }
this(clsEf, clsAi, true); ApiType(Class<? extends SpellAbilityEffect> clsEf, final boolean isStateLess) {
}
ApiType(Class<? extends SpellAbilityEffect> clsEf, Class<? extends SpellAbilityAi> clsAI, final boolean isStateLess) {
clsEffect = clsEf; clsEffect = clsEf;
clsAi = clsAI;
instanceAi = isStateLess ? ReflectionUtil.makeDefaultInstanceOf(clsAi) : null;
instanceEffect = isStateLess ? ReflectionUtil.makeDefaultInstanceOf(clsEf) : null; instanceEffect = isStateLess ? ReflectionUtil.makeDefaultInstanceOf(clsEf) : null;
} }
public static ApiType smartValueOf(String value) { public static ApiType smartValueOf(String value) {
if (allValues.isEmpty()) if (allValues.isEmpty())
for(ApiType c : ApiType.values()) for(ApiType c : ApiType.values())
allValues.put(c.toString(), c); allValues.put(c.toString(), c);
ApiType v = allValues.get(value); ApiType v = allValues.get(value);
if ( v == null ) if ( v == null )
throw new RuntimeException("Element " + value + " not found in ApiType enum"); throw new RuntimeException("Element " + value + " not found in ApiType enum");
@@ -173,9 +159,4 @@ public enum ApiType {
public SpellAbilityEffect getSpellEffect() { public SpellAbilityEffect getSpellEffect() {
return instanceEffect != null ? instanceEffect : ReflectionUtil.makeDefaultInstanceOf(clsEffect); return instanceEffect != null ? instanceEffect : ReflectionUtil.makeDefaultInstanceOf(clsEffect);
} }
public SpellAbilityAi getAi() {
return instanceAi != null ? instanceAi : ReflectionUtil.makeDefaultInstanceOf(clsAi);
}
} }

View File

@@ -6,6 +6,8 @@ import com.google.common.collect.Multimap;
import forge.ai.ComputerUtil; import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilMana; import forge.ai.ComputerUtilMana;
import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.ai.ability.ChangeZoneAi; import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.DrawAi; import forge.ai.ability.DrawAi;
import forge.ai.ability.GameWinAi; import forge.ai.ability.GameWinAi;
@@ -96,10 +98,11 @@ public class PlayerControllerForTests extends PlayerController {
HumanPlay.playSpellAbilityNoStack(player, effectSA, !mayChoseNewTargets); HumanPlay.playSpellAbilityNoStack(player, effectSA, !mayChoseNewTargets);
return; return;
} }
SpellAbilityAi sai = SpellApiToAi.Converter.get(effectSA.getApi());
if ( if (
(effectSA.getHostCard().getName().equals("Nefarious Lich") && effectSA.getApi().getAi() instanceof DrawAi) || (effectSA.getHostCard().getName().equals("Nefarious Lich") && sai instanceof DrawAi) ||
(effectSA.getHostCard().getName().equals("Laboratory Maniac") && effectSA.getApi().getAi() instanceof GameWinAi) || (effectSA.getHostCard().getName().equals("Laboratory Maniac") && sai instanceof GameWinAi) ||
(effectSA.getHostCard().getName().equals("Nefarious Lich") && effectSA.getApi().getAi() instanceof ChangeZoneAi) (effectSA.getHostCard().getName().equals("Nefarious Lich") && sai instanceof ChangeZoneAi)
) {//test_104_3f_if_a_player_would_win_and_lose_simultaneously_he_loses ) {//test_104_3f_if_a_player_would_win_and_lose_simultaneously_he_loses
HumanPlay.playSpellAbilityNoStack(player, effectSA, !mayChoseNewTargets); HumanPlay.playSpellAbilityNoStack(player, effectSA, !mayChoseNewTargets);
return; return;