int chattingPartner;
char marker[BOARD_RANKS][BOARD_FILES]; /* [HGM] marks for target squares */
ChessSquare pieceSweep = EmptySquare;
+ChessSquare promoSweep = EmptySquare, defaultPromoChoice;
+int promoDefaultAltered;
/* States for ics_getting_history */
#define H_FALSE 0
}
+static int lastX, lastY, selectFlag, dragging;
+
+void
+Sweep(int step)
+{
+ ChessSquare king = WhiteKing, pawn = WhitePawn, last = promoSweep;
+ if(gameInfo.variant == VariantKnightmate) king = WhiteUnicorn;
+ if(gameInfo.variant == VariantSuicide || gameInfo.variant == VariantGiveaway) king = EmptySquare;
+ if(promoSweep >= BlackPawn) king = WHITE_TO_BLACK king, pawn = WHITE_TO_BLACK pawn;
+ if(gameInfo.variant == VariantSpartan && pawn == BlackPawn) pawn = BlackLance, king = EmptySquare;
+ if(fromY != BOARD_HEIGHT-2 && fromY != 1) pawn = EmptySquare;
+ do {
+ promoSweep -= step;
+ if(promoSweep == EmptySquare) promoSweep = BlackPawn; // wrap
+ else if((int)promoSweep == -1) promoSweep = WhiteKing;
+ else if(promoSweep == BlackPawn && step < 0) promoSweep = WhitePawn;
+ else if(promoSweep == WhiteKing && step > 0) promoSweep = BlackKing;
+ if(!step) step = 1;
+ } while(PieceToChar(promoSweep) == '.' || PieceToChar(promoSweep) == '~' || promoSweep == pawn ||
+ appData.testLegality && (promoSweep == king ||
+ gameInfo.variant == VariantShogi && promoSweep != PROMOTED last && last != PROMOTED promoSweep && last != promoSweep));
+ ChangeDragPiece(promoSweep);
+}
+
+int PromoScroll(int x, int y)
+{
+ int step = 0;
+
+ if(promoSweep == EmptySquare || !appData.sweepSelect) return FALSE;
+ if(abs(x - lastX) < 15 && abs(y - lastY) < 15) return FALSE;
+ if( y > lastY + 2 ) step = -1; else if(y < lastY - 2) step = 1;
+ if(!step) return FALSE;
+ lastX = x; lastY = y;
+ if((promoSweep < BlackPawn) == flipView) step = -step;
+ if(step > 0) selectFlag = 1;
+ if(!selectFlag) Sweep(step);
+ return FALSE;
+}
+
void
NextPiece(int step)
{
ChessSquare piece = boards[currentMove][toY][toX];
do {
- pieceSweep += step;
+ pieceSweep -= step;
if(pieceSweep == EmptySquare) pieceSweep = WhitePawn; // wrap
if((int)pieceSweep == -1) pieceSweep = BlackKing;
- if(!step) step = 1;
+ if(!step) step = -1;
} while(PieceToChar(pieceSweep) == '.');
boards[currentMove][toY][toX] = pieceSweep;
DrawPosition(FALSE, boards[currentMove]);
DrawPosition(TRUE, boards[currentMove]);
}
-static int lastX, lastY;
-
Boolean
LoadMultiPV(int x, int y, char *buf, int index, int *start, int *end)
{
void
MovePV(int x, int y, int h)
{ // step through PV based on mouse coordinates (called on mouse move)
- int margin = h>>3, step = 0, dist;
+ int margin = h>>3, step = 0;
// we must somehow check if right button is still down (might be released off board!)
+ if(endPV < 0 && pieceSweep == EmptySquare) return; // needed in XBoard because lastX/Y is shared :-(
if(abs(x - lastX) < 7 && abs(y - lastY) < 7) return;
if( y > lastY + 2 ) step = -1; else if(y < lastY - 2) step = 1;
if(!step) return;
setboardSpoiledMachineBlack = 0; /* [HGM] assume WB 4.2.7 already solves this after sending setboard */
}
+ChessSquare
+DefaultPromoChoice(int white)
+{
+ ChessSquare result;
+ if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
+ result = WhiteFerz; // no choice
+ else if(gameInfo.variant == VariantSuicide || gameInfo.variant == VariantGiveaway)
+ result= WhiteKing; // in Suicide Q is the last thing we want
+ else if(gameInfo.variant == VariantSpartan)
+ result = white ? WhiteQueen : WhiteAngel;
+ else result = WhiteQueen;
+ if(!white) result = WHITE_TO_BLACK result;
+ return result;
+}
+
static int autoQueen; // [HGM] oneclick
int
return FALSE;
}
// give caller the default choice even if we will not make it
- if(gameInfo.variant == VariantSuicide || gameInfo.variant == VariantGiveaway)
- *promoChoice = PieceToChar(BlackKing); // in Suicide Q is the last thing we want
- else *promoChoice = PieceToChar(BlackQueen);
+ *promoChoice = ToLower(PieceToChar(defaultPromoChoice));
+ if(gameInfo.variant == VariantShogi) *promoChoice = '+';
+ if(appData.sweepSelect && gameInfo.variant != VariantGreat
+ && gameInfo.variant != VariantShogi
+ && gameInfo.variant != VariantSuper) return FALSE;
if(autoQueen) return FALSE; // predetermined
// suppress promotion popup on illegal moves that are not premoves
}
userOfferedDraw = FALSE; // [HGM] drawclaim: after move made, and tested for claimable draw
+ promoDefaultAltered = FALSE; // [HGM] fall back on default choice
if(bookHit) { // [HGM] book: simulate book reply
static char bookMove[MSG_SIZ]; // a bit generous?
ChessSquare gatingPiece = EmptySquare; // exported to front-end, for dragging
+int CanPromote(ChessSquare piece, int y)
+{
+ if(gameMode == EditPosition) return FALSE; // no promotions when editing position
+ // some variants have fixed promotion piece, no promotion at all, or another selection mechanism
+ if(gameInfo.variant == VariantShogi || gameInfo.variant == VariantXiangqi ||
+ gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat ||
+ gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
+ gameInfo.variant == VariantMakruk) return FALSE;
+ return (piece == BlackPawn && y == 1 ||
+ piece == WhitePawn && y == BOARD_HEIGHT-2 ||
+ piece == BlackLance && y == 1 ||
+ piece == WhiteLance && y == BOARD_HEIGHT-2 );
+}
+
void LeftClick(ClickType clickType, int xPix, int yPix)
{
int x, y;
Boolean saveAnimate;
- static int second = 0, promotionChoice = 0, dragging = 0;
+ static int second = 0, promotionChoice = 0;
char promoChoice = NULLCHAR;
+ ChessSquare piece;
if(appData.seekGraph && appData.icsActive && loggedOn &&
(gameMode == BeginningOfGame || gameMode == IcsIdle)) {
x = BOARD_WIDTH - 1 - x;
}
+ if(promoSweep != EmptySquare) { // up-click during sweep-select of promo-piece
+ defaultPromoChoice = promoSweep;
+ promoSweep = EmptySquare; // terminate sweep
+ promoDefaultAltered = TRUE;
+ if(!selectFlag) x = fromX, y = fromY; // and fake up-click on same square if we were still selecting
+ }
+
if(promotionChoice) { // we are waiting for a click to indicate promotion piece
if(clickType == Release) return; // ignore upclick of click-click destination
promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
|| x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize) )
return;
+ if(clickType == Press && fromX == x && fromY == y && promoDefaultAltered)
+ fromX = fromY = -1; // second click on piece after altering default promo piece treated as first click
+
+ if(!promoDefaultAltered) { // determine default promotion piece, based on the side the user is moving for
+ int side = (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack ||
+ gameMode != MachinePlaysWhite && gameMode != IcsPlayingBlack && WhiteOnMove(currentMove));
+ defaultPromoChoice = DefaultPromoChoice(side);
+ }
+
autoQueen = appData.alwaysPromoteToQueen;
if (fromX == -1) {
+ int originalY = y;
gatingPiece = EmptySquare;
if (clickType != Press) {
if(dragging) { // [HGM] from-square must have been reset due to game end since last press
}
return;
}
- if(!appData.oneClick || !OnlyMove(&x, &y, FALSE)) {
+ fromX = x; fromY = y;
+ if(!appData.oneClick || !OnlyMove(&x, &y, FALSE) ||
+ // even if only move, we treat as normal when this would trigger a promotion popup, to allow sweep selection
+ appData.sweepSelect && CanPromote(boards[currentMove][fromY][fromX], fromY) && originalY != y) {
/* First square */
- if (OKToStartUserMove(x, y)) {
- fromX = x;
- fromY = y;
+ if (OKToStartUserMove(fromX, fromY)) {
second = 0;
MarkTargetSquares(0);
DragPieceBegin(xPix, yPix); dragging = 1;
+ if(appData.sweepSelect && CanPromote(piece = boards[currentMove][fromY][fromX], fromY)) {
+ promoSweep = defaultPromoChoice;
+ selectFlag = 0; lastX = xPix; lastY = yPix;
+ Sweep(0); // Pawn that is going to promote: preview promotion piece
+ DisplayMessage("", _("Pull pawn backwards to under-promote"));
+ }
if (appData.highlightDragging) {
- SetHighlights(x, y, -1, -1);
+ SetHighlights(fromX, fromY, -1, -1);
}
}
return;
!(fromP == BlackKing && toP == BlackRook && frc))) {
/* Clicked again on same color piece -- changed his mind */
second = (x == fromX && y == fromY);
+ promoDefaultAltered = FALSE;
if(!second || appData.oneClick && !OnlyMove(&x, &y, TRUE)) {
if (appData.highlightDragging) {
SetHighlights(x, y, -1, -1);
fromY = y; dragging = 1;
MarkTargetSquares(0);
DragPieceBegin(xPix, yPix);
+ if(appData.sweepSelect && CanPromote(piece = boards[currentMove][y][x], y)) {
+ promoSweep = defaultPromoChoice;
+ selectFlag = 0; lastX = xPix; lastY = yPix;
+ Sweep(0); // Pawn that is going to promote: preview promotion piece
+ }
}
}
if(x == fromX && y == fromY) return; // if OnlyMove altered (x,y) we go on