package magic.model.choice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import magic.exception.UndoClickedException;
import magic.model.IUIGameController;
import magic.model.MagicGame;
import magic.model.MagicPermanentState;
import magic.model.MagicPlayer;
import magic.model.MagicSource;
import magic.model.event.MagicActivation;
import magic.model.event.MagicEvent;
import magic.model.event.MagicSourceActivation;
import magic.model.phase.MagicPhaseType;
import magic.translate.MText;
import magic.translate.StringContext;
public class MagicPlayChoice extends MagicChoice {
// translatable strings
private static final String _S_PLAY_MESSAGE = "Play a card or ability.";
@StringContext(eg = "{f} will be replaced by an icon.")
private static final String _S_CONTINUE_MESSAGE = "Click {f} or Space to pass.";
@StringContext(eg = "| represents a new line. Position to fit text in user prompt.")
private static final String _S_SKIP_MESSAGE = "Right click {f} or Shift+Space to|skip till end of turn.";
private static final String MESSAGE = String.format("%s|%s|[%s]",
MText.get(_S_PLAY_MESSAGE),
MText.get(_S_CONTINUE_MESSAGE),
MText.get(_S_SKIP_MESSAGE)
);
private static final MagicChoice INSTANCE=new MagicPlayChoice();
private static final Collection<Object> PASS_OPTIONS=Collections.<Object>singleton(MagicPlayChoiceResult.SKIP);
private static final Object[] PASS_CHOICE_RESULTS= {MagicPlayChoiceResult.SKIP};
private MagicPlayChoice() {
super(MText.get(_S_PLAY_MESSAGE));
}
@Override
Collection<Object> getArtificialOptions(final MagicGame game, final MagicEvent event) {
final MagicPlayer player = event.getPlayer();
// When something is already on top of stack for the player, always pass.
if (game.getStack().hasItemOnTopOfPlayer(player)) {
return PASS_OPTIONS;
}
//can't play spells or abilities during combat damage phase
if (game.isPhase(MagicPhaseType.CombatDamage)) {
return PASS_OPTIONS;
}
final ArrayList<Object> options=new ArrayList<>();
// Pass is first choice when scores are equal.
options.add(MagicPlayChoiceResult.PASS);
// add rest of the options
addValidChoices(game, player, true, options);
// only one option, return SKIP instead of PASS
return options.size() > 1 ? options : PASS_OPTIONS;
}
private static void addValidChoices(final MagicGame game, final MagicPlayer player, final boolean isAI, final Collection<Object> validChoices) {
final Set<MagicSourceActivation<? extends MagicSource>> sourceActivations = player.getSourceActivations();
MagicActivation<? extends MagicSource> skip = null;
for (final MagicSourceActivation<? extends MagicSource> sourceActivation : sourceActivations) {
if (sourceActivation.activation != skip && sourceActivation.canPlay(game, player, isAI)) {
validChoices.add(isAI ?
new MagicPlayChoiceResult(sourceActivation) :
sourceActivation.source
);
if (isAI && sourceActivation.isIndependent()) {
skip = sourceActivation.activation;
}
}
}
}
@Override
public Object[] getPlayerChoiceResults(final IUIGameController controller, final MagicGame game, final MagicEvent event) throws UndoClickedException {
final MagicPlayer player = event.getPlayer();
final MagicSource source = event.getSource();
controller.focusViewers(0);
//always pass draw and begin combat if
// option is true and
// stack is empty
if (game.canAlwaysPass() && game.getStack().isEmpty()) {
return PASS_CHOICE_RESULTS;
}
//skip all combat phases if
// nobody is attacking and
// stack is empty
if ((game.isPhase(MagicPhaseType.DeclareAttackers) ||
game.isPhase(MagicPhaseType.DeclareBlockers) ||
game.isPhase(MagicPhaseType.CombatDamage) ||
game.isPhase(MagicPhaseType.EndOfCombat)) &&
game.getNrOfPermanents(MagicPermanentState.Attacking) == 0 &&
game.getStack().isEmpty()) {
return PASS_CHOICE_RESULTS;
}
//skip if phase is combat damage, not supposed to be able to do
//anything but resolve triggers
if (game.isPhase(MagicPhaseType.CombatDamage)) {
controller.doStackItemPause();
return PASS_CHOICE_RESULTS;
}
final Set<Object> validChoices = new HashSet<>();
addValidChoices(game, player, false, validChoices);
if (validChoices.isEmpty() && MagicGame.canSkipSingleChoice()) {
boolean skip = true;
//if AI blocks, don't skip priority so that user can observe how the AI is blocking
if (game.isPhase(MagicPhaseType.DeclareBlockers) &&
player.getOpponent().getNrOfBlockers() > 0 &&
game.getStack().isEmpty()) {
skip = false;
}
if (skip) {
controller.doStackItemPause();
return PASS_CHOICE_RESULTS;
}
}
if (game.shouldSkip()) {
// clear skip till EOT if someone declares attacks
if (game.isPhase(MagicPhaseType.DeclareAttackers) && game.getNrOfPermanents(MagicPermanentState.Attacking) > 0) {
game.clearSkipTurnTill();
} else {
return PASS_CHOICE_RESULTS;
}
} else {
game.clearSkipTurnTill();
}
if (validChoices.isEmpty()) {
controller.showMessage(source, MText.get(_S_CONTINUE_MESSAGE));
} else {
controller.showMessage(source,MESSAGE);
controller.setValidChoices(validChoices,false);
}
controller.enableForwardButton();
controller.waitForInput();
controller.clearValidChoices();
controller.disableActionButton(false);
game.snapshot();
if (controller.isActionClicked()) {
return PASS_CHOICE_RESULTS;
}
final MagicSource activationSource = controller.getChoiceClicked();
final List<MagicPlayChoiceResult> results=new ArrayList<>();
for (final MagicSourceActivation<? extends MagicSource> sourceActivation : activationSource.getSourceActivations()) {
if (sourceActivation.canPlay(game,player,false)) {
results.add(new MagicPlayChoiceResult(sourceActivation));
}
}
assert results.size() > 0 : "ERROR! There should be at least one activation possible.";
if (results.size() == 1) {
return new Object[]{results.get(0)};
} else {
controller.setSourceCardDefinition(activationSource);
return new Object[]{controller.getPlayChoice(activationSource, results)};
}
}
public static MagicChoice getInstance() {
return INSTANCE;
}
}