extern char installDir[MSG_SIZ];
VariantClass startVariant; /* [HGM] nicks: initial variant */
Boolean abortMatch;
+int deadRanks;
extern int tinyLayout, smallLayout;
ChessProgramStats programStats;
!(fromX >=0 && fromY >= 0 && toX >= 0 && toY >= 0) ) // invalid move
return FALSE;
+ if(legal[toY][toX] == 4) return FALSE;
+
piece = boards[currentMove][fromY][fromX];
if(gameInfo.variant == VariantChu) {
promotionZoneSize = BOARD_HEIGHT/3;
int r, f;
if(!appData.markers || !appData.highlightDragging) return;
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) legal[r][f] = 0;
- r=BOARD_HEIGHT-1; f=BOARD_LEFT;
+ r=BOARD_HEIGHT-1-deadRanks; f=BOARD_LEFT;
while(*fen) {
int s = 0;
marker[r][f] = 0;
if(*fen == 'M') legal[r][f] = 2; else // request promotion choice
+ if(*fen == 'B') legal[r][f] = 4; else // request auto-promotion to victim
if(*fen >= 'A' && *fen <= 'Z') legal[r][f] = 3; else
if(*fen >= 'a' && *fen <= 'z') *fen += 'A' - 'a';
if(*fen == '/' && f > BOARD_LEFT) f = BOARD_LEFT, r--; else
}
Boolean right; // instructs front-end to use button-1 events as if they were button 3
+Boolean deferChoice;
void
LeftClick (ClickType clickType, int xPix, int yPix)
{
int x, y;
- Boolean saveAnimate;
+ static Boolean saveAnimate;
static int second = 0, promotionChoice = 0, clearFlag = 0, sweepSelecting = 0, flashing = 0, saveFlash;
char promoChoice = NULLCHAR;
ChessSquare piece;
if(flashing) return;
+ if(!deferChoice) { // when called for a retry, skip everything to the point where we left off
x = EventToSquare(xPix, BOARD_WIDTH);
y = EventToSquare(yPix, BOARD_HEIGHT);
if (!flipView && y >= 0) {
else ReportClick("put", x, y);
if(gatingPiece != EmptySquare && gameInfo.variant == VariantSChess) promoChoice = ToLower(PieceToChar(gatingPiece));
-
- if(legal[toY][toX] == 2) promoChoice = ToLower(PieceToChar(defaultPromoChoice)); // highlight-induced promotion
+ }
+
+ if(legal[toY][toX] == 2) { // highlight-induced promotion
+ if(piece == defaultPromoChoice) promoChoice = NULLCHAR; // deferral
+ else promoChoice = ToLower(PieceToChar(defaultPromoChoice));
+ } else if(legal[toY][toX] == 4) { // blue target square: engine must supply promotion choice
+ if(!*promoRestrict) { // but has not done that yet
+ deferChoice = TRUE; // set up retry for when it does
+ return; // and wait for that
+ }
+ promoChoice = ToLower(*promoRestrict); // force engine's choice
+ deferChoice = FALSE;
+ }
if (legal[toY][toX] == 2 && !appData.sweepSelect || HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, appData.sweepSelect)) {
SetHighlights(fromX, fromY, toX, toY);
while(message[s] && message[s++] != ' ');
if(BOARD_HEIGHT != h || BOARD_WIDTH != w + 4*(hand != 0) || gameInfo.holdingsSize != hand ||
dummy == 4 && gameInfo.variant != StringToVariant(varName) ) { // engine wants to change board format or variant
+ if(hand <= h) deadRanks = 0; else deadRanks = hand - h, h = hand; // adapt board to over-sized holdings
appData.NrFiles = w; appData.NrRanks = h; appData.holdingsSize = hand;
if(dummy == 4) gameInfo.variant = StringToVariant(varName); // parent variant
InitPosition(1); // calls InitDrawingSizes to let new parameters take effect
}
return;
}
- if(sscanf(message, "choice %s", promoRestrict) == 1 && promoSweep != EmptySquare) {
- promoSweep = CharToPiece(currentMove&1 ? ToLower(*promoRestrict) : ToUpper(*promoRestrict));
- Sweep(0);
+ if(sscanf(message, "choice %s", promoRestrict) == 1) {
+ if(deferChoice) {
+ LeftClick(Press, 0, 0); // finish the click that was interrupted
+ } else if(promoSweep != EmptySquare) {
+ promoSweep = CharToPiece(currentMove&1 ? ToLower(*promoRestrict) : ToUpper(*promoRestrict));
+ if(strlen(promoRestrict) > 1) Sweep(0);
+ }
return;
}
/* [HGM] Allow engine to set up a position. Don't ask me why one would
redraw, init, gameMode);
}
pieceDefs = FALSE; // [HGM] gen: reset engine-defined piece moves
+ deadRanks = 0; // assume entire board is used
for(i=0; i<EmptySquare; i++) { FREE(pieceDesc[i]); pieceDesc[i] = NULL; }
CleanupTail(); // [HGM] vari: delete any stored variations
CommentPopDown(); // [HGM] make sure no comments to the previous game keep hanging on
#define FUDGE 25 /* 25ms = 1/40 sec; should be plenty even for 50 Hz clocks */
+static int timeSuffix; // [HGM] This should realy be a passed parameter, but it has to pass through too many levels for my laziness...
+
/* Decrement running clock by amount of time that has passed */
void
DecrementClocks ()
{
- long timeRemaining;
+ long tRemaining;
long lastTickLength, fudge;
TimeMark now;
if (WhiteOnMove(forwardMostMove)) {
if(whiteNPS >= 0) lastTickLength = 0;
- timeRemaining = whiteTimeRemaining -= lastTickLength;
- if(timeRemaining < 0 && !appData.icsActive) {
+ tRemaining = whiteTimeRemaining -= lastTickLength;
+ if( tRemaining < 0 && !appData.icsActive) {
GetTimeQuota((forwardMostMove-whiteStartMove-1)/2, 0, whiteTC); // sets suddenDeath & nextSession;
if(suddenDeath) { // [HGM] if we run out of a non-last incremental session, go to the next
whiteStartMove = forwardMostMove; whiteTC = nextSession;
- lastWhite= timeRemaining = whiteTimeRemaining += GetTimeQuota(-1, 0, whiteTC);
+ lastWhite= tRemaining = whiteTimeRemaining += GetTimeQuota(-1, 0, whiteTC);
}
}
+ if(forwardMostMove && appData.moveTime) timeSuffix = timeRemaining[0][forwardMostMove-1] - tRemaining;
DisplayWhiteClock(whiteTimeRemaining - fudge,
WhiteOnMove(currentMove < forwardMostMove ? currentMove : forwardMostMove));
+ timeSuffix = 0;
} else {
if(blackNPS >= 0) lastTickLength = 0;
- timeRemaining = blackTimeRemaining -= lastTickLength;
- if(timeRemaining < 0 && !appData.icsActive) { // [HGM] if we run out of a non-last incremental session, go to the next
+ tRemaining = blackTimeRemaining -= lastTickLength;
+ if( tRemaining < 0 && !appData.icsActive) { // [HGM] if we run out of a non-last incremental session, go to the next
GetTimeQuota((forwardMostMove-blackStartMove-1)/2, 0, blackTC);
if(suddenDeath) {
blackStartMove = forwardMostMove;
- lastBlack = timeRemaining = blackTimeRemaining += GetTimeQuota(-1, 0, blackTC=nextSession);
+ lastBlack = tRemaining = blackTimeRemaining += GetTimeQuota(-1, 0, blackTC=nextSession);
}
}
+ if(forwardMostMove && appData.moveTime) timeSuffix = timeRemaining[1][forwardMostMove-1] - tRemaining;
DisplayBlackClock(blackTimeRemaining - fudge,
!WhiteOnMove(currentMove < forwardMostMove ? currentMove : forwardMostMove));
+ timeSuffix = 0;
}
if (CheckFlags()) return;
}
tickStartTM = now;
- intendedTickLength = NextTickLength(timeRemaining - fudge) + fudge;
+ intendedTickLength = NextTickLength( tRemaining - fudge) + fudge;
StartClockTimer(intendedTickLength);
/* if the time remaining has fallen below the alarm threshold, sound the
((gameMode == IcsPlayingBlack) && !WhiteOnMove(currentMove))
)) return;
- if (alarmSounded && (timeRemaining > appData.icsAlarmTime)) {
+ if (alarmSounded && ( tRemaining > appData.icsAlarmTime)) {
alarmSounded = FALSE;
- } else if (!alarmSounded && (timeRemaining <= appData.icsAlarmTime)) {
+ } else if (!alarmSounded && ( tRemaining <= appData.icsAlarmTime)) {
PlayAlarmSound();
alarmSounded = TRUE;
}
{
long second, minute, hour, day;
char *sign = "";
- static char buf[32];
+ static char buf[40], moveTime[8];
if (ms > 0 && ms <= 9900) {
/* convert milliseconds to tenths, rounding up */
minute = second / 60;
second = second % 60;
+ if(timeSuffix) snprintf(moveTime, 8, " (%d)", timeSuffix/1000); // [HGM] kludge alert; fraction contains move time
+ else *moveTime = NULLCHAR;
+
if (day > 0)
- snprintf(buf, sizeof(buf)/sizeof(buf[0]), " %s%ld:%02ld:%02ld:%02ld ",
- sign, day, hour, minute, second);
+ snprintf(buf, sizeof(buf)/sizeof(buf[0]), " %s%ld:%02ld:%02ld:%02ld%s ",
+ sign, day, hour, minute, second, moveTime);
else if (hour > 0)
- snprintf(buf, sizeof(buf)/sizeof(buf[0]), " %s%ld:%02ld:%02ld ", sign, hour, minute, second);
+ snprintf(buf, sizeof(buf)/sizeof(buf[0]), " %s%ld:%02ld:%02ld%s ", sign, hour, minute, second, moveTime);
else
- snprintf(buf, sizeof(buf)/sizeof(buf[0]), " %s%2ld:%02ld ", sign, minute, second);
+ snprintf(buf, sizeof(buf)/sizeof(buf[0]), " %s%2ld:%02ld%s ", sign, minute, second, moveTime);
return buf;
}
p = buf;
/* Piece placement data */
- for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
+ for (i = BOARD_HEIGHT - 1 - deadRanks; i >= 0; i--) {
if(MSG_SIZ - (p - buf) < BOARD_RGHT - BOARD_LEFT + 20) { *p = 0; return StrSave(buf); }
emptycount = 0;
for (j = BOARD_LEFT; j < BOARD_RGHT; j++) {
p = fen;
+ for(i=1; i<=deadRanks; i++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++) board[BOARD_HEIGHT-i][j] = DarkSquare;
+
/* Piece placement data */
- for (i = BOARD_HEIGHT - 1; i >= 0; i--) {
+ for (i = BOARD_HEIGHT - 1 - deadRanks; i >= 0; i--) {
j = 0;
for (;;) {
if (*p == '/' || *p == ' ' || *p == '[' ) {
ToNrEvent(currentMove+1);
}
+int transparency[2];
+
void
LoadTheme ()
{
appData.liteBackTextureMode,
appData.darkBackTextureMode );
} else {
- snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -ubt false -lsc %s -dsc %s",
- Col2Text(2), // lightSquareColor
- Col2Text(3) ); // darkSquareColor
+ snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -ubt false");
+ }
+ if(!appData.useBitmaps || transparency[0]) {
+ snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -lsc %s", Col2Text(2) ); // lightSquareColor
+ }
+ if(!appData.useBitmaps || transparency[1]) {
+ snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -dsc %s", Col2Text(3) ); // darkSquareColor
}
if(appData.useBorder) {
snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -ub true -border \"%s\"",
Col2Text(9), // appData.fontBackColorWhite
Col2Text(10) ); // appData.fontForeColorBlack
} else {
- snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -upf false -pid \"%s\"",
- appData.pieceDirectory);
- if(!appData.pieceDirectory[0])
+ snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -upf false");
+ if(appData.pieceDirectory[0]) {
+ snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -pid \"%s\"", appData.pieceDirectory);
+ if(appData.trueColors != 2) // 2 is a kludge to suppress this in WinBoard
+ snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -trueColors %s", appData.trueColors ? "true" : "false");
+ }
+ if(!appData.pieceDirectory[0] && !appData.trueColors)
snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -wpc %s -bpc %s",
Col2Text(0), // whitePieceColor
Col2Text(1) ); // blackPieceColor