package magic.ui.widget.duel.animation;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingUtilities;
import magic.data.GeneralConfig;
import magic.model.MagicCard;
import magic.model.phase.MagicPhaseType;
import magic.ui.duel.viewerinfo.CardViewerInfo;
import magic.ui.duel.viewerinfo.GameViewerInfo;
import magic.ui.duel.viewerinfo.PlayerViewerInfo;
import magic.ui.screen.duel.game.DuelPanel;
import magic.utility.MagicSystem;
public class MagicAnimations {
private MagicAnimations() {}
private static GameLayoutInfo layoutInfo;
private static boolean isEnabled = true;
public static MagicAnimation getGameplayAnimation(
final GameViewerInfo oldGameInfo,
final GameViewerInfo newGameInfo,
final DuelPanel gamePanel) {
if (!isEnabled) {
return null;
}
if (isOn(AnimationFx.DRAW_CARD) && isDrawCardEvent(newGameInfo)) {
return getDrawCardAnimation(oldGameInfo, newGameInfo, gamePanel);
}
if (isOn(AnimationFx.PLAY_CARD) && isPlayCardEvent(newGameInfo)) {
return getPlayCardAnimationInfo(oldGameInfo, newGameInfo, gamePanel);
}
if (isOn(AnimationFx.NEW_TURN_MSG) && isNewTurnEvent(oldGameInfo, newGameInfo)) {
gamePanel.doNewTurnNotification(newGameInfo);
// return getNewTurnAnimation(newGameInfo, gamePanel);
}
return null;
}
private static boolean isDrawCardEvent(GameViewerInfo newGameInfo) {
final boolean isDrawPhase = newGameInfo.getPhaseType() == MagicPhaseType.Draw;
final boolean isValid = newGameInfo.getTurnPlayer().isHuman() || MagicSystem.isAiVersusAi();
return isDrawPhase && isValid;
}
private static boolean isPlayCardEvent(GameViewerInfo newGameInfo) {
return newGameInfo.getPhaseType().isMain() && newGameInfo.getTurnPlayer().isAi();
}
private static boolean isNewTurnEvent(GameViewerInfo oldGameInfo, GameViewerInfo newGameInfo) {
final int turn = newGameInfo.getTurn();
if (turn != oldGameInfo.getTurn()) {
final GeneralConfig config = GeneralConfig.getInstance();
final boolean isShowingMulliganScreen = config.showMulliganScreen() && turn == 1;
return !isShowingMulliganScreen && config.getNewTurnAlertDuration() > 0;
}
return false;
}
private static MagicAnimation getNewTurnAnimation(GameViewerInfo newGameInfo, DuelPanel gamePanel) {
setLayoutInfo(gamePanel, newGameInfo, CardViewerInfo.NO_CARD);
return new NewTurnAnimation(newGameInfo, layoutInfo);
}
private static void setLayoutInfo(DuelPanel gamePanel, GameViewerInfo newGameInfo, CardViewerInfo cardInfo) {
assert !SwingUtilities.isEventDispatchThread();
try {
SwingUtilities.invokeAndWait(() -> {
layoutInfo = gamePanel.getLayoutInfo(newGameInfo, cardInfo);
});
} catch (InterruptedException | InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
/**
* A player draws a card by putting the top card of his or her library into his or her hand.
* Instead of just appearing suddenly in the player's hand, this animation will first display
* the card briefly. This only applies when the non-AI player draws a card.
*/
private static MagicAnimation getDrawCardAnimation(
final GameViewerInfo oldGameInfo,
final GameViewerInfo newGameInfo,
final DuelPanel gamePanel) {
final List<MagicCard> cards = new ArrayList<>(oldGameInfo.getTurnPlayer().library);
cards.removeAll(newGameInfo.getTurnPlayer().library);
if (cards.isEmpty()) {
return null;
}
assert cards.size() == 1;
final CardViewerInfo cardInfo = newGameInfo.getCardViewerInfo(cards.get(0));
setLayoutInfo(gamePanel, newGameInfo, cardInfo);
return new DrawCardAnimation(
newGameInfo.getTurnPlayer().player,
cardInfo,
layoutInfo
);
}
/**
* AI plays a card from hand to the battlefield or stack during M1 or M2.
*/
private static MagicAnimation getPlayCardAnimationInfo(
final GameViewerInfo oldGameInfo,
final GameViewerInfo newGameInfo,
final DuelPanel gamePanel) {
PlayerViewerInfo tpOld = oldGameInfo.getTurnPlayer();
PlayerViewerInfo tpNew = newGameInfo.getTurnPlayer();
// if a card has been played then the current game state's hand should have one
// less card than the previous game state's hand.
final List<MagicCard> cards = new ArrayList<>(tpOld.hand);
cards.removeAll(tpNew.hand);
if (cards.isEmpty()) {
return null;
} else if (cards.size() > 1) {
return null; // eg. due to Tolarian Winds.
} else if (tpNew.graveyard.size() > tpOld.graveyard.size()) {
return null; // discarding card from hand (see github issue #695).
}
final CardViewerInfo cardInfo = newGameInfo.getCardViewerInfo(cards.get(0));
setLayoutInfo(gamePanel, newGameInfo, cardInfo);
return new PlayCardAnimation(tpNew.player, cardInfo, layoutInfo);
}
public static void debugPrint(MagicAnimation animation) {
if (animation != null) {
if (animation instanceof CardAnimation) {
final CardAnimation ca = (CardAnimation)animation;
System.out.printf("\n%s %s %s\n",
ca.getPlayer().getName(),
ca instanceof DrawCardAnimation ? "draws" : "plays",
ca.getCardInfo()
);
}
}
}
public static boolean isOn(long aFlag) {
return GeneralConfig.getInstance().showGameplayAnimations() && AnimationFx.isOn(aFlag);
}
public static boolean isOff(long aFlag) {
return !GeneralConfig.getInstance().showGameplayAnimations() || !AnimationFx.isOn(aFlag);
}
private static void showDebugInfo(GameViewerInfo oldGameInfo, GameViewerInfo newGameInfo, MagicCard aCard) {
PlayerViewerInfo tpOld = oldGameInfo.getTurnPlayer();
PlayerViewerInfo tpNew = newGameInfo.getTurnPlayer();
System.out.println("===" + aCard + "===");
System.out.printf(" hand %d : %d\n", tpOld.hand.size(), tpNew.hand.size());
System.out.printf(" graveyard %d : %d\n", tpOld.graveyard.size(), tpNew.graveyard.size());
System.out.printf(" permanents %d : %d\n", tpOld.permanents.size(), tpNew.permanents.size());
System.out.printf(" stack %d : %d\n", oldGameInfo.getStack().size(), newGameInfo.getStack().size());
}
public static void setEnabled(boolean b) {
isEnabled = b;
}
}