mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Refactor confirmTrigger into controller class
This commit is contained in:
@@ -10,6 +10,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
|
|||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
|
||||||
import forge.card.ColorSet;
|
import forge.card.ColorSet;
|
||||||
import forge.deck.Deck;
|
import forge.deck.Deck;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
@@ -27,6 +28,7 @@ import forge.game.spellability.AbilitySub;
|
|||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.SpellAbilityStackInstance;
|
import forge.game.spellability.SpellAbilityStackInstance;
|
||||||
import forge.game.spellability.TargetChoices;
|
import forge.game.spellability.TargetChoices;
|
||||||
|
import forge.game.trigger.Trigger;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
|
|
||||||
@@ -43,19 +45,19 @@ public abstract class PlayerController {
|
|||||||
DeclareBlocker,
|
DeclareBlocker,
|
||||||
Echo,
|
Echo,
|
||||||
Multikicker,
|
Multikicker,
|
||||||
Replicate,
|
Replicate,
|
||||||
CumulativeUpkeep;
|
CumulativeUpkeep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static enum BinaryChoiceType {
|
public static enum BinaryChoiceType {
|
||||||
HeadsOrTails, // coin
|
HeadsOrTails, // coin
|
||||||
TapOrUntap,
|
TapOrUntap,
|
||||||
PlayOrDraw,
|
PlayOrDraw,
|
||||||
OddsOrEvens
|
OddsOrEvens
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final Game game;
|
protected final Game game;
|
||||||
|
|
||||||
private PhaseType autoPassUntil = null;
|
private PhaseType autoPassUntil = null;
|
||||||
protected final Player player;
|
protected final Player player;
|
||||||
protected final LobbyPlayer lobbyPlayer;
|
protected final LobbyPlayer lobbyPlayer;
|
||||||
@@ -95,14 +97,14 @@ public abstract class PlayerController {
|
|||||||
// End of Triggers preliminary choice
|
// End of Triggers preliminary choice
|
||||||
|
|
||||||
public LobbyPlayer getLobbyPlayer() { return lobbyPlayer; }
|
public LobbyPlayer getLobbyPlayer() { return lobbyPlayer; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses GUI to learn which spell the player (human in our case) would like to play
|
* Uses GUI to learn which spell the player (human in our case) would like to play
|
||||||
*/
|
*/
|
||||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities) {
|
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities) {
|
||||||
return getAbilityToPlay(abilities, null);
|
return getAbilityToPlay(abilities, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses GUI to learn which spell the player (human in our case) would like to play
|
* Uses GUI to learn which spell the player (human in our case) would like to play
|
||||||
*/
|
*/
|
||||||
@@ -135,8 +137,9 @@ public abstract class PlayerController {
|
|||||||
public abstract SpellAbility chooseSingleSpellForEffect(List<SpellAbility> spells, SpellAbility sa, String title);
|
public abstract SpellAbility chooseSingleSpellForEffect(List<SpellAbility> spells, SpellAbility sa, String title);
|
||||||
|
|
||||||
public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message);
|
public abstract boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message);
|
||||||
public abstract boolean getWillPlayOnFirstTurn(boolean isFirstGame);
|
|
||||||
public abstract boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message);
|
public abstract boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message);
|
||||||
|
public abstract boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, boolean isMandatory);
|
||||||
|
public abstract boolean getWillPlayOnFirstTurn(boolean isFirstGame);
|
||||||
|
|
||||||
public abstract List<Card> orderBlockers(Card attacker, List<Card> blockers);
|
public abstract List<Card> orderBlockers(Card attacker, List<Card> blockers);
|
||||||
public abstract List<Card> orderAttackers(Card blocker, List<Card> attackers);
|
public abstract List<Card> orderAttackers(Card blocker, List<Card> attackers);
|
||||||
@@ -148,7 +151,7 @@ public abstract class PlayerController {
|
|||||||
public abstract ImmutablePair<List<Card>, List<Card>> arrangeForScry(List<Card> topN);
|
public abstract ImmutablePair<List<Card>, List<Card>> arrangeForScry(List<Card> topN);
|
||||||
public abstract boolean willPutCardOnTop(Card c);
|
public abstract boolean willPutCardOnTop(Card c);
|
||||||
public abstract List<Card> orderMoveToZoneList(List<Card> cards, ZoneType destinationZone);
|
public abstract List<Card> orderMoveToZoneList(List<Card> cards, ZoneType destinationZone);
|
||||||
|
|
||||||
/** p = target player, validCards - possible discards, min cards to discard */
|
/** p = target player, validCards - possible discards, min cards to discard */
|
||||||
public abstract List<Card> chooseCardsToDiscardFrom(Player playerDiscard, SpellAbility sa, List<Card> validCards, int min, int max);
|
public abstract List<Card> chooseCardsToDiscardFrom(Player playerDiscard, SpellAbility sa, List<Card> validCards, int min, int max);
|
||||||
public abstract Card chooseCardToDredge(List<Card> dredgers);
|
public abstract Card chooseCardToDredge(List<Card> dredgers);
|
||||||
@@ -168,7 +171,7 @@ public abstract class PlayerController {
|
|||||||
public abstract void declareAttackers(Player attacker, Combat combat);
|
public abstract void declareAttackers(Player attacker, Combat combat);
|
||||||
public abstract void declareBlockers(Player defender, Combat combat);
|
public abstract void declareBlockers(Player defender, Combat combat);
|
||||||
public abstract void takePriority();
|
public abstract void takePriority();
|
||||||
|
|
||||||
public abstract List<Card> chooseCardsToDiscardToMaximumHandSize(int numDiscard);
|
public abstract List<Card> chooseCardsToDiscardToMaximumHandSize(int numDiscard);
|
||||||
public abstract boolean payManaOptional(Card card, Cost cost, SpellAbility sa, String prompt, ManaPaymentPurpose purpose);
|
public abstract boolean payManaOptional(Card card, Cost cost, SpellAbility sa, String prompt, ManaPaymentPurpose purpose);
|
||||||
|
|
||||||
@@ -181,7 +184,7 @@ public abstract class PlayerController {
|
|||||||
public abstract List<AbilitySub> chooseModeForAbility(SpellAbility sa, int min, int num);
|
public abstract List<AbilitySub> chooseModeForAbility(SpellAbility sa, int min, int num);
|
||||||
|
|
||||||
public abstract byte chooseColor(String message, SpellAbility sa, ColorSet colors);
|
public abstract byte chooseColor(String message, SpellAbility sa, ColorSet colors);
|
||||||
|
|
||||||
public abstract PaperCard chooseSinglePaperCard(SpellAbility sa, String message, Predicate<PaperCard> cpp, String name);
|
public abstract PaperCard chooseSinglePaperCard(SpellAbility sa, String message, Predicate<PaperCard> cpp, String name);
|
||||||
public abstract List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options);
|
public abstract List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options);
|
||||||
public abstract CounterType chooseCounterType(Collection<CounterType> options, SpellAbility sa, String prompt);
|
public abstract CounterType chooseCounterType(Collection<CounterType> options, SpellAbility sa, String prompt);
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import forge.game.spellability.Spell;
|
|||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.SpellAbilityStackInstance;
|
import forge.game.spellability.SpellAbilityStackInstance;
|
||||||
import forge.game.spellability.TargetChoices;
|
import forge.game.spellability.TargetChoices;
|
||||||
|
import forge.game.trigger.Trigger;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
import forge.util.Aggregates;
|
import forge.util.Aggregates;
|
||||||
@@ -64,7 +65,7 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
public PlayerControllerAi(Game game, Player p, LobbyPlayer lp) {
|
public PlayerControllerAi(Game game, Player p, LobbyPlayer lp) {
|
||||||
super(game, p, lp);
|
super(game, p, lp);
|
||||||
|
|
||||||
brains = new AiController(p, game);
|
brains = new AiController(p, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,11 +74,13 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities, MouseEvent triggerEvent) {
|
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities, MouseEvent triggerEvent) {
|
||||||
if (abilities.size() == 0) {
|
if (abilities.size() == 0) {
|
||||||
return null;
|
return null;
|
||||||
} else
|
}
|
||||||
|
else {
|
||||||
return abilities.get(0);
|
return abilities.get(0);
|
||||||
// } else {
|
}
|
||||||
// return GuiChoose.oneOrNone("Choose ability for AI to play", abilities); // some day network interaction will be here
|
// else {
|
||||||
// }
|
// return GuiChoose.oneOrNone("Choose ability for AI to play", abilities); // some day network interaction will be here
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,11 +143,11 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
}
|
}
|
||||||
return chosen;
|
return chosen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Card chooseSingleCardForEffect(Collection<Card> options, SpellAbility sa, String title, boolean isOptional) {
|
public Card chooseSingleCardForEffect(Collection<Card> options, SpellAbility sa, String title, boolean isOptional) {
|
||||||
ApiType api = sa.getApi();
|
ApiType api = sa.getApi();
|
||||||
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().chooseSingleCard(player, sa, options, isOptional);
|
return api.getAi().chooseSingleCard(player, sa, options, isOptional);
|
||||||
@@ -153,7 +156,7 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
@Override
|
@Override
|
||||||
public Player chooseSinglePlayerForEffect(List<Player> options, SpellAbility sa, String title) {
|
public Player chooseSinglePlayerForEffect(List<Player> options, SpellAbility sa, String title) {
|
||||||
ApiType api = sa.getApi();
|
ApiType api = sa.getApi();
|
||||||
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().chooseSinglePlayer(player, sa, options);
|
return api.getAi().chooseSinglePlayer(player, sa, options);
|
||||||
@@ -162,27 +165,67 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
@Override
|
@Override
|
||||||
public SpellAbility chooseSingleSpellForEffect(java.util.List<SpellAbility> spells, SpellAbility sa, String title) {
|
public SpellAbility chooseSingleSpellForEffect(java.util.List<SpellAbility> spells, SpellAbility sa, String title) {
|
||||||
ApiType api = sa.getApi();
|
ApiType api = sa.getApi();
|
||||||
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 api.getAi().chooseSingleSpellAbility(player, sa, spells);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
return getAi().confirmAction(sa, mode, message);
|
return getAi().confirmAction(sa, mode, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getWillPlayOnFirstTurn(boolean isFirstGame) {
|
|
||||||
return true; // AI is brave :)
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
|
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
|
||||||
return getAi().confirmStaticApplication(hostCard, affected, logic, message);
|
return getAi().confirmStaticApplication(hostCard, affected, logic, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, boolean isMandatory) {
|
||||||
|
if (triggerParams.containsKey("DelayedTrigger")) {
|
||||||
|
//TODO: The only card with an optional delayed trigger is Shirei, Shizo's Caretaker,
|
||||||
|
// needs to be expanded when a more difficult cards comes up
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Store/replace target choices more properly to get this SA cleared.
|
||||||
|
TargetChoices tc = null;
|
||||||
|
TargetChoices subtc = null;
|
||||||
|
boolean storeChoices = sa.getTargetRestrictions() != null;
|
||||||
|
final SpellAbility sub = sa.getSubAbility();
|
||||||
|
boolean storeSubChoices = sub != null && sub.getTargetRestrictions() != null;
|
||||||
|
boolean ret = true;
|
||||||
|
|
||||||
|
if (storeChoices) {
|
||||||
|
tc = sa.getTargets();
|
||||||
|
sa.resetTargets();
|
||||||
|
}
|
||||||
|
if (storeSubChoices) {
|
||||||
|
subtc = sub.getTargets();
|
||||||
|
sub.resetTargets();
|
||||||
|
}
|
||||||
|
// There is no way this doTrigger here will have the same target as stored above
|
||||||
|
// So it's possible it's making a different decision here than will actually happen
|
||||||
|
if (!sa.doTrigger(isMandatory, player)) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
if (storeChoices) {
|
||||||
|
sa.resetTargets();
|
||||||
|
sa.setTargets(tc);
|
||||||
|
}
|
||||||
|
if (storeSubChoices) {
|
||||||
|
sub.resetTargets();
|
||||||
|
sub.setTargets(subtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getWillPlayOnFirstTurn(boolean isFirstGame) {
|
||||||
|
return true; // AI is brave :)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> orderBlockers(Card attacker, List<Card> blockers) {
|
public List<Card> orderBlockers(Card attacker, List<Card> blockers) {
|
||||||
return AiBlockController.orderBlockers(attacker, blockers);
|
return AiBlockController.orderBlockers(attacker, blockers);
|
||||||
@@ -207,10 +250,12 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
List<Card> toTop = new ArrayList<Card>();
|
List<Card> toTop = new ArrayList<Card>();
|
||||||
|
|
||||||
for (Card c: topN) {
|
for (Card c: topN) {
|
||||||
if (ComputerUtil.scryWillMoveCardToBottomOfLibrary(player, c))
|
if (ComputerUtil.scryWillMoveCardToBottomOfLibrary(player, c)) {
|
||||||
toBottom.add(c);
|
toBottom.add(c);
|
||||||
else
|
}
|
||||||
toTop.add(c);
|
else {
|
||||||
|
toTop.add(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// put the rest on top in random order
|
// put the rest on top in random order
|
||||||
@@ -218,7 +263,6 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
return ImmutablePair.of(toTop, toBottom);
|
return ImmutablePair.of(toTop, toBottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean willPutCardOnTop(Card c) {
|
public boolean willPutCardOnTop(Card c) {
|
||||||
return true; // AI does not know what will happen next (another clash or that would become his topdeck)
|
return true; // AI does not know what will happen next (another clash or that would become his topdeck)
|
||||||
@@ -232,11 +276,12 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> validCards, int min, int max) {
|
public List<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> validCards, int min, int max) {
|
||||||
if ( p == player )
|
if (p == player) {
|
||||||
return brains.getCardsToDiscard(min, max, validCards, sa);
|
return brains.getCardsToDiscard(min, max, validCards, sa);
|
||||||
|
}
|
||||||
|
|
||||||
boolean isTargetFriendly = !p.isOpponentOf(player);
|
boolean isTargetFriendly = !p.isOpponentOf(player);
|
||||||
|
|
||||||
return isTargetFriendly
|
return isTargetFriendly
|
||||||
? ComputerUtil.getCardsToDiscardFromFriend(player, p, sa, validCards, min, max)
|
? ComputerUtil.getCardsToDiscardFromFriend(player, p, sa, validCards, min, max)
|
||||||
: ComputerUtil.getCardsToDiscardFromOpponent(player, p, sa, validCards, min, max);
|
: ComputerUtil.getCardsToDiscardFromOpponent(player, p, sa, validCards, min, max);
|
||||||
@@ -253,13 +298,14 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
@Override
|
@Override
|
||||||
public void playSpellAbilityForFree(SpellAbility copySA, boolean mayChooseNewTargets) {
|
public void playSpellAbilityForFree(SpellAbility copySA, boolean mayChooseNewTargets) {
|
||||||
// Ai is known to set targets in doTrigger, so if it cannot choose new targets, we won't call canPlays
|
// Ai is known to set targets in doTrigger, so if it cannot choose new targets, we won't call canPlays
|
||||||
if( mayChooseNewTargets ) {
|
if (mayChooseNewTargets) {
|
||||||
if (copySA instanceof Spell) {
|
if (copySA instanceof Spell) {
|
||||||
Spell spell = (Spell) copySA;
|
Spell spell = (Spell) copySA;
|
||||||
if (!spell.canPlayFromEffectAI(player, true, true)) {
|
if (!spell.canPlayFromEffectAI(player, true, true)) {
|
||||||
return; // is this legal at all?
|
return; // is this legal at all?
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
copySA.canPlayAI(player);
|
copySA.canPlayAI(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,7 +314,7 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playSpellAbilityNoStack(SpellAbility effectSA, boolean canSetupTargets) {
|
public void playSpellAbilityNoStack(SpellAbility effectSA, boolean canSetupTargets) {
|
||||||
if ( canSetupTargets )
|
if (canSetupTargets)
|
||||||
effectSA.doTrigger(true, player); // first parameter does not matter, since return value won't be used
|
effectSA.doTrigger(true, player); // first parameter does not matter, since return value won't be used
|
||||||
ComputerUtil.playNoStack(player, effectSA, game);
|
ComputerUtil.playNoStack(player, effectSA, game);
|
||||||
}
|
}
|
||||||
@@ -320,10 +366,10 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
@Override
|
@Override
|
||||||
public String chooseSomeType(String kindOfType, SpellAbility sa, List<String> validTypes, List<String> invalidTypes) {
|
public String chooseSomeType(String kindOfType, SpellAbility sa, List<String> validTypes, List<String> invalidTypes) {
|
||||||
String chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), invalidTypes);
|
String chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), invalidTypes);
|
||||||
if( StringUtils.isBlank(chosen) && !validTypes.isEmpty() )
|
if (StringUtils.isBlank(chosen) && !validTypes.isEmpty())
|
||||||
{
|
{
|
||||||
chosen = validTypes.get(0);
|
chosen = validTypes.get(0);
|
||||||
Log.warn("AI has no idea how to choose " + kindOfType +", defaulting to 1st element: chosen" );
|
Log.warn("AI has no idea how to choose " + kindOfType +", defaulting to 1st element: chosen");
|
||||||
}
|
}
|
||||||
game.getAction().nofityOfValue(sa, null, "Computer picked: " + chosen, player);
|
game.getAction().nofityOfValue(sa, null, "Computer picked: " + chosen, player);
|
||||||
return chosen;
|
return chosen;
|
||||||
@@ -338,14 +384,17 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> getCardsToMulligan(boolean isCommander, Player firstPlayer) {
|
public List<Card> getCardsToMulligan(boolean isCommander, Player firstPlayer) {
|
||||||
if( !ComputerUtil.wantMulligan(player) )
|
if (!ComputerUtil.wantMulligan(player)) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isCommander)
|
if (!isCommander) {
|
||||||
return player.getCardsIn(ZoneType.Hand);
|
return player.getCardsIn(ZoneType.Hand);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
return ComputerUtil.getPartialParisCandidates(player);
|
return ComputerUtil.getPartialParisCandidates(player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -353,7 +402,6 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
brains.declareAttackers(attacker, combat);
|
brains.declareAttackers(attacker, combat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declareBlockers(Player defender, Combat combat) {
|
public void declareBlockers(Player defender, Combat combat) {
|
||||||
brains.declareBlockersFor(defender, combat);
|
brains.declareBlockersFor(defender, combat);
|
||||||
@@ -361,8 +409,9 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void takePriority() {
|
public void takePriority() {
|
||||||
if ( !game.isGameOver() )
|
if (!game.isGameOver()) {
|
||||||
brains.onPriorityRecieved();
|
brains.onPriorityRecieved();
|
||||||
|
}
|
||||||
// use separate thread for AI?
|
// use separate thread for AI?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,7 +485,7 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice) {
|
public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice) {
|
||||||
if(kindOfChoice == BinaryChoiceType.TapOrUntap) return true;
|
if (kindOfChoice == BinaryChoiceType.TapOrUntap) { return true; }
|
||||||
return MyRandom.getRandom().nextBoolean();
|
return MyRandom.getRandom().nextBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,7 +567,7 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
@Override
|
@Override
|
||||||
public CounterType chooseCounterType(Collection<CounterType> options, SpellAbility sa, String prompt) {
|
public CounterType chooseCounterType(Collection<CounterType> options, SpellAbility sa, String prompt) {
|
||||||
// may write a smarter AI if you need to (with calls to AI-clas for given API ability)
|
// may write a smarter AI if you need to (with calls to AI-clas for given API ability)
|
||||||
|
|
||||||
// TODO: ArsenalNut (06 Feb 12)computer needs
|
// TODO: ArsenalNut (06 Feb 12)computer needs
|
||||||
// better logic to pick a counter type and probably
|
// better logic to pick a counter type and probably
|
||||||
// an initial target
|
// an initial target
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import forge.game.spellability.SpellAbility;
|
|||||||
import forge.game.spellability.SpellAbilityStackInstance;
|
import forge.game.spellability.SpellAbilityStackInstance;
|
||||||
import forge.game.spellability.TargetChoices;
|
import forge.game.spellability.TargetChoices;
|
||||||
import forge.game.spellability.TargetSelection;
|
import forge.game.spellability.TargetSelection;
|
||||||
|
import forge.game.trigger.Trigger;
|
||||||
import forge.game.zone.Zone;
|
import forge.game.zone.Zone;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.gui.GuiChoose;
|
import forge.gui.GuiChoose;
|
||||||
@@ -403,6 +404,36 @@ public class PlayerControllerHuman extends PlayerController {
|
|||||||
return GuiDialog.confirm(hostCard, message);
|
return GuiDialog.confirm(hostCard, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, boolean isMandatory) {
|
||||||
|
if (this.shouldAlwaysAcceptTrigger(regtrig.getId())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this.shouldAlwaysDeclineTrigger(regtrig.getId())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String triggerDesc = triggerParams.get("TriggerDescription").replace("CARDNAME", regtrig.getHostCard().getName());
|
||||||
|
final StringBuilder buildQuestion = new StringBuilder("Use triggered ability of ");
|
||||||
|
buildQuestion.append(regtrig.getHostCard().toString()).append("?");
|
||||||
|
buildQuestion.append("\r\n(").append(triggerDesc).append(")\r\n");
|
||||||
|
HashMap<String, Object> tos = sa.getTriggeringObjects();
|
||||||
|
if (tos.containsKey("Attacker")) {
|
||||||
|
buildQuestion.append("[Attacker: " + tos.get("Attacker") + "]");
|
||||||
|
}
|
||||||
|
if (tos.containsKey("Card")) {
|
||||||
|
Card card = (Card) tos.get("Card");
|
||||||
|
if (card != null && (card.getController() == player || game.getZoneOf(card) == null
|
||||||
|
|| game.getZoneOf(card).getZoneType().isKnown())) {
|
||||||
|
buildQuestion.append("[Triggering card: " + tos.get("Card") + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!GuiDialog.confirm(regtrig.getHostCard(), buildQuestion.toString())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getWillPlayOnFirstTurn(boolean isFirstGame) {
|
public boolean getWillPlayOnFirstTurn(boolean isFirstGame) {
|
||||||
InputPlayOrDraw inp = new InputPlayOrDraw(player, isFirstGame);
|
InputPlayOrDraw inp = new InputPlayOrDraw(player, isFirstGame);
|
||||||
@@ -869,10 +900,10 @@ public class PlayerControllerHuman extends PlayerController {
|
|||||||
default:
|
default:
|
||||||
String[] colorNames = new String[cntColors];
|
String[] colorNames = new String[cntColors];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(byte b : colors) {
|
for (byte b : colors) {
|
||||||
colorNames[i++] = MagicColor.toLongString(b);
|
colorNames[i++] = MagicColor.toLongString(b);
|
||||||
}
|
}
|
||||||
if(colorNames.length > 2) {
|
if (colorNames.length > 2) {
|
||||||
return MagicColor.fromName(GuiChoose.one(message, colorNames));
|
return MagicColor.fromName(GuiChoose.one(message, colorNames));
|
||||||
}
|
}
|
||||||
int idxChosen = GuiDialog.confirm(sa.getSourceCard(), message, colorNames) ? 0 : 1;
|
int idxChosen = GuiDialog.confirm(sa.getSourceCard(), message, colorNames) ? 0 : 1;
|
||||||
@@ -890,8 +921,9 @@ public class PlayerControllerHuman extends PlayerController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CounterType chooseCounterType(Collection<CounterType> options, SpellAbility sa, String prompt) {
|
public CounterType chooseCounterType(Collection<CounterType> options, SpellAbility sa, String prompt) {
|
||||||
if( options.size() <= 1)
|
if (options.size() <= 1) {
|
||||||
return Iterables.getFirst(options, null);
|
return Iterables.getFirst(options, null);
|
||||||
|
}
|
||||||
return GuiChoose.one(prompt, options);
|
return GuiChoose.one(prompt, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import forge.game.spellability.SpellAbility;
|
|||||||
import forge.game.spellability.SpellAbilityRestriction;
|
import forge.game.spellability.SpellAbilityRestriction;
|
||||||
import forge.game.spellability.TargetChoices;
|
import forge.game.spellability.TargetChoices;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
import forge.game.spellability.TargetRestrictions;
|
||||||
import forge.gui.GuiDialog;
|
|
||||||
|
|
||||||
// Wrapper ability that checks the requirements again just before
|
// Wrapper ability that checks the requirements again just before
|
||||||
// resolving, for intervening if clauses.
|
// resolving, for intervening if clauses.
|
||||||
@@ -356,8 +355,9 @@ public class WrappedAbility extends Ability implements ISpellAbility {
|
|||||||
TriggerHandler th = game.getTriggerHandler();
|
TriggerHandler th = game.getTriggerHandler();
|
||||||
Map<String, String> triggerParams = regtrig.getMapParams();
|
Map<String, String> triggerParams = regtrig.getMapParams();
|
||||||
|
|
||||||
if (decider != null && !confirmTrigger(decider, triggerParams))
|
if (decider != null && !decider.getController().confirmTrigger(sa, regtrig, triggerParams, this.isMandatory())) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
getActivatingPlayer().getController().playSpellAbilityNoStack(sa, false);
|
getActivatingPlayer().getController().playSpellAbilityNoStack(sa, false);
|
||||||
|
|
||||||
@@ -370,71 +370,4 @@ public class WrappedAbility extends Ability implements ISpellAbility {
|
|||||||
th.registerDelayedTrigger(deltrig);
|
th.registerDelayedTrigger(deltrig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean confirmTrigger(Player decider, Map<String, String> triggerParams) {
|
|
||||||
if (decider.isHuman()) {
|
|
||||||
if(decider.getController().shouldAlwaysAcceptTrigger(regtrig.getId()))
|
|
||||||
return true;
|
|
||||||
else if(decider.getController().shouldAlwaysDeclineTrigger(regtrig.getId()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
String triggerDesc = triggerParams.get("TriggerDescription").replace("CARDNAME", regtrig.getHostCard().getName());
|
|
||||||
final StringBuilder buildQuestion = new StringBuilder("Use triggered ability of ");
|
|
||||||
buildQuestion.append(regtrig.getHostCard().toString()).append("?");
|
|
||||||
buildQuestion.append("\r\n(").append(triggerDesc).append(")\r\n");
|
|
||||||
HashMap<String, Object> tos = sa.getTriggeringObjects();
|
|
||||||
if (tos.containsKey("Attacker")) {
|
|
||||||
buildQuestion.append("[Attacker: " + tos.get("Attacker") + "]");
|
|
||||||
}
|
|
||||||
if (tos.containsKey("Card")) {
|
|
||||||
Card card = (Card) tos.get("Card");
|
|
||||||
if (card != null && (card.getController() == decider || decider.getGame().getZoneOf(card) == null
|
|
||||||
|| decider.getGame().getZoneOf(card).getZoneType().isKnown())) {
|
|
||||||
buildQuestion.append("[Triggering card: " + tos.get("Card") + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!GuiDialog.confirm(regtrig.getHostCard(), buildQuestion.toString())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} // human end
|
|
||||||
|
|
||||||
if (triggerParams.containsKey("DelayedTrigger")) {
|
|
||||||
//TODO: The only card with an optional delayed trigger is Shirei, Shizo's Caretaker,
|
|
||||||
// needs to be expanded when a more difficult cards comes up
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Store/replace target choices more properly to get this SA cleared.
|
|
||||||
TargetChoices tc = null;
|
|
||||||
TargetChoices subtc = null;
|
|
||||||
boolean storeChoices = sa.getTargetRestrictions() != null;
|
|
||||||
final SpellAbility sub = sa.getSubAbility();
|
|
||||||
boolean storeSubChoices = sub != null && sub.getTargetRestrictions() != null;
|
|
||||||
boolean ret = true;
|
|
||||||
|
|
||||||
if (storeChoices) {
|
|
||||||
tc = sa.getTargets();
|
|
||||||
sa.resetTargets();
|
|
||||||
}
|
|
||||||
if (storeSubChoices) {
|
|
||||||
subtc = sub.getTargets();
|
|
||||||
sub.resetTargets();
|
|
||||||
}
|
|
||||||
// There is no way this doTrigger here will have the same target as stored above
|
|
||||||
// So it's possible it's making a different decision here than will actually happen
|
|
||||||
if (!sa.doTrigger(this.isMandatory(), decider)) {
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
if (storeChoices) {
|
|
||||||
sa.resetTargets();
|
|
||||||
sa.setTargets(tc);
|
|
||||||
}
|
|
||||||
if (storeSubChoices) {
|
|
||||||
sub.resetTargets();
|
|
||||||
sub.setTargets(subtc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import forge.game.spellability.AbilitySub;
|
|||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.SpellAbilityStackInstance;
|
import forge.game.spellability.SpellAbilityStackInstance;
|
||||||
import forge.game.spellability.TargetChoices;
|
import forge.game.spellability.TargetChoices;
|
||||||
|
import forge.game.trigger.Trigger;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.gamesimulationtests.util.card.CardSpecification;
|
import forge.gamesimulationtests.util.card.CardSpecification;
|
||||||
import forge.gamesimulationtests.util.card.CardSpecificationHandler;
|
import forge.gamesimulationtests.util.card.CardSpecificationHandler;
|
||||||
@@ -63,387 +64,392 @@ import forge.item.PaperCard;
|
|||||||
*/
|
*/
|
||||||
public class PlayerControllerForTests extends PlayerController {
|
public class PlayerControllerForTests extends PlayerController {
|
||||||
private PlayerActions playerActions;
|
private PlayerActions playerActions;
|
||||||
|
|
||||||
public PlayerControllerForTests( Game game, Player player, LobbyPlayer lobbyPlayer ) {
|
public PlayerControllerForTests(Game game, Player player, LobbyPlayer lobbyPlayer) {
|
||||||
super( game, player, lobbyPlayer );
|
super(game, player, lobbyPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPlayerActions( PlayerActions playerActions ) {
|
public void setPlayerActions(PlayerActions playerActions) {
|
||||||
this.playerActions = playerActions;
|
this.playerActions = playerActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerActions getPlayerActions() {
|
public PlayerActions getPlayerActions() {
|
||||||
return playerActions;
|
return playerActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Game getGame() {
|
public Game getGame() {
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpellAbility getAbilityToPlay( List<SpellAbility> abilities ) {
|
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities) {
|
||||||
System.out.println( "getAbilityToPlay " + StringUtils.join( abilities, ", " ) );
|
System.out.println("getAbilityToPlay " + StringUtils.join(abilities, ", "));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playSpellAbilityForFree( SpellAbility copySA, boolean mayChoseNewTargets ) {
|
public void playSpellAbilityForFree(SpellAbility copySA, boolean mayChoseNewTargets) {
|
||||||
throw new IllegalStateException( "Callers of this method currently assume that it performs extra functionality!" );
|
throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playSpellAbilityNoStack( SpellAbility effectSA, boolean mayChoseNewTargets ) {
|
public void playSpellAbilityNoStack(SpellAbility effectSA, boolean mayChoseNewTargets) {
|
||||||
//TODO: eventually (when the real code is refactored) this should be handled normally...
|
//TODO: eventually (when the real code is refactored) this should be handled normally...
|
||||||
if( effectSA.getDescription().equals( "At the beginning of your upkeep, if you have exactly 1 life, you win the game." ) ) {//test_104_2b_effect_may_state_that_player_wins_the_game
|
if (effectSA.getDescription().equals("At the beginning of your upkeep, if you have exactly 1 life, you win the game.")) {//test_104_2b_effect_may_state_that_player_wins_the_game
|
||||||
HumanPlay.playSpellAbilityNoStack( player, effectSA, !mayChoseNewTargets );
|
HumanPlay.playSpellAbilityNoStack(player, effectSA, !mayChoseNewTargets);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(
|
if (
|
||||||
( effectSA.getSourceCard().getName().equals( "Nefarious Lich" ) && effectSA.getApi().getAi() instanceof DrawAi ) ||
|
(effectSA.getSourceCard().getName().equals("Nefarious Lich") && effectSA.getApi().getAi() instanceof DrawAi) ||
|
||||||
( effectSA.getSourceCard().getName().equals( "Laboratory Maniac" ) && effectSA.getApi().getAi() instanceof GameWinAi ) ||
|
(effectSA.getSourceCard().getName().equals("Laboratory Maniac") && effectSA.getApi().getAi() instanceof GameWinAi) ||
|
||||||
( effectSA.getSourceCard().getName().equals( "Nefarious Lich" ) && effectSA.getApi().getAi() instanceof ChangeZoneAi )
|
(effectSA.getSourceCard().getName().equals("Nefarious Lich") && effectSA.getApi().getAi() 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;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException( "Callers of this method currently assume that it performs extra functionality!" );
|
throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Deck sideboard( Deck deck, GameType gameType ) {
|
public Deck sideboard(Deck deck, GameType gameType) {
|
||||||
return deck;
|
return deck;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Card, Integer> assignCombatDamage( Card attacker, List<Card> blockers, int damageDealt, GameEntity defender, boolean overrideOrder ) {
|
public Map<Card, Integer> assignCombatDamage(Card attacker, List<Card> blockers, int damageDealt, GameEntity defender, boolean overrideOrder) {
|
||||||
if( blockers.size() == 1 && damageDealt == 2 && (
|
if (blockers.size() == 1 && damageDealt == 2 && (
|
||||||
( attacker.getName().equals( "Grizzly Bears" ) && blockers.get( 0 ).getName().equals( "Ajani's Sunstriker" ) ) ||
|
(attacker.getName().equals("Grizzly Bears") && blockers.get(0).getName().equals("Ajani's Sunstriker")) ||
|
||||||
( attacker.getName().equals( "Ajani's Sunstriker" ) && blockers.get( 0 ).getName().equals( "Grizzly Bears" ) )
|
(attacker.getName().equals("Ajani's Sunstriker") && blockers.get(0).getName().equals("Grizzly Bears"))
|
||||||
) ) {//test_104_3b_player_with_less_than_zero_life_loses_the_game_only_when_a_player_receives_priority_variant_with_combat
|
)) {//test_104_3b_player_with_less_than_zero_life_loses_the_game_only_when_a_player_receives_priority_variant_with_combat
|
||||||
Map<Card, Integer> result = new HashMap<Card, Integer>();
|
Map<Card, Integer> result = new HashMap<Card, Integer>();
|
||||||
result.put( blockers.get( 0 ), damageDealt );
|
result.put(blockers.get(0), damageDealt);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException( "Erring on the side of caution here..." );
|
throw new IllegalStateException("Erring on the side of caution here...");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer announceRequirements( SpellAbility ability, String announce, boolean allowZero ) {
|
public Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero) {
|
||||||
throw new IllegalStateException( "Erring on the side of caution here..." );
|
throw new IllegalStateException("Erring on the side of caution here...");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> choosePermanentsToSacrifice( SpellAbility sa, int min, int max, List<Card> validTargets, String message ) {
|
public List<Card> choosePermanentsToSacrifice(SpellAbility sa, int min, int max, List<Card> validTargets, String message) {
|
||||||
return chooseItems( validTargets, min );
|
return chooseItems(validTargets, min);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> choosePermanentsToDestroy( SpellAbility sa, int min, int max, List<Card> validTargets, String message ) {
|
public List<Card> choosePermanentsToDestroy(SpellAbility sa, int min, int max, List<Card> validTargets, String message) {
|
||||||
return chooseItems( validTargets, min );
|
return chooseItems(validTargets, min);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TargetChoices chooseNewTargetsFor( SpellAbility ability ) {
|
public TargetChoices chooseNewTargetsFor(SpellAbility ability) {
|
||||||
throw new IllegalStateException( "Erring on the side of caution here..." );
|
throw new IllegalStateException("Erring on the side of caution here...");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<SpellAbilityStackInstance, GameObject> chooseTarget( SpellAbility sa, List<Pair<SpellAbilityStackInstance, GameObject>> allTargets ) {
|
public Pair<SpellAbilityStackInstance, GameObject> chooseTarget(SpellAbility sa, List<Pair<SpellAbilityStackInstance, GameObject>> allTargets) {
|
||||||
return chooseItem( allTargets );
|
return chooseItem(allTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> chooseCardsForEffect( List<Card> sourceList, SpellAbility sa, String title, int amount, boolean isOptional ) {
|
public List<Card> chooseCardsForEffect(List<Card> sourceList, SpellAbility sa, String title, int amount, boolean isOptional) {
|
||||||
return chooseItems( sourceList, amount );
|
return chooseItems(sourceList, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Card chooseSingleCardForEffect( Collection<Card> sourceList, SpellAbility sa, String title, boolean isOptional ) {
|
public Card chooseSingleCardForEffect(Collection<Card> sourceList, SpellAbility sa, String title, boolean isOptional) {
|
||||||
return chooseItem( sourceList );
|
return chooseItem(sourceList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Player chooseSinglePlayerForEffect( List<Player> options, SpellAbility sa, String title ) {
|
public Player chooseSinglePlayerForEffect(List<Player> options, SpellAbility sa, String title) {
|
||||||
return chooseItem( options );
|
return chooseItem(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpellAbility chooseSingleSpellForEffect( List<SpellAbility> spells, SpellAbility sa, String title ) {
|
public SpellAbility chooseSingleSpellForEffect(List<SpellAbility> spells, SpellAbility sa, String title) {
|
||||||
return chooseItem( spells );
|
return chooseItem(spells);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean confirmAction( SpellAbility sa, PlayerActionConfirmMode mode, String message ) {
|
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getWillPlayOnFirstTurn( boolean isFirstGame ) {
|
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean confirmStaticApplication( Card hostCard, GameEntity affected, String logic, String message ) {
|
public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, boolean isMandatory) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getWillPlayOnFirstTurn(boolean isFirstGame) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> orderBlockers( Card attacker, List<Card> blockers ) {
|
public List<Card> orderBlockers(Card attacker, List<Card> blockers) {
|
||||||
return blockers;
|
return blockers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> orderAttackers( Card blocker, List<Card> attackers ) {
|
public List<Card> orderAttackers(Card blocker, List<Card> attackers) {
|
||||||
return attackers;
|
return attackers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reveal( String string, Collection<Card> cards, ZoneType zone, Player owner ) {
|
public void reveal(String string, Collection<Card> cards, ZoneType zone, Player owner) {
|
||||||
//nothing needs to be done here
|
//nothing needs to be done here
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyOfValue( SpellAbility saSource, GameObject realtedTarget, String value ) {
|
public void notifyOfValue(SpellAbility saSource, GameObject realtedTarget, String value) {
|
||||||
//nothing needs to be done here
|
//nothing needs to be done here
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImmutablePair<List<Card>, List<Card>> arrangeForScry( List<Card> topN ) {
|
public ImmutablePair<List<Card>, List<Card>> arrangeForScry(List<Card> topN) {
|
||||||
return ImmutablePair.of( topN, null );
|
return ImmutablePair.of(topN, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean willPutCardOnTop( Card c ) {
|
public boolean willPutCardOnTop(Card c) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> orderMoveToZoneList( List<Card> cards, ZoneType destinationZone ) {
|
public List<Card> orderMoveToZoneList(List<Card> cards, ZoneType destinationZone) {
|
||||||
return cards;
|
return cards;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> chooseCardsToDiscardFrom( Player playerDiscard, SpellAbility sa, List<Card> validCards, int min, int max ) {
|
public List<Card> chooseCardsToDiscardFrom(Player playerDiscard, SpellAbility sa, List<Card> validCards, int min, int max) {
|
||||||
return chooseItems( validCards, min );
|
return chooseItems(validCards, min);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Card chooseCardToDredge( List<Card> dredgers ) {
|
public Card chooseCardToDredge(List<Card> dredgers) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void playMiracle( SpellAbility miracle, Card card ) {
|
public void playMiracle(SpellAbility miracle, Card card) {
|
||||||
throw new IllegalStateException( "Callers of this method currently assume that it performs extra functionality!" );
|
throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> chooseCardsToDelve( int colorLessAmount, List<Card> grave ) {
|
public List<Card> chooseCardsToDelve(int colorLessAmount, List<Card> grave) {
|
||||||
return Collections.<Card>emptyList();
|
return Collections.<Card>emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> chooseCardsToRevealFromHand( int min, int max, List<Card> valid ) {
|
public List<Card> chooseCardsToRevealFromHand(int min, int max, List<Card> valid) {
|
||||||
return chooseItems( valid, min );
|
return chooseItems(valid, min);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> chooseCardsToDiscardUnlessType( int min, List<Card> hand, String param, SpellAbility sa ) {
|
public List<Card> chooseCardsToDiscardUnlessType(int min, List<Card> hand, String param, SpellAbility sa) {
|
||||||
throw new IllegalStateException( "Erring on the side of caution here..." );
|
throw new IllegalStateException("Erring on the side of caution here...");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SpellAbility> chooseSaToActivateFromOpeningHand( List<SpellAbility> usableFromOpeningHand ) {
|
public List<SpellAbility> chooseSaToActivateFromOpeningHand(List<SpellAbility> usableFromOpeningHand) {
|
||||||
return usableFromOpeningHand;
|
return usableFromOpeningHand;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mana chooseManaFromPool( List<Mana> manaChoices ) {
|
public Mana chooseManaFromPool(List<Mana> manaChoices) {
|
||||||
return chooseItem( manaChoices );
|
return chooseItem(manaChoices);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<CounterType, String> chooseAndRemoveOrPutCounter( Card cardWithCounter ) {
|
public Pair<CounterType, String> chooseAndRemoveOrPutCounter(Card cardWithCounter) {
|
||||||
throw new IllegalStateException( "Erring on the side of caution here..." );
|
throw new IllegalStateException("Erring on the side of caution here...");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean confirmReplacementEffect( ReplacementEffect replacementEffect, SpellAbility effectSA, String question ) {
|
public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> getCardsToMulligan( boolean isCommander, Player firstPlayer ) {
|
public List<Card> getCardsToMulligan(boolean isCommander, Player firstPlayer) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declareAttackers( Player attacker, Combat combat ) {
|
public void declareAttackers(Player attacker, Combat combat) {
|
||||||
//Doing nothing is safe in most cases, but not all (creatures that must attack etc). TODO: introduce checks?
|
//Doing nothing is safe in most cases, but not all (creatures that must attack etc). TODO: introduce checks?
|
||||||
if( playerActions == null ) {
|
if (playerActions == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DeclareAttackersAction declareAttackers = playerActions.getNextActionIfApplicable( player, game, DeclareAttackersAction.class );
|
DeclareAttackersAction declareAttackers = playerActions.getNextActionIfApplicable(player, game, DeclareAttackersAction.class);
|
||||||
if( declareAttackers == null ) {
|
if (declareAttackers == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: check that the chosen attack configuration is legal? (Including creatures that did not attack but should)
|
//TODO: check that the chosen attack configuration is legal? (Including creatures that did not attack but should)
|
||||||
//TODO: check that the chosen attack configuration was a complete match to what was requested?
|
//TODO: check that the chosen attack configuration was a complete match to what was requested?
|
||||||
//TODO: banding (don't really care at the moment...)
|
//TODO: banding (don't really care at the moment...)
|
||||||
|
|
||||||
for( Map.Entry<CardSpecification, PlayerSpecification> playerAttackAssignment : declareAttackers.getPlayerAttackAssignments().entrySet() ) {
|
for (Map.Entry<CardSpecification, PlayerSpecification> playerAttackAssignment : declareAttackers.getPlayerAttackAssignments().entrySet()) {
|
||||||
Player defender = getPlayerBeingAttacked( game, player, playerAttackAssignment.getValue() );
|
Player defender = getPlayerBeingAttacked(game, player, playerAttackAssignment.getValue());
|
||||||
attack( combat, playerAttackAssignment.getKey(), defender );
|
attack(combat, playerAttackAssignment.getKey(), defender);
|
||||||
}
|
}
|
||||||
for( Map.Entry<CardSpecification, CardSpecification> planeswalkerAttackAssignment: declareAttackers.getPlaneswalkerAttackAssignments().entrySet() ) {
|
for (Map.Entry<CardSpecification, CardSpecification> planeswalkerAttackAssignment: declareAttackers.getPlaneswalkerAttackAssignments().entrySet()) {
|
||||||
Card defender = CardSpecificationHandler.INSTANCE.find( game.getCardsInGame(), planeswalkerAttackAssignment.getKey() );
|
Card defender = CardSpecificationHandler.INSTANCE.find(game.getCardsInGame(), planeswalkerAttackAssignment.getKey());
|
||||||
attack( combat, planeswalkerAttackAssignment.getKey(), defender );
|
attack(combat, planeswalkerAttackAssignment.getKey(), defender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Player getPlayerBeingAttacked( Game game, Player attacker, PlayerSpecification defenderSpecification ) {
|
private Player getPlayerBeingAttacked(Game game, Player attacker, PlayerSpecification defenderSpecification) {
|
||||||
if( defenderSpecification != null ) {
|
if (defenderSpecification != null) {
|
||||||
return PlayerSpecificationHandler.INSTANCE.find( game.getPlayers(), defenderSpecification );
|
return PlayerSpecificationHandler.INSTANCE.find(game.getPlayers(), defenderSpecification);
|
||||||
}
|
}
|
||||||
if( game.getPlayers().size() != 2 ) {
|
if (game.getPlayers().size() != 2) {
|
||||||
throw new IllegalStateException( "Can't use implicit defender specification in this situation!" );
|
throw new IllegalStateException("Can't use implicit defender specification in this situation!");
|
||||||
}
|
}
|
||||||
for( Player player : game.getPlayers() ) {
|
for (Player player : game.getPlayers()) {
|
||||||
if( !attacker.equals( player ) ) {
|
if (!attacker.equals(player)) {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new IllegalStateException( "Couldn't find implicit defender!" );
|
throw new IllegalStateException("Couldn't find implicit defender!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void attack( Combat combat, CardSpecification attackerSpecification, GameEntity defender ) {
|
private void attack(Combat combat, CardSpecification attackerSpecification, GameEntity defender) {
|
||||||
Card attacker = CardSpecificationHandler.INSTANCE.find( combat.getAttackingPlayer().getCreaturesInPlay(), attackerSpecification );
|
Card attacker = CardSpecificationHandler.INSTANCE.find(combat.getAttackingPlayer().getCreaturesInPlay(), attackerSpecification);
|
||||||
if ( !CombatUtil.canAttack( attacker, defender, combat ) ) {
|
if (!CombatUtil.canAttack(attacker, defender, combat)) {
|
||||||
throw new IllegalStateException( attacker + " can't attack " + defender );
|
throw new IllegalStateException(attacker + " can't attack " + defender);
|
||||||
}
|
}
|
||||||
combat.addAttacker( attacker, defender );
|
combat.addAttacker(attacker, defender);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void declareBlockers( Player defender, Combat combat ) {
|
public void declareBlockers(Player defender, Combat combat) {
|
||||||
//Doing nothing is safe in most cases, but not all (creatures that must block, attackers that must be blocked etc). TODO: legality checks?
|
//Doing nothing is safe in most cases, but not all (creatures that must block, attackers that must be blocked etc). TODO: legality checks?
|
||||||
if( playerActions == null ) {
|
if (playerActions == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DeclareBlockersAction declareBlockers = playerActions.getNextActionIfApplicable( player, game, DeclareBlockersAction.class );
|
DeclareBlockersAction declareBlockers = playerActions.getNextActionIfApplicable(player, game, DeclareBlockersAction.class);
|
||||||
if( declareBlockers == null ) {
|
if (declareBlockers == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: check that the chosen block configuration is 100% legal?
|
//TODO: check that the chosen block configuration is 100% legal?
|
||||||
//TODO: check that the chosen block configuration was a 100% match to what was requested?
|
//TODO: check that the chosen block configuration was a 100% match to what was requested?
|
||||||
//TODO: where do damage assignment orders get handled?
|
//TODO: where do damage assignment orders get handled?
|
||||||
|
|
||||||
for( Map.Entry<CardSpecification, Collection<CardSpecification>> blockingAssignment : declareBlockers.getBlockingAssignments().asMap().entrySet() ) {
|
for (Map.Entry<CardSpecification, Collection<CardSpecification>> blockingAssignment : declareBlockers.getBlockingAssignments().asMap().entrySet()) {
|
||||||
Card attacker = CardSpecificationHandler.INSTANCE.find( combat.getAttackers(), blockingAssignment.getKey() );
|
Card attacker = CardSpecificationHandler.INSTANCE.find(combat.getAttackers(), blockingAssignment.getKey());
|
||||||
for( CardSpecification blockerSpecification : blockingAssignment.getValue() ) {
|
for (CardSpecification blockerSpecification : blockingAssignment.getValue()) {
|
||||||
Card blocker = CardSpecificationHandler.INSTANCE.find( game, blockerSpecification );
|
Card blocker = CardSpecificationHandler.INSTANCE.find(game, blockerSpecification);
|
||||||
if( !CombatUtil.canBlock( attacker, blocker ) ) {
|
if (!CombatUtil.canBlock(attacker, blocker)) {
|
||||||
throw new IllegalStateException( blocker + " can't block " + blocker );
|
throw new IllegalStateException(blocker + " can't block " + blocker);
|
||||||
}
|
}
|
||||||
combat.addBlocker( attacker, blocker );
|
combat.addBlocker(attacker, blocker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String blockValidation = CombatUtil.validateBlocks( combat, player );
|
String blockValidation = CombatUtil.validateBlocks(combat, player);
|
||||||
if( blockValidation != null ) {
|
if (blockValidation != null) {
|
||||||
throw new IllegalStateException( blockValidation );
|
throw new IllegalStateException(blockValidation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void takePriority() {
|
public void takePriority() {
|
||||||
//TODO: just about everything...
|
//TODO: just about everything...
|
||||||
if( playerActions != null ) {
|
if (playerActions != null) {
|
||||||
CastSpellFromHandAction castSpellFromHand = playerActions.getNextActionIfApplicable( player, game, CastSpellFromHandAction.class );
|
CastSpellFromHandAction castSpellFromHand = playerActions.getNextActionIfApplicable(player, game, CastSpellFromHandAction.class);
|
||||||
if( castSpellFromHand != null ) {
|
if (castSpellFromHand != null) {
|
||||||
castSpellFromHand.castSpellFromHand( player, game );
|
castSpellFromHand.castSpellFromHand(player, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivateAbilityAction activateAbilityAction = playerActions.getNextActionIfApplicable( player, game, ActivateAbilityAction.class );
|
ActivateAbilityAction activateAbilityAction = playerActions.getNextActionIfApplicable(player, game, ActivateAbilityAction.class);
|
||||||
if( activateAbilityAction != null ) {
|
if (activateAbilityAction != null) {
|
||||||
activateAbilityAction.activateAbility( player, game );
|
activateAbilityAction.activateAbility(player, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Card> chooseCardsToDiscardToMaximumHandSize( int numDiscard ) {
|
public List<Card> chooseCardsToDiscardToMaximumHandSize(int numDiscard) {
|
||||||
return chooseItems( player.getZone( ZoneType.Hand ).getCards(), numDiscard );
|
return chooseItems(player.getZone(ZoneType.Hand).getCards(), numDiscard);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean payManaOptional( Card card, Cost cost, SpellAbility sa, String prompt, ManaPaymentPurpose purpose ) {
|
public boolean payManaOptional(Card card, Cost cost, SpellAbility sa, String prompt, ManaPaymentPurpose purpose) {
|
||||||
throw new IllegalStateException( "Callers of this method currently assume that it performs extra functionality!" );
|
throw new IllegalStateException("Callers of this method currently assume that it performs extra functionality!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int chooseNumber( SpellAbility sa, String title, int min, int max ) {
|
public int chooseNumber(SpellAbility sa, String title, int min, int max) {
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean chooseBinary( SpellAbility sa, String question, BinaryChoiceType kindOfChoice ) {
|
public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean chooseFlipResult( SpellAbility sa, Player flipper, boolean[] results, boolean call ) {
|
public boolean chooseFlipResult(SpellAbility sa, Player flipper, boolean[] results, boolean call) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Card chooseProtectionShield( GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap ) {
|
public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap) {
|
||||||
return choiceMap.get( options.get( 0 ) );
|
return choiceMap.get(options.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AbilitySub> chooseModeForAbility( SpellAbility sa, int min, int num ) {
|
public List<AbilitySub> chooseModeForAbility(SpellAbility sa, int min, int num) {
|
||||||
throw new IllegalStateException( "Erring on the side of caution here..." );
|
throw new IllegalStateException("Erring on the side of caution here...");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte chooseColor( String message, SpellAbility sa, ColorSet colors ) {
|
public byte chooseColor(String message, SpellAbility sa, ColorSet colors) {
|
||||||
return Iterables.getFirst(colors, MagicColor.WHITE);
|
return Iterables.getFirst(colors, MagicColor.WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> List<T> chooseItems( Collection<T> items, int amount ) {
|
private <T> List<T> chooseItems(Collection<T> items, int amount) {
|
||||||
if( items == null || items.isEmpty() ) {
|
if (items == null || items.isEmpty()) {
|
||||||
return new ArrayList<T>( items );
|
return new ArrayList<T>(items);
|
||||||
}
|
}
|
||||||
return new ArrayList<T>( items ).subList( 0, Math.max( amount, items.size() ) );
|
return new ArrayList<T>(items).subList(0, Math.max(amount, items.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> T chooseItem( Collection<T> items ) {
|
private <T> T chooseItem(Collection<T> items) {
|
||||||
if( items == null || items.isEmpty() ) {
|
if (items == null || items.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Iterables.getFirst( items, null );
|
return Iterables.getFirst(items, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpellAbility getAbilityToPlay( List<SpellAbility> abilities, MouseEvent triggerEvent ) {
|
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities, MouseEvent triggerEvent) {
|
||||||
return getAbilityToPlay( abilities );
|
return getAbilityToPlay(abilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String chooseSomeType( String kindOfType, SpellAbility sa, List<String> validTypes, List<String> invalidTypes ) {
|
public String chooseSomeType(String kindOfType, SpellAbility sa, List<String> validTypes, List<String> invalidTypes) {
|
||||||
return chooseItem( validTypes );
|
return chooseItem(validTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PaperCard chooseSinglePaperCard( SpellAbility sa, String message, Predicate<PaperCard> cpp, String name ) {
|
public PaperCard chooseSinglePaperCard(SpellAbility sa, String message, Predicate<PaperCard> cpp, String name) {
|
||||||
throw new IllegalStateException( "Erring on the side of caution here..." );
|
throw new IllegalStateException("Erring on the side of caution here...");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user