#else
+#include <sys/file.h>
#define DoSleep( n ) if( (n) >= 0) sleep(n)
#define SLASH '/'
{
char buf[MSG_SIZ];
+ if(moveList[moveNum][1] == '@' && moveList[moveNum][0] == '@') {
+ // null move in variant where engine does not understand it (for analysis purposes)
+ SendBoard(cps, moveNum + 1); // send position after move in stead.
+ return;
+ }
if (cps->useUsermove) {
SendToProgram("usermove ", cps);
}
} else
if(BOARD_HEIGHT > 10) { // [HGM] big: convert ranks to double-digit where needed
if(moveList[moveNum][1] == '@' && (BOARD_HEIGHT < 16 || moveList[moveNum][0] <= 'Z')) { // drop move
+ if(moveList[moveNum][0]== '@') snprintf(buf, MSG_SIZ, "@@@@\n"); else
snprintf(buf, MSG_SIZ, "%c@%c%d%s", moveList[moveNum][0],
moveList[moveNum][2], moveList[moveNum][3] - '0', moveList[moveNum]+4);
} else
char move[7];
{
if (rf == DROP_RANK) {
+ if(ff == EmptySquare) sprintf(move, "@@@@\n"); else // [HGM] pass
sprintf(move, "%c@%c%c\n",
ToUpper(PieceToChar((ChessSquare) ff)), AAA + ft, ONE + rt);
} else {
static int autoQueen; // [HGM] oneclick
int
-HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice)
+HasPromotionChoice(int fromX, int fromY, int toX, int toY, char *promoChoice, int sweepSelect)
{
/* [HGM] rewritten IsPromotion to only flag promotions that offer a choice */
/* [HGM] add Shogi promotions */
}
// give caller the default choice even if we will not make it
*promoChoice = ToLower(PieceToChar(defaultPromoChoice));
- if(gameInfo.variant == VariantShogi) *promoChoice = '+';
- if(appData.sweepSelect && gameInfo.variant != VariantGreat
- && gameInfo.variant != VariantShogi
+ if(gameInfo.variant == VariantShogi) *promoChoice = (defaultPromoChoice == piece ? '=' : '+');
+ if( sweepSelect && gameInfo.variant != VariantGreat
+ && gameInfo.variant != VariantGrand
&& gameInfo.variant != VariantSuper) return FALSE;
if(autoQueen) return FALSE; // predetermined
(int)from_piece < (int)BlackPawn; /* [HGM] can be > King! */
switch (gameMode) {
- case PlayFromGameFile:
case AnalyzeFile:
case TwoMachinesPlay:
case EndOfGame:
}
break;
+ case PlayFromGameFile:
+ if(!shiftKey || !appData.variations) return FALSE; // [HGM] allow starting variation in this mode
case EditGame:
if (!white_piece && WhiteOnMove(currentMove)) {
DisplayMoveError(_("It is White's turn"));
}
if (currentMove != forwardMostMove && gameMode != AnalyzeMode
&& gameMode != EditGame // [HGM] vari: treat as AnalyzeMode
+ && gameMode != PlayFromGameFile // [HGM] as EditGame, with protected main line
&& gameMode != AnalyzeFile && gameMode != Training) {
DisplayMoveError(_("Displayed position is not current"));
return FALSE;
*/
switch (gameMode) {
- case PlayFromGameFile:
case AnalyzeFile:
case TwoMachinesPlay:
case EndOfGame:
}
break;
+ case PlayFromGameFile:
+ if(!shiftKey ||!appData.variations) return; // [HGM] only variations
case EditGame:
case IcsExamining:
case BeginningOfGame:
/* [HGM] always test for legality, to get promotion info */
moveType = LegalityTest(boards[currentMove], PosFlags(currentMove),
fromY, fromX, toY, toX, promoChar);
+
+ if(fromY == DROP_RANK && fromX == EmptySquare && (gameMode == AnalyzeMode || gameMode == EditGame)) moveType = NormalMove;
+
/* [HGM] but possibly ignore an IllegalMove result */
if (appData.testLegality) {
if (moveType == IllegalMove || moveType == ImpossibleMove) {
/* Ok, now we know that the move is good, so we can kill
the previous line in Analysis Mode */
- if ((gameMode == AnalyzeMode || gameMode == EditGame)
+ if ((gameMode == AnalyzeMode || gameMode == EditGame || gameMode == PlayFromGameFile && appData.variations && shiftKey)
&& currentMove < forwardMostMove) {
if(appData.variations && shiftKey) PushTail(currentMove, forwardMostMove); // [HGM] vari: save tail of game
else forwardMostMove = currentMove;
// [HGM] book: if program might be playing, let it use book
bookHit = SendMoveToBookUser(forwardMostMove-1, &first, FALSE);
first.maybeThinking = TRUE;
+ } else if(fromY == DROP_RANK && fromX == EmptySquare) {
+ if(!first.useSetboard) SendToProgram("undo\n", &first); // kludge to change stm in engines that do not support setboard
+ SendBoard(&first, currentMove+1);
} else SendMoveToProgram(forwardMostMove-1, &first);
if (currentMove == cmailOldMove + 1) {
cmailMoveType[lastLoadGameNumber - 1] = CMAIL_MOVE;
MarkTargetSquares(int clear)
{
int x, y;
- if(!appData.markers || !appData.highlightDragging ||
+ if(!appData.markers || !appData.highlightDragging || appData.icsActive && gameInfo.variant < VariantShogi ||
!appData.testLegality || gameMode == EditPosition) return;
if(clear) {
for(x=0; x<BOARD_WIDTH; x++) for(y=0; y<BOARD_HEIGHT; y++) marker[y][x] = 0;
}
if (clickType == Press) ErrorPopDown();
- MarkTargetSquares(1);
x = EventToSquare(xPix, BOARD_WIDTH);
y = EventToSquare(yPix, BOARD_HEIGHT);
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(!selectFlag && (x != toX || y != toY)) 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
}
return;
}
- fromX = x; fromY = y;
+ fromX = x; fromY = y; toX = toY = -1;
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) {
if (OKToStartUserMove(fromX, fromY)) {
second = 0;
MarkTargetSquares(0);
- DragPieceBegin(xPix, yPix); dragging = 1;
+ DragPieceBegin(xPix, yPix, FALSE); dragging = 1;
if(appData.sweepSelect && CanPromote(piece = boards[currentMove][fromY][fromX], fromY)) {
promoSweep = defaultPromoChoice;
selectFlag = 0; lastX = xPix; lastY = yPix;
/* Clicked again on same color piece -- changed his mind */
second = (x == fromX && y == fromY);
promoDefaultAltered = FALSE;
+ MarkTargetSquares(1);
if(!second || appData.oneClick && !OnlyMove(&x, &y, TRUE)) {
if (appData.highlightDragging) {
SetHighlights(x, y, -1, -1);
fromX = x;
fromY = y; dragging = 1;
MarkTargetSquares(0);
- DragPieceBegin(xPix, yPix);
+ DragPieceBegin(xPix, yPix, FALSE);
if(appData.sweepSelect && CanPromote(piece = boards[currentMove][y][x], y)) {
promoSweep = defaultPromoChoice;
selectFlag = 0; lastX = xPix; lastY = yPix;
toX = x;
toY = y;
saveAnimate = appData.animate;
+ MarkTargetSquares(1);
if (clickType == Press) {
if(gameMode == EditPosition && boards[currentMove][fromY][fromX] == EmptySquare) {
// must be Edit Position mode with empty-square selected
- fromX = x; fromY = y; DragPieceBegin(xPix, yPix); dragging = 1; // consider this a new attempt to drag
+ fromX = x; fromY = y; DragPieceBegin(xPix, yPix, FALSE); dragging = 1; // consider this a new attempt to drag
if(x >= BOARD_LEFT && x < BOARD_RGHT) clearFlag = 1; // and defer click-click move of empty-square to up-click
return;
}
+ if(appData.sweepSelect && HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, FALSE)) {
+ ChessSquare piece = boards[currentMove][fromY][fromX];
+ DragPieceBegin(xPix, yPix, TRUE); dragging = 1;
+ promoSweep = defaultPromoChoice;
+ if(PieceToChar(PROMOTED piece) == '+') promoSweep = PROMOTED piece;
+ selectFlag = 0; lastX = xPix; lastY = yPix;
+ Sweep(0); // Pawn that is going to promote: preview promotion piece
+ DisplayMessage("", _("Pull pawn backwards to under-promote"));
+ DrawPosition(FALSE, boards[currentMove]);
+ return;
+ }
/* Finish clickclick move */
if (appData.animate || appData.highlightLastMove) {
SetHighlights(fromX, fromY, toX, toY);
if(gatingPiece != EmptySquare) promoChoice = ToLower(PieceToChar(gatingPiece));
- if (HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice)) {
+ if (HasPromotionChoice(fromX, fromY, toX, toY, &promoChoice, appData.sweepSelect)) {
SetHighlights(fromX, fromY, toX, toY);
if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat || gameInfo.variant == VariantGrand) {
// [HGM] super: promotion to captured piece selected from holdings
toX = xSqr; toY = ySqr; lastX = x, lastY = y;
if(flipView) toX = BOARD_WIDTH - 1 - toX; else toY = BOARD_HEIGHT - 1 - toY;
NextPiece(0);
- return -2;
+ return 2; // grab
case IcsObserving:
if(!appData.icsEngineAnalyze) return -1;
case IcsPlayingWhite:
}
int
+CompareWithRights(Board b1, Board b2)
+{
+ int rights = 0;
+ if(!CompareBoards(b1, b2)) return FALSE;
+ if(b1[EP_STATUS] != b2[EP_STATUS]) return FALSE;
+ /* compare castling rights */
+ if( b1[CASTLING][2] != b2[CASTLING][2] && (b2[CASTLING][0] != NoRights || b2[CASTLING][1] != NoRights) )
+ rights++; /* King lost rights, while rook still had them */
+ if( b1[CASTLING][2] != NoRights ) { /* king has rights */
+ if( b1[CASTLING][0] != b2[CASTLING][0] || b1[CASTLING][1] != b2[CASTLING][1] )
+ rights++; /* but at least one rook lost them */
+ }
+ if( b1[CASTLING][5] != b1[CASTLING][5] && (b2[CASTLING][3] != NoRights || b2[CASTLING][4] != NoRights) )
+ rights++;
+ if( b1[CASTLING][5] != NoRights ) {
+ if( b1[CASTLING][3] != b2[CASTLING][3] || b1[CASTLING][4] != b2[CASTLING][4] )
+ rights++;
+ }
+ return rights == 0;
+}
+
+int
Adjudicate(ChessProgramState *cps)
{ // [HGM] some adjudications useful with buggy engines
// [HGM] adjudicate: made into separate routine, which now can be called after every move
oldEP = (signed char)board[EP_STATUS];
board[EP_STATUS] = EP_NONE;
- if( board[toY][toX] != EmptySquare )
- board[EP_STATUS] = EP_CAPTURE;
-
if (fromY == DROP_RANK) {
/* must be first */
+ if(fromX == EmptySquare) { // [HGM] pass: empty drop encodes null move; nothing to change.
+ board[EP_STATUS] = EP_CAPTURE; // null move considered irreversible
+ return;
+ }
piece = board[toY][toX] = (ChessSquare) fromX;
} else {
int i;
+ if( board[toY][toX] != EmptySquare )
+ board[EP_STATUS] = EP_CAPTURE;
+
if( board[fromY][fromX] == WhiteLance || board[fromY][fromX] == BlackLance ) {
if( gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi )
board[EP_STATUS] = EP_PAWN_MOVE; // Lance is Pawn-like in most variants
redraw, init, gameMode);
}
CleanupTail(); // [HGM] vari: delete any stored variations
+ CommentPopDown(); // [HGM] make sure no comments to the previous game keep hanging on
pausing = pauseExamInvalid = FALSE;
startedFromSetupPosition = blackPlaysFirst = FALSE;
firstMove = TRUE;
if (currentMove >= forwardMostMove) {
if(gameMode == AnalyzeFile) { ExitAnalyzeMode(); SendToProgram("force\n", &first); }
- gameMode = EditGame;
- ModeHighlight();
+// gameMode = EndOfGame;
+// ModeHighlight();
/* [AS] Clear current move marker at the end of a game */
/* HistorySet(parseList, backwardMostMove, forwardMostMove, -1); */
}
}
+int keys[EmptySquare+1];
+int
+PositionMatches(Board b1, Board b2)
+{
+ int r, f, sum=0;
+ switch(appData.searchMode) {
+ case 1: return CompareWithRights(b1, b2);
+ case 2:
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ if(b2[r][f] != EmptySquare && b1[r][f] != b2[r][f]) return FALSE;
+ }
+ return TRUE;
+ case 3:
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ if((b2[r][f] == WhitePawn || b2[r][f] == BlackPawn) && b1[r][f] != b2[r][f]) return FALSE;
+ sum += keys[b1[r][f]] - keys[b2[r][f]];
+ }
+ return sum==0;
+ case 4:
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ sum += keys[b1[r][f]] - keys[b2[r][f]];
+ }
+ return sum==0;
+ }
+ return TRUE;
+}
+
+GameInfo dummyInfo;
+
+int GameContainsPosition(FILE *f, ListGame *lg)
+{
+ int next, btm=0, plyNr=0, scratch=forwardMostMove+2&~1;
+ int fromX, fromY, toX, toY;
+ char promoChar;
+ static int initDone=FALSE;
+
+ if(!initDone) {
+ for(next = WhitePawn; next<EmptySquare; next++) keys[next] = rand()>>8 ^ rand()<<6 ^rand()<<20;
+ initDone = TRUE;
+ }
+ dummyInfo.variant = VariantNormal;
+ FREE(dummyInfo.fen); dummyInfo.fen = NULL;
+ dummyInfo.whiteRating = 0;
+ dummyInfo.blackRating = 0;
+ FREE(dummyInfo.date); dummyInfo.date = NULL;
+ fseek(f, lg->offset, 0);
+ yynewfile(f);
+ CopyBoard(boards[scratch], initialPosition); // default start position
+ while(1) {
+ yyboardindex = scratch + (plyNr&1);
+ quickFlag = 1;
+ next = Myylex();
+ quickFlag = 0;
+ switch(next) {
+ case PGNTag:
+ if(plyNr) return -1; // after we have seen moves, any tags will be start of next game
+#if 0
+ ParsePGNTag(yy_text, &dummyInfo); // this has a bad memory leak...
+ if(dummyInfo.fen) ParseFEN(boards[scratch], &btm, dummyInfo.fen), free(dummyInfo.fen), dummyInfo.fen = NULL;
+#else
+ // do it ourselves avoiding malloc
+ { char *p = yy_text+1, *q;
+ while(!isdigit(*p) && !isalpha(*p)) p++;
+ q = p; while(*p != ' ' && *p != '\t' && *p != '\n') p++;
+ *p = NULLCHAR;
+ if(!StrCaseCmp(q, "Date") && (p = strchr(p+1, '"'))) { if(atoi(p+1) < appData.dateThreshold) return -1; } else
+ if(!StrCaseCmp(q, "Variant") && (p = strchr(p+1, '"'))) dummyInfo.variant = StringToVariant(p+1); else
+ if(!StrCaseCmp(q, "WhiteElo") && (p = strchr(p+1, '"'))) dummyInfo.whiteRating = atoi(p+1); else
+ if(!StrCaseCmp(q, "BlackElo") && (p = strchr(p+1, '"'))) dummyInfo.blackRating = atoi(p+1); else
+ if(!StrCaseCmp(q, "WhiteUSCF") && (p = strchr(p+1, '"'))) dummyInfo.whiteRating = atoi(p+1); else
+ if(!StrCaseCmp(q, "BlackUSCF") && (p = strchr(p+1, '"'))) dummyInfo.blackRating = atoi(p+1); else
+ if(!StrCaseCmp(q, "FEN") && (p = strchr(p+1, '"'))) ParseFEN(boards[scratch], &btm, p+1);
+ }
+#endif
+ default:
+ continue;
+
+ case XBoardGame:
+ case GNUChessGame:
+ if(plyNr) return -1; // after we have seen moves, this is for new game
+ continue;
+
+ case AmbiguousMove: // we cannot reconstruct the game beyond these two
+ case ImpossibleMove:
+ case WhiteWins: // game ends here with these four
+ case BlackWins:
+ case GameIsDrawn:
+ case GameUnfinished:
+ return -1;
+
+ case IllegalMove:
+ if(appData.testLegality) return -1;
+ case WhiteCapturesEnPassant:
+ case BlackCapturesEnPassant:
+ case WhitePromotion:
+ case BlackPromotion:
+ case WhiteNonPromotion:
+ case BlackNonPromotion:
+ case NormalMove:
+ case WhiteKingSideCastle:
+ case WhiteQueenSideCastle:
+ case BlackKingSideCastle:
+ case BlackQueenSideCastle:
+ case WhiteKingSideCastleWild:
+ case WhiteQueenSideCastleWild:
+ case BlackKingSideCastleWild:
+ case BlackQueenSideCastleWild:
+ case WhiteHSideCastleFR:
+ case WhiteASideCastleFR:
+ case BlackHSideCastleFR:
+ case BlackASideCastleFR:
+ fromX = currentMoveString[0] - AAA;
+ fromY = currentMoveString[1] - ONE;
+ toX = currentMoveString[2] - AAA;
+ toY = currentMoveString[3] - ONE;
+ promoChar = currentMoveString[4];
+ break;
+ case WhiteDrop:
+ case BlackDrop:
+ fromX = next == WhiteDrop ?
+ (int) CharToPiece(ToUpper(currentMoveString[0])) :
+ (int) CharToPiece(ToLower(currentMoveString[0]));
+ fromY = DROP_RANK;
+ toX = currentMoveString[2] - AAA;
+ toY = currentMoveString[3] - ONE;
+ break;
+ }
+ // Move encountered; peform it. We need to shuttle between two boards, as even/odd index determines side to move
+ if(plyNr == 0) { // but first figure out variant and initial position
+ if(dummyInfo.variant != gameInfo.variant) return -1; // wrong variant
+ if(appData.eloThreshold1 && (dummyInfo.whiteRating < appData.eloThreshold1 && dummyInfo.blackRating < appData.eloThreshold1)) return -1;
+ if(appData.eloThreshold2 && (dummyInfo.whiteRating < appData.eloThreshold2 || dummyInfo.blackRating < appData.eloThreshold2)) return -1;
+ if(appData.dateThreshold && (!dummyInfo.date || atoi(dummyInfo.date) < appData.dateThreshold)) return -1;
+ if(btm) CopyBoard(boards[scratch+1], boards[scratch]), plyNr++;
+ if(PositionMatches(boards[scratch + plyNr], boards[currentMove])) return plyNr;
+ }
+ CopyBoard(boards[scratch + (plyNr+1&1)], boards[scratch + (plyNr&1)]);
+ plyNr++;
+ ApplyMove(fromX, fromY, toX, toY, promoChar, boards[scratch + (plyNr&1)]);
+ if(PositionMatches(boards[scratch + (plyNr&1)], boards[currentMove])) return plyNr;
+ }
+}
/* Load the nth game from open file f */
int
int gn = gameNumber;
ListGame *lg = NULL;
int numPGNTags = 0;
- int err;
+ int err, pos = -1;
GameMode oldGameMode;
VariantClass oldVariant = gameInfo.variant; /* [HGM] PGNvariant */
if (lg) {
fseek(f, lg->offset, 0);
GameListHighlight(gameNumber);
+ pos = lg->position;
gn = 1;
}
else {
AnalyzeFileEvent();
}
+ if (!matchMode && pos >= 0) {
+ ToNrEvent(pos); // [HGM] no autoplay if selected on position
+ } else
if (matchMode || appData.timeDelay == 0) {
ToEndEvent();
- gameMode = EditGame;
- ModeHighlight();
} else if (appData.timeDelay > 0) {
AutoPlayGameLoop();
}
if (gameMode == EditPosition || gameMode == IcsExamining) {
if(!appData.pieceMenu && blackPlaysFirst) EditPositionMenuEvent(ClearBoard, 0, 0);
SetBlackToPlayEvent();
- } else if (gameMode == EditGame || shiftKey) {
+ } else if ((gameMode == AnalyzeMode || gameMode == EditGame) && !blackFlag && WhiteOnMove(currentMove)) {
+ UserMoveEvent((int)EmptySquare, DROP_RANK, 0, 0, 0); // [HGM] multi-move: if not out of time, enters null move
+ } else if (shiftKey) {
AdjustClock(which, -1);
} else if (gameMode == IcsPlayingWhite ||
gameMode == MachinePlaysBlack) {
if (gameMode == EditPosition || gameMode == IcsExamining) {
if(!appData.pieceMenu && !blackPlaysFirst) EditPositionMenuEvent(ClearBoard, 0, 0);
SetWhiteToPlayEvent();
- } else if (gameMode == EditGame || shiftKey) {
+ } else if ((gameMode == AnalyzeMode || gameMode == EditGame) && !whiteFlag && !WhiteOnMove(currentMove)) {
+ UserMoveEvent((int)EmptySquare, DROP_RANK, 0, 0, 0); // [HGM] multi-move
+ } else if (shiftKey) {
AdjustClock(which, -1);
} else if (gameMode == IcsPlayingBlack ||
gameMode == MachinePlaysWhite) {
if (gameMode == EditGame || gameMode==AnalyzeMode ||
gameMode == PlayFromGameFile || gameMode == AnalyzeFile) {
while (currentMove > target) {
+ if(moveList[currentMove-1][1] == '@' && moveList[currentMove-1][0] == '@') {
+ // null move cannot be undone. Reload program with move history before it.
+ int i;
+ for(i=target; i>backwardMostMove; i--) { // seek back to start or previous null move
+ if(moveList[i-1][1] == '@' && moveList[i-1][0] == '@') break;
+ }
+ SendBoard(&first, i);
+ for(currentMove=i; currentMove<target; currentMove++) SendMoveToProgram(currentMove, &first);
+ break;
+ }
SendToProgram("undo\n", &first);
currentMove--;
}
char *text;
{
char title[MSG_SIZ];
- char buf[8000]; // comment can be long!
- int score, depth;
if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR) {
safeStrCpy(title, "Comment", sizeof(title)/sizeof(title[0]));
WhiteOnMove(moveNumber) ? " " : ".. ",
parseList[moveNumber]);
}
- // [HGM] PV info: display PV info together with (or as) comment
- if(moveNumber >= 0 && (depth = pvInfoList[moveNumber].depth) > 0) {
- if(text == NULL) text = "";
- score = pvInfoList[moveNumber].score;
- snprintf(buf,sizeof(buf)/sizeof(buf[0]), "%s%.2f/%d %d\n%s", score>0 ? "+" : "", score/100.,
- depth, (pvInfoList[moveNumber].time+50)/100, text);
- text = buf;
- }
if (text != NULL && (appData.autoDisplayComment || commentUp))
CommentPopUp(title, text);
}
}
// [HGM] vari: routines for shelving variations
+Boolean modeRestore = FALSE;
void
PushInner(int firstMove, int lastMove)
PushInner(firstMove, lastMove);
if(storedGames == 1) GreyRevert(FALSE);
+ if(gameMode == PlayFromGameFile) gameMode = EditGame, modeRestore = TRUE;
}
void
int i, j, nrMoves;
char buf[8000], moveBuf[20];
- storedGames--;
- ToNrEvent(savedFirst[storedGames]); // sets currentMove
+ ToNrEvent(savedFirst[storedGames-1]); // sets currentMove
+ storedGames--; // do this after ToNrEvent, to make sure HistorySet will refresh entire game after PopInner returns
nrMoves = savedLast[storedGames] - currentMove;
if(annotate) {
int cnt = 10;
CommentPopDown(); // make sure no stale variation comments to the destroyed line can remain open
PopInner(annotate);
+ if(currentMove < forwardMostMove) ForwardEvent(); else
+ HistorySet(parseList, backwardMostMove, forwardMostMove, currentMove-1);
- if(storedGames == 0) GreyRevert(TRUE);
+ if(storedGames == 0) { GreyRevert(TRUE); if(modeRestore) modeRestore = FALSE, gameMode = PlayFromGameFile; }
return TRUE;
}
char *p = text, *start = NULL, *end = NULL, wait = NULLCHAR;
int level = 0, move;
- if(gameMode != EditGame && gameMode != AnalyzeMode) return;
+ if(gameMode != EditGame && gameMode != AnalyzeMode && gameMode != PlayFromGameFile) return;
// first find outermost bracketing variation
while(*p) { // hope I got this right... Non-nesting {} and [] can screen each other and nesting ()
if(!wait) { // while inside [] pr {}, ignore everyting except matching closing ]}