X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=34ffd0a9e0023368ecbc1f70a82f99d6a8637f0c;hb=1c03d229073e56dda9e5856db5adaae51576a3bb;hp=13afbc52f435b666fe21ec76ee1c3997661edd45;hpb=8baea05c6e9e63f8b1b57891b67b5ac0e1961b81;p=xboard.git diff --git a/backend.c b/backend.c index 13afbc5..34ffd0a 100644 --- a/backend.c +++ b/backend.c @@ -5,7 +5,7 @@ * Massachusetts. * * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -224,6 +224,7 @@ FILE *WriteTourneyFile P((char *results, FILE *f)); void DisplayTwoMachinesTitle P(()); static void ExcludeClick P((int index)); void ToggleSecond P((void)); +void PauseEngine P((ChessProgramState *cps)); #ifdef WIN32 extern void ConsoleCreate(); @@ -875,7 +876,7 @@ ReplaceEngine (ChessProgramState *cps, int n) extern char *engineName, *engineDir, *engineChoice, *engineLine, *nickName, *params; extern Boolean isUCI, hasBook, storeVariant, v1, addToList, useNick; -static char resetOptions[] = +static char resetOptions[] = "-reuse -firstIsUCI false -firstHasOwnBookUCI true -firstTimeOdds 1 " "-firstInitString \"" INIT_STRING "\" -firstComputerString \"" COMPUTER_STRING "\" " "-firstFeatures \"\" -firstLogo \"\" -firstAccumulateTC 1 " @@ -947,7 +948,7 @@ Load (ChessProgramState *cps, int i) if(nickName[0]) snprintf(buf, MSG_SIZ, "\"%s\" -fcp ", nickName); else buf[0] = NULLCHAR; quote = strchr(p, '"') ? '\'' : '"'; // use single quotes around engine command if it contains double quotes snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), "%c%s%c -fd \"%s\"%s%s%s%s%s%s%s%s\n", - quote, p, quote, appData.directory[i], + quote, p, quote, appData.directory[i], useNick ? " -fn \"" : "", useNick ? nickName : "", useNick ? "\"" : "", @@ -1284,16 +1285,16 @@ ParseTimeControl (char *tc, float ti, int mps) if(mps) snprintf(buf, MSG_SIZ, ":%d/%s+%g", mps, mytc, ti); - else + else snprintf(buf, MSG_SIZ, ":%s+%g", mytc, ti); } else { if(mps) snprintf(buf, MSG_SIZ, ":%d/%s", mps, mytc); - else + else snprintf(buf, MSG_SIZ, ":%s", mytc); } fullTimeControlString = StrSave(buf); // this should now be in PGN format - + if( NextTimeControlFromString( &tc, &tc1 ) != 0 ) { return FALSE; } @@ -5415,7 +5416,8 @@ ParsePV (char *pv, Boolean storeComments, Boolean atEnd) Boolean valid; int nr = 0; - if (gameMode == AnalyzeMode && currentMove < forwardMostMove) { + lastParseAttempt = pv; if(!*pv) return; // turns out we crash when we parse an empty PV + if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) && currentMove < forwardMostMove) { PushInner(currentMove, forwardMostMove); // [HGM] engine might not be thinking on forwardMost position! pushed = TRUE; } @@ -5520,7 +5522,7 @@ PvToSAN (char *pv) static char buf[10*MSG_SIZ]; int i, k=0, savedEnd=endPV, saveFMM = forwardMostMove; *buf = NULLCHAR; - if(forwardMostMove < endPV) PushInner(forwardMostMove, endPV); + if(forwardMostMove < endPV) PushInner(forwardMostMove, endPV); // shelve PV of PV-walk ParsePV(pv, FALSE, 2); // this appends PV to game, suppressing any display of it for(i = forwardMostMove; i= BOARD_RGHT) return; @@ -7611,6 +7614,9 @@ MatingPotential (int pCnt[], int side, int nMine, int nHis, int stale, int bisCo || majors + (12*pCnt[BlackFerz-side] | 6*pCnt[BlackAlfil-side]) > 16; // KCKAA, KCKAX, KCKEEX, KCKEXX (XX!=HH), KCKXXX // TO DO: cases wih an unpromoted f-Pawn acting as platform for an opponent Cannon + } else if(v == VariantKnightmate) { + if(nMine == 1) return FALSE; + if(nMine == 2 && nHis == 1 && pCnt[WhiteBishop+side] + pCnt[WhiteFerz+side] + pCnt[WhiteKnight+side]) return FALSE; // KBK is only draw } else if(pCnt[WhiteKing] == 1 && pCnt[BlackKing] == 1) { // other variants with orthodox Kings int nBishops = pCnt[WhiteBishop+side] + pCnt[WhiteFerz+side]; @@ -7663,7 +7669,7 @@ Adjudicate (ChessProgramState *cps) // In any case it determnes if the game is a claimable draw (filling in EP_STATUS). // Actually ending the game is now based on the additional internal condition canAdjudicate. // Only when the game is ended, and the opponent is a computer, this opponent gets the move relayed. - int k, count = 0; static int bare = 1; + int k, drop, count = 0; static int bare = 1; ChessProgramState *engineOpponent = (gameMode == TwoMachinesPlay ? cps->other : (cps ? NULL : &first)); Boolean canAdjudicate = !appData.icsActive; @@ -7818,10 +7824,12 @@ Adjudicate (ChessProgramState *cps) /* Check for rep-draws */ count = 0; + drop = gameInfo.holdingsSize && (gameInfo.variant != VariantSuper && gameInfo.variant != VariantSChess + && gameInfo.variant != VariantGreat && gameInfo.variant != VariantGrand); for(k = forwardMostMove-2; - k>=backwardMostMove && k>=forwardMostMove-100 && + k>=backwardMostMove && k>=forwardMostMove-100 && (drop || (signed char)boards[k][EP_STATUS] < EP_UNKNOWN && - (signed char)boards[k+2][EP_STATUS] <= EP_NONE && (signed char)boards[k+1][EP_STATUS] <= EP_NONE; + (signed char)boards[k+2][EP_STATUS] <= EP_NONE && (signed char)boards[k+1][EP_STATUS] <= EP_NONE); k-=2) { int rights=0; if(CompareBoards(boards[k], boards[forwardMostMove])) { @@ -8013,7 +8021,7 @@ LoadError (char *errmess, ChessProgramState *cps) if(cps->initDone) return FALSE; cps->isr = NULL; // this should suppress further error popups from breaking pipes DestroyChildProcess(cps->pr, 9 ); // just to be sure - cps->pr = NoProc; + cps->pr = NoProc; if(cps == &first) { appData.noChessProgram = TRUE; gameMode = MachinePlaysBlack; ModeHighlight(); // kludge to unmark Machine Black menu @@ -8038,6 +8046,8 @@ DeferredBookMove (void) } static int savedWhitePlayer, savedBlackPlayer, pairingReceived; +static ChessProgramState *stalledEngine; +static char stashedInputMove[MSG_SIZ]; void HandleMachineMove (char *message, ChessProgramState *cps) @@ -8103,6 +8113,22 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if ((sscanf(message, "%s %s %s", buf1, buf2, machineMove) == 3 && strcmp(buf2, "...") == 0) || (sscanf(message, "%s %s", buf1, machineMove) == 2 && strcmp(buf1, "move") == 0)) { + if(pausing && !cps->pause) { // for pausing engine that does not support 'pause', we stash its move for processing when we resume. + if(appData.debugMode) fprintf(debugFP, "pause %s engine after move\n", cps->which); + safeStrCpy(stashedInputMove, message, MSG_SIZ); + stalledEngine = cps; + if(appData.ponderNextMove) { // bring opponent out of ponder + if(gameMode == TwoMachinesPlay) { + if(cps->other->pause) + PauseEngine(cps->other); + else + SendToProgram("easy\n", cps->other); + } + } + StopClocks(); + return; + } + /* This method is only useful on engines that support ping */ if (cps->lastPing != cps->lastPong) { if (gameMode == BeginningOfGame) { @@ -8370,7 +8396,7 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. return; // [HGM] This return was missing, causing option features to be recognized as non-compliant commands! } - if ((!appData.testLegality || gameInfo.variant == VariantFairy) && + if ((!appData.testLegality || gameInfo.variant == VariantFairy) && !strncmp(message, "setup ", 6)) { // [HGM] allow first engine to define opening position int dummy, s=6; char buf[MSG_SIZ]; if(appData.icsActive || forwardMostMove != 0 || cps != &first) return; @@ -9426,8 +9452,8 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) ) { /* white pawn promotion */ board[toY][toX] = CharToPiece(ToUpper(promoChar)); - if(gameInfo.variant==VariantBughouse || - gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */ + if((gameInfo.variant==VariantBughouse || gameInfo.variant==VariantCrazyhouse) + && PieceToChar(PROMOTED board[toY][toX]) == '~') /* [HGM] use shadow piece (if available) */ board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]); board[fromY][fromX] = EmptySquare; } else if ((fromY >= BOARD_HEIGHT>>1) @@ -9487,8 +9513,8 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) ) { /* black pawn promotion */ board[toY][toX] = CharToPiece(ToLower(promoChar)); - if(gameInfo.variant==VariantBughouse || - gameInfo.variant==VariantCrazyhouse) /* [HGM] use shadow piece */ + if((gameInfo.variant==VariantBughouse || gameInfo.variant==VariantCrazyhouse) + && PieceToChar(PROMOTED board[toY][toX]) == '~') /* [HGM] use shadow piece (if available) */ board[toY][toX] = (ChessSquare) (PROMOTED board[toY][toX]); board[fromY][fromX] = EmptySquare; } else if ((fromY < BOARD_HEIGHT>>1) @@ -9748,12 +9774,12 @@ ShowMove (int fromX, int fromY, int toX, int toY) if (instant) return; DisplayMove(currentMove - 1); - DrawPosition(FALSE, boards[currentMove]); if (!pausing || gameMode == PlayFromGameFile || gameMode == AnalyzeFile) { if (appData.highlightLastMove) { // [HGM] moved to after DrawPosition, as with arrow it could redraw old board SetHighlights(fromX, fromY, toX, toY); } } + DrawPosition(FALSE, boards[currentMove]); DisplayBothClocks(); HistorySet(parseList,backwardMostMove,forwardMostMove,currentMove-1); } @@ -10331,7 +10357,7 @@ Pairing (int nr, int nPlayers, int *whitePlayer, int *blackPlayer, int *syncInte *blackPlayer = curRound + appData.tourneyType; } - // take care of white/black alternation per round. + // take care of white/black alternation per round. // For cycles and games this is already taken care of by default, derived from matchGame! return curRound & 1; } @@ -10380,7 +10406,7 @@ NextTourneyGame (int nr, int *swapColors) SendToProgram(buf, &pairing); return 0; // wait for pairing engine to answer (which causes NextTourneyGame to be called again... } - pairingReceived = 0; // ... so we continue here + pairingReceived = 0; // ... so we continue here *swapColors = 0; appData.matchGames = appData.tourneyCycles * syncInterval - 1; whitePlayer = savedWhitePlayer-1; blackPlayer = savedBlackPlayer-1; @@ -10504,6 +10530,8 @@ GameEnds (ChessMove result, char *resultDetails, int whosays) fromX = fromY = -1; // [HGM] abort any move the user is entering. + if(pausing) PauseEvent(); // can happen when we abort a paused game (New Game or Quit) + if (appData.icsActive && (whosays == GE_ENGINE || whosays >= GE_ENGINE1)) { /* If we are playing on ICS, the server decides when the game is over, but the engine can offer to draw, claim @@ -10647,6 +10675,7 @@ GameEnds (ChessMove result, char *resultDetails, int whosays) if (*appData.savePositionFile != NULLCHAR) { SavePositionToFile(appData.savePositionFile); } + AddGameToBook(FALSE); // Only does something during Monte-Carlo book building } } @@ -11752,12 +11781,12 @@ InitSearch () if(piece < BlackPawn) piece += BlackPawn; else if(piece < EmptySquare) piece -= BlackPawn; // color-flip reverseBoard[r][f] = piece; } - reverseBoard[EP_STATUS-1] = soughtBoard[EP_STATUS-1] ^ 3; + reverseBoard[EP_STATUS-1] = soughtBoard[EP_STATUS-1] ^ 3; for(r=0; r<6; r++) reverseBoard[CASTLING][r] = boards[currentMove][CASTLING][(r+3)%6]; if(appData.findMirror && appData.searchMode <= 3 && (!nrCastlingRights - || (boards[currentMove][CASTLING][2] == NoRights || + || (boards[currentMove][CASTLING][2] == NoRights || boards[currentMove][CASTLING][0] == NoRights && boards[currentMove][CASTLING][1] == NoRights ) - && (boards[currentMove][CASTLING][5] == NoRights || + && (boards[currentMove][CASTLING][5] == NoRights || boards[currentMove][CASTLING][3] == NoRights && boards[currentMove][CASTLING][4] == NoRights ) ) ) { flipSearch = TRUE; @@ -11779,6 +11808,7 @@ InitSearch () } GameInfo dummyInfo; +static int creatingBook; int GameContainsPosition (FILE *f, ListGame *lg) @@ -12242,6 +12272,7 @@ LoadGame (FILE *f, int gameNumber, char *title, int useList) cm = (ChessMove) Myylex(); } + if(!creatingBook) { if (first.pr == NoProc) { StartChessProgram(&first); } @@ -12254,6 +12285,7 @@ LoadGame (FILE *f, int gameNumber, char *title, int useList) } DisplayBothClocks(); } + } /* [HGM] server: flag to write setup moves in broadcast file as one */ loadFlag = appData.suppressLoadMoves; @@ -12318,11 +12350,10 @@ LoadGame (FILE *f, int gameNumber, char *title, int useList) if (oldGameMode == AnalyzeFile || oldGameMode == AnalyzeMode) { appData.loadGameIndex = -1; // [HGM] order auto-stepping through games - keepInfo = 1; AnalyzeFileEvent(); - keepInfo = 0; } + if(creatingBook) return TRUE; if (!matchMode && pos > 0) { ToNrEvent(pos); // [HGM] no autoplay if selected on position } else @@ -13357,6 +13388,20 @@ ExitEvent (int status) } void +PauseEngine (ChessProgramState *cps) +{ + SendToProgram("pause\n", cps); + cps->pause = 2; +} + +void +UnPauseEngine (ChessProgramState *cps) +{ + SendToProgram("resume\n", cps); + cps->pause = 1; +} + +void PauseEvent () { if (appData.debugMode) @@ -13364,8 +13409,24 @@ PauseEvent () if (pausing) { pausing = FALSE; ModeHighlight(); + if(stalledEngine) { // [HGM] pause: resume game by releasing withheld move + StartClocks(); + if(gameMode == TwoMachinesPlay) { // we might have to make the opponent resume pondering + if(stalledEngine->other->pause == 2) UnPauseEngine(stalledEngine->other); + else if(appData.ponderNextMove) SendToProgram("hard\n", stalledEngine->other); + } + if(appData.ponderNextMove) SendToProgram("hard\n", stalledEngine); + HandleMachineMove(stashedInputMove, stalledEngine); + stalledEngine = NULL; + return; + } if (gameMode == MachinePlaysWhite || - gameMode == MachinePlaysBlack) { + gameMode == TwoMachinesPlay || + gameMode == MachinePlaysBlack) { // the thinking engine must have used pause mode, or it would have been stalledEngine + if(first.pause) UnPauseEngine(&first); + else if(appData.ponderNextMove) SendToProgram("hard\n", &first); + if(second.pause) UnPauseEngine(&second); + else if(gameMode == TwoMachinesPlay && appData.ponderNextMove) SendToProgram("hard\n", &second); StartClocks(); } else { DisplayBothClocks(); @@ -13377,7 +13438,7 @@ PauseEvent () Reset(FALSE, TRUE); SendToICS(ics_prefix); SendToICS("refresh\n"); - } else if (currentMove < forwardMostMove) { + } else if (currentMove < forwardMostMove && gameMode != AnalyzeMode) { ForwardInner(forwardMostMove); } pauseExamInvalid = FALSE; @@ -13408,12 +13469,29 @@ PauseEvent () case TwoMachinesPlay: if (forwardMostMove == 0) return; /* don't pause if no one has moved */ - if ((gameMode == MachinePlaysWhite && - !WhiteOnMove(forwardMostMove)) || - (gameMode == MachinePlaysBlack && - WhiteOnMove(forwardMostMove))) { + if(gameMode == TwoMachinesPlay) { // [HGM] pause: stop clocks if engine can be paused immediately + ChessProgramState *onMove = (WhiteOnMove(forwardMostMove) == (first.twoMachinesColor[0] == 'w') ? &first : &second); + if(onMove->pause) { // thinking engine can be paused + PauseEngine(onMove); // do it + if(onMove->other->pause) // pondering opponent can always be paused immediately + PauseEngine(onMove->other); + else + SendToProgram("easy\n", onMove->other); + StopClocks(); + } else if(appData.ponderNextMove) SendToProgram("easy\n", onMove); // pre-emptively bring out of ponder + } else if(gameMode == (WhiteOnMove(forwardMostMove) ? MachinePlaysWhite : MachinePlaysBlack)) { // engine on move + if(first.pause) { + PauseEngine(&first); + StopClocks(); + } else if(appData.ponderNextMove) SendToProgram("easy\n", &first); // pre-emptively bring out of ponder + } else { // human on move, pause pondering by either method + if(first.pause) + PauseEngine(&first); + else if(appData.ponderNextMove) + SendToProgram("easy\n", &first); StopClocks(); } + // if no immediate pausing is possible, wait for engine to move, and stop clocks then case AnalyzeMode: pausing = TRUE; ModeHighlight(); @@ -13549,7 +13627,9 @@ AnalyzeFileEvent () } if (gameMode != AnalyzeMode) { + keepInfo = 1; // mere annotating should not alter PGN tags EditGameEvent(); + keepInfo = 0; if (gameMode != EditGame) return; if (!appData.showThinking) ToggleShowThinking(); ResurrectChessProgram(); @@ -13562,7 +13642,6 @@ AnalyzeFileEvent () gameMode = AnalyzeFile; pausing = FALSE; ModeHighlight(); - SetGameInfo(); StartAnalysisClock(); GetTimeMark(&lastNodeCountTime); @@ -13738,7 +13817,7 @@ DisplayTwoMachinesTitle () gameInfo.white, _("vs."), gameInfo.black, nextGame+1, appData.matchGames+1, appData.tourneyType>0 ? "gt" : appData.tourneyType<0 ? "sw" : "rr"); - } else + } else if (first.twoMachinesColor[0] == 'w') { snprintf(buf, MSG_SIZ, "%s %s %s (%d-%d-%d)", gameInfo.white, _("vs."), gameInfo.black, @@ -14813,7 +14892,7 @@ BackwardInner (int target) 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); + SendBoard(&first, i); if(second.analyzing) SendBoard(&second, i); for(currentMove=i; currentMovenumber <= 0 ) { + DisplayError(_("Game list not loaded or empty"), 0); + return; + } + + if(!secondTime && (f = fopen(appData.polyglotBook, "r"))) { + fclose(f); + secondTime++; + DisplayNote(_("Book file exists! Try again for overwrite.")); + return; + } + + creatingBook = TRUE; + secondTime = FALSE; + + /* Get list size */ + for (nItem = 1; nItem <= ((ListGame *) gameList.tailPred)->number; nItem++){ + LoadGame(f, nItem, "", TRUE); + AddGameToBook(TRUE); + lg = (ListGame *) lg->node.succ; + } + + creatingBook = FALSE; + FlushBook(); +} + +void BookEvent () { if (appData.noChessProgram) return; @@ -15259,7 +15372,7 @@ ReplaceComment (int index, char *text) char *p; float score; - if(index && sscanf(text, "%f/%d", &score, &len) == 2 && + if(index && sscanf(text, "%f/%d", &score, &len) == 2 && pvInfoList[index-1].depth == len && fabs(pvInfoList[index-1].score - score*100.) < 0.5 && (p = strchr(text, '\n'))) text = p; // [HGM] strip off first line with PV info, if any @@ -15572,7 +15685,7 @@ ReceiveFromProgram (InputSourceRef isr, VOIDSTAR closure, char *message, int cou sscanf(message, "tell%c", &c)!=1 && sscanf(message, "0-1 %c", &c)!=1 && sscanf(message, "1-0 %c", &c)!=1 && sscanf(message, "1/2-1/2 %c", &c)!=1 && sscanf(message, "setboard %c", &c)!=1 && sscanf(message, "setup %c", &c)!=1 && - sscanf(message, "hint: %c", &c)!=1 && + sscanf(message, "hint: %c", &c)!=1 && sscanf(message, "pong %c", &c)!=1 && start != '#') { quote = appData.engineComments == 2 ? "# " : "### NON-COMPLIANT! ### "; print = (appData.engineComments >= 2); @@ -15910,7 +16023,7 @@ ParseFeatures (char *args, ChessProgramState *cps) if (BoolFeature(&p, "exclude", &cps->excludeMoves, cps)) continue; if (BoolFeature(&p, "ics", &cps->sendICS, cps)) continue; if (BoolFeature(&p, "name", &cps->sendName, cps)) continue; - if (BoolFeature(&p, "pause", &val, cps)) continue; /* unused at present */ + if (BoolFeature(&p, "pause", &cps->pause, cps)) continue; // [HGM] pause if (IntFeature(&p, "done", &val, cps)) { FeatureDone(cps, val); continue; @@ -16054,9 +16167,9 @@ AskQuestionEvent (char *title, char *question, char *replyPrefix, char *which) void TypeInEvent (char firstChar) { - if ((gameMode == BeginningOfGame && !appData.icsActive) || + if ((gameMode == BeginningOfGame && !appData.icsActive) || gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack || - gameMode == AnalyzeMode || gameMode == EditGame || + gameMode == AnalyzeMode || gameMode == EditGame || gameMode == EditPosition || gameMode == IcsExamining || gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack || isdigit(firstChar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes @@ -16092,16 +16205,16 @@ TypeInDoneEvent (char *move) return; } - if (gameMode != EditGame && currentMove != forwardMostMove && + if (gameMode != EditGame && currentMove != forwardMostMove && gameMode != Training) { DisplayMoveError(_("Displayed move is not current")); } else { - int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, + int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, &moveType, &fromX, &fromY, &toX, &toY, &promoChar); if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized - if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, + if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) { - UserMoveEvent(fromX, fromY, toX, toY, promoChar); + UserMoveEvent(fromX, fromY, toX, toY, promoChar); } else { DisplayMoveError(_("Could not parse move")); } @@ -17519,7 +17632,7 @@ LoadTheme () snprintf(buf, MSG_SIZ, "\"%s\"", nickName); if(appData.useBitmaps) { snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " -ubt true -lbtf \"%s\" -dbtf \"%s\" -lbtm %d -dbtm %d", - appData.liteBackTextureFile, appData.darkBackTextureFile, + appData.liteBackTextureFile, appData.darkBackTextureFile, appData.liteBackTextureMode, appData.darkBackTextureMode ); } else {