package me.desht.chesscraft.chess.player;
import chesspresso.Chess;
import me.desht.chesscraft.ChessCraft;
import me.desht.chesscraft.Messages;
import me.desht.chesscraft.chess.*;
import me.desht.chesscraft.exceptions.ChessException;
import me.desht.chesscraft.expector.ExpectDrawResponse;
import me.desht.chesscraft.expector.ExpectSwapResponse;
import me.desht.chesscraft.expector.ExpectUndoResponse;
import me.desht.chesscraft.expector.ExpectYesNoResponse;
import me.desht.chesscraft.util.ChessUtils;
import me.desht.chesscraft.util.EconomyUtil;
import me.desht.dhutils.MiscUtil;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.UUID;
public class HumanChessPlayer extends ChessPlayer {
private final UUID uuid;
private final String oldStyleName;
private String resultsName;
private int tcWarned;
public HumanChessPlayer(String id, String name, ChessGame game, int colour) {
super(id, name, game, colour);
if (MiscUtil.looksLikeUUID(id)) {
uuid = UUID.fromString(id);
oldStyleName = null;
OfflinePlayer op = Bukkit.getOfflinePlayer(uuid);
setResultsName(op.getName());
} else {
// not a UUID - then *hopefully* this is a Bukkit player name
// which can be migrated to a UUID
ChessGameManager.getManager().needToDoUUIDMigration(game);
resultsName = oldStyleName = id;
uuid = null;
}
}
public OfflinePlayer getOfflinePlayer() {
return Bukkit.getOfflinePlayer(uuid);
}
public Player getBukkitPlayer() {
return uuid == null ? null : Bukkit.getPlayer(uuid);
}
/**
* Get the old-style (player.getName()) player name. This will only be non-null after an old
* save game file has been loaded and before a UUID migration operation has been carried out
* and is only intended to be used by the migration process.
*
* @return the old-style player name
*/
public String getOldStyleName() {
return oldStyleName;
}
public synchronized void setResultsName(String resultsName) {
this.resultsName = resultsName;
}
@Override
public synchronized String getResultsName() {
return resultsName;
}
@Override
public void promptForFirstMove() {
alert(Messages.getString("Game.started", ChessUtils.getDisplayColour(getColour()), ChessUtils.getWandDescription()));
}
@Override
public void promptForNextMove() {
Player p = getBukkitPlayer();
if (p == null) {
return;
}
alert(Messages.getString("Game.playerPlayedMove",
ChessUtils.getDisplayColour(getOtherColour()),
getGame().getPosition().getLastMove().getSAN()));
if (getGame().getPosition().isCheck()) {
playEffect("check");
alert(Messages.getString("Game.check"));
}
}
@Override
public void alert(String message) {
Player p = getBukkitPlayer();
if (p != null) {
MiscUtil.alertMessage(p, Messages.getString("Game.alertPrefix", getGame().getName()) + message);
}
}
@Override
public void statusMessage(String message) {
Player p = getBukkitPlayer();
if (p != null) {
MiscUtil.statusMessage(p, message);
}
}
@Override
public void replayMoves() {
// nothing to do here
}
@Override
public void cleanup() {
// nothing to do here
}
@Override
public void validateAffordability(String error) {
if (error == null) error = "Game.cantAffordToJoin";
double stake = getGame().getStake();
OfflinePlayer player = getOfflinePlayer();
if (EconomyUtil.enabled() && (player == null || !EconomyUtil.has(player, stake))) {
throw new ChessException(Messages.getString(error, EconomyUtil.formatStakeStr(stake)));
}
}
@Override
public void validateInvited(String error) {
UUID invited = getGame().getInvitedId();
if (!getGame().isOpenInvite() && (invited == null || !invited.equals(uuid))) {
throw new ChessException(Messages.getString(error));
}
}
@Override
public boolean isHuman() {
return true;
}
@Override
public void withdrawFunds(double amount) {
OfflinePlayer player = getOfflinePlayer();
EconomyUtil.withdraw(player, amount);
alert(Messages.getString("Game.paidStake", EconomyUtil.formatStakeStr(amount)));
}
@Override
public void depositFunds(double amount) {
OfflinePlayer player = getOfflinePlayer();
EconomyUtil.deposit(player, amount);
}
@Override
public void teleport(BoardView view) {
Player p = getBukkitPlayer();
if (p != null) {
view.summonPlayer(p);
}
}
@Override
public void cancelOffers() {
Player p = getBukkitPlayer();
if (p != null) {
// making a move after a draw/swap/undo offer has been made is equivalent to declining the offer
ExpectYesNoResponse.handleYesNoResponse(p, false);
}
}
@Override
public double getPayoutMultiplier() {
return 2.0;
}
@Override
public void drawOffered() {
ChessPlayer other = getGame().getPlayer(Chess.otherPlayer(getColour()));
ChessCraft.getInstance().responseHandler.expect(getBukkitPlayer(), new ExpectDrawResponse(getGame(), getColour()));
alert(Messages.getString("ChessCommandExecutor.drawOfferedOther", other.getDisplayName()));
alert(Messages.getString("ChessCommandExecutor.typeYesOrNo"));
}
@Override
public void swapOffered() {
ChessPlayer other = getGame().getPlayer(Chess.otherPlayer(getColour()));
ChessCraft.getInstance().responseHandler.expect(getBukkitPlayer(), new ExpectSwapResponse(getGame(), getColour()));
alert(Messages.getString("ChessCommandExecutor.swapOfferedOther", other.getDisplayName()));
alert(Messages.getString("ChessCommandExecutor.typeYesOrNo"));
}
@Override
public void undoOffered() {
ChessPlayer other = getGame().getPlayer(Chess.otherPlayer(getColour()));
ChessCraft.getInstance().responseHandler.expect(getBukkitPlayer(), new ExpectUndoResponse(getGame(), getColour()));
alert(Messages.getString("ChessCommandExecutor.undoOfferedOther", other.getDisplayName()));
alert(Messages.getString("ChessCommandExecutor.typeYesOrNo"));
}
@Override
public void undoLastMove() {
// do nothing here
}
@Override
public void checkPendingAction() {
// do nothing here
}
@Override
public void playEffect(String effect) {
Player p = getBukkitPlayer();
if (p != null) {
ChessCraft.getInstance().getFX().playEffect(p.getLocation(), effect);
}
}
@Override
public void notifyTimeControl(TimeControl timeControl) {
if (timeControl.isNewPhase()) {
alert(Messages.getString("Game.newTimeControlPhase", timeControl.phaseString()));
} else if (getGame().getPosition().getPlyNumber() <= 2) {
alert(Messages.getString("ChessCommandExecutor.gameDetail.timeControlType", timeControl.getSpec()));
}
}
@Override
public void timeControlCheck() {
TwoPlayerClock clock = getGame().getClock();
if (needToWarn(clock)) {
alert(Messages.getString("Game.timeControlWarning", clock.getRemainingTime(getColour()) / 1000));
tcWarned++;
}
}
private boolean needToWarn(TwoPlayerClock clock) {
if (clock.getTimeControl().getControlType() == TimeControl.ControlType.NONE) {
return false;
}
long remaining = clock.getRemainingTime(getColour());
long t = ChessCraft.getInstance().getConfig().getInt("time_control.warn_seconds") * 1000;
long tot = clock.getTimeControl().getTotalTime();
long warning = Math.min(t, tot) >>> tcWarned;
// int tickInt = (ChessCraft.getInstance().getConfig().getInt("tick_interval") * 1000) + 50; // fudge for inaccuracy of tick timer
return remaining <= warning && remaining > warning - 1050;
}
}