From: A. Scotti Date: Thu, 16 Apr 2009 20:53:41 +0000 (-0700) Subject: changes from Alessandro Scotti from 20050322 X-Git-Tag: v4.3.2~6 X-Git-Url: http://winboard.nl/cgi-bin?p=xboard.git;a=commitdiff_plain;h=a180888cfea059c10e147b2357571c421cb4346f changes from Alessandro Scotti from 20050322 --- diff --git a/backend.c b/backend.c index f28d863..958f503 100644 --- a/backend.c +++ b/backend.c @@ -1,6 +1,6 @@ /* * backend.c -- Common back end for X and Windows NT versions of - * XBoard $Id$ + * XBoard $Id: backend.c,v 2.6 2003/11/28 09:37:36 mann Exp $ * * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. * Enhancements Copyright 1992-2001 Free Software Foundation, Inc. @@ -47,8 +47,21 @@ * * See the file ChangeLog for a revision history. */ +/* [AS] For debugging purposes */ +#ifdef WIN32 +#include + +#define DoSleep( n ) if( (n) != 0 ) Sleep( (n) ); + +#else + +#define DoSleep( n ) + +#endif + #include "config.h" +#include #include #include #include @@ -131,6 +144,12 @@ typedef struct { int seen_stat; /* 1 if we've seen the stat01: line */ } ChessProgramStats; +/* [AS] Search stats from chessprogram, for the played move */ +typedef struct { + int score; + int depth; +} ChessProgramStats_Move; + int establish P((void)); void read_from_player P((InputSourceRef isr, VOIDSTAR closure, char *buf, int count, int error)); @@ -245,6 +264,35 @@ static ChessProgramStats programStats; #define TN_SGA 0003 #define TN_PORT 23 +/* [AS] */ +static char * safeStrCpy( char * dst, const char * src, size_t count ) +{ + assert( dst != NULL ); + assert( src != NULL ); + assert( count > 0 ); + + strncpy( dst, src, count ); + dst[ count-1 ] = '\0'; + return dst; +} + +static char * safeStrCat( char * dst, const char * src, size_t count ) +{ + size_t dst_len; + + assert( dst != NULL ); + assert( src != NULL ); + assert( count > 0 ); + + dst_len = strlen(dst); + + assert( count > dst_len ); /* Buffer size must be greater than current length */ + + safeStrCpy( dst + dst_len, src, count - dst_len ); + + return dst; +} + /* Fake up flags for now, as we aren't keeping track of castling availability yet */ int @@ -275,6 +323,15 @@ PosFlags(index) FILE *gameFileFP, *debugFP; +/* + [AS] Note: sometimes, the sscanf() function is used to parse the input + into a fixed-size buffer. Because of this, we must be prepared to + receive strings as long as the size of the input buffer, which is currently + set to 4K for Windows and 8K for the rest. + So, we must either allocate sufficiently large buffers here, or + reduce the size of the input buffer in the input reading part. +*/ + char cmailMove[CMAIL_MAX_GAMES][MOVE_LEN], cmailMsg[MSG_SIZ]; char bookOutput[MSG_SIZ*10], thinkOutput[MSG_SIZ*10], lastHint[MSG_SIZ]; char thinkOutput1[MSG_SIZ*10]; @@ -317,12 +374,17 @@ InputSourceRef telnetISR = NULL, fromUserISR = NULL, cmailISR = NULL; GameMode gameMode = BeginningOfGame; char moveList[MAX_MOVES][MOVE_LEN], parseList[MAX_MOVES][MOVE_LEN * 2]; char *commentList[MAX_MOVES], *cmailCommentList[CMAIL_MAX_GAMES]; +ChessProgramStats_Move pvInfoList[MAX_MOVES]; /* [AS] Info about engine thinking */ +int hiddenThinkOutputState = 0; /* [AS] */ +int adjudicateLossThreshold = 0; /* [AS] Automatic adjudication */ +int adjudicateLossPlies = 6; char white_holding[64], black_holding[64]; TimeMark lastNodeCountTime; long lastNodeCount=0; int have_sent_ICS_logon = 0; int movesPerSession; long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement; +long timeControl_2; /* [AS] Allow separate time controls */ long timeRemaining[2][MAX_MOVES]; int matchGame = 0; TimeMark programStartTime; @@ -446,6 +508,15 @@ InitBackEnd1() appData.zippyTalk = appData.zippyPlay = FALSE; } + /* [AS] Initialize pv info list */ + { + int i; + + for( i=0; i PROTOVER || appData.firstProtocolVersion < 1) { char buf[MSG_SIZ]; @@ -626,12 +703,73 @@ InitBackEnd1() } } +int NextIntegerFromString( char ** str, long * value ) +{ + int result = -1; + char * s = *str; + + while( *s == ' ' || *s == '\t' ) { + s++; + } + + *value = 0; + + if( *s >= '0' && *s <= '9' ) { + while( *s >= '0' && *s <= '9' ) { + *value = *value * 10 + (*s - '0'); + s++; + } + + result = 0; + } + + *str = s; + + return result; +} + +int NextTimeControlFromString( char ** str, long * value ) +{ + long temp; + int result = NextIntegerFromString( str, &temp ); + + if( result == 0 ) { + *value = temp * 60; /* Minutes */ + if( **str == ':' ) { + (*str)++; + result = NextIntegerFromString( str, &temp ); + *value += temp; /* Seconds */ + } + } + + return result; +} + +int GetTimeControlForWhite() +{ + int result = timeControl; + + return result; +} + +int GetTimeControlForBlack() +{ + int result = timeControl; + + if( timeControl_2 > 0 ) { + result = timeControl_2; + } + + return result; +} + int ParseTimeControl(tc, ti, mps) char *tc; int ti; int mps; { +#if 0 int matched, min, sec; matched = sscanf(tc, "%d:%d", &min, &sec); @@ -642,6 +780,38 @@ ParseTimeControl(tc, ti, mps) } else { return FALSE; } +#else + long tc1; + long tc2; + + if( NextTimeControlFromString( &tc, &tc1 ) != 0 ) { + return FALSE; + } + + if( *tc == '/' ) { + /* Parse second time control */ + tc++; + + if( NextTimeControlFromString( &tc, &tc2 ) != 0 ) { + return FALSE; + } + + if( tc2 == 0 ) { + return FALSE; + } + + timeControl_2 = tc2 * 1000; + } + else { + timeControl_2 = 0; + } + + if( tc1 == 0 ) { + return FALSE; + } + + timeControl = tc1 * 1000; +#endif if (ti >= 0) { timeIncrement = ti * 1000; /* convert to ms */ @@ -2725,6 +2895,7 @@ ParseBoard12(string) gameInfo.white = StrSave(white); gameInfo.black = StrSave(black); timeControl = basetime * 60 * 1000; + timeControl_2 = 0; timeIncrement = increment * 1000; movesPerSession = 0; gameInfo.timeControl = TimeControlTagValue(); @@ -3242,6 +3413,16 @@ InitPosition(redraw) int redraw; { currentMove = forwardMostMove = backwardMostMove = 0; + + /* [AS] Initialize pv info list */ + { + int i; + + for( i=0; i= adjudicateLossPlies ) { + int count = 0; + + while( count < adjudicateLossPlies ) { + int score = pvInfoList[ forwardMostMove - count - 1 ].score; + + if( count & 1 ) { + score = -score; /* Flip score for winning side */ + } + + if( score > adjudicateLossThreshold ) { + break; + } + + count++; + } + + if( count >= adjudicateLossPlies ) { + GameEnds( WhiteOnMove(forwardMostMove) ? WhiteWins : BlackWins, + "Xboard adjudication", + GE_XBOARD ); + } + } + return; } @@ -4315,7 +4532,7 @@ HandleMachineMove(message, cps) /* * Look for thinking output */ - if (appData.showThinking) { + if ( appData.showThinking) { int plylev, mvleft, mvtot, curscore, time; char mvname[MOVE_LEN]; unsigned long nodes; @@ -4337,8 +4554,7 @@ HandleMachineMove(message, cps) case AnalyzeFile: break; case TwoMachinesPlay: - if ((cps->twoMachinesColor[0] == 'w') != - WhiteOnMove(forwardMostMove)) { + if ((cps->twoMachinesColor[0] == 'w') != WhiteOnMove(forwardMostMove)) { ignore = TRUE; } break; @@ -4361,6 +4577,13 @@ HandleMachineMove(message, cps) programStats.score = curscore; programStats.got_only_move = 0; + /* [AS] Negate score if machine is playing black and it's reporting absolute scores */ + if( cps->scoreIsAbsolute && + ((gameMode == MachinePlaysBlack) || (gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b')) ) + { + programStats.score = -curscore; + } + /* Buffer overflow protection */ if (buf1[0] != NULLCHAR) { if (strlen(buf1) >= sizeof(programStats.movelist) @@ -4369,10 +4592,8 @@ HandleMachineMove(message, cps) "PV is too long; using the first %d bytes.\n", sizeof(programStats.movelist) - 1); } - strncpy(programStats.movelist, buf1, - sizeof(programStats.movelist)); - programStats.movelist[sizeof(programStats.movelist) - 1] - = NULLCHAR; + + safeStrCpy( programStats.movelist, buf1, sizeof(programStats.movelist) ); } else { sprintf(programStats.movelist, " no PV\n"); } @@ -4389,16 +4610,32 @@ HandleMachineMove(message, cps) programStats.line_is_book = 0; } - sprintf(thinkOutput, "[%d]%c%+.2f %s%s%s", + /* + [AS] Protect the thinkOutput buffer from overflow... this + is only useful if buf1 hasn't overflowed first! + */ + sprintf(thinkOutput, "[%d]%c%+.2f %s%s", plylev, (gameMode == TwoMachinesPlay ? ToUpper(cps->twoMachinesColor[0]) : ' '), ((double) curscore) / 100.0, prefixHint ? lastHint : "", - prefixHint ? " " : "", buf1); + prefixHint ? " " : "" ); + + if( buf1[0] != NULLCHAR ) { + unsigned max_len = sizeof(thinkOutput) - strlen(thinkOutput) - 1; - if (currentMove == forwardMostMove || - gameMode == AnalyzeMode || gameMode == AnalyzeFile) { + if( strlen(buf1) > max_len ) { + if( appData.debugMode) { + fprintf(debugFP,"PV is too long for thinkOutput, truncating.\n"); + } + buf1[max_len+1] = '\0'; + } + + strcat( thinkOutput, buf1 ); + } + + if (currentMove == forwardMostMove || gameMode == AnalyzeMode || gameMode == AnalyzeFile) { DisplayMove(currentMove - 1); DisplayAnalysis(); } @@ -4423,8 +4660,7 @@ HandleMachineMove(message, cps) isn't searching, so stats won't change) */ programStats.line_is_book = 1; - if (currentMove == forwardMostMove || gameMode==AnalyzeMode || - gameMode == AnalyzeFile) { + if (currentMove == forwardMostMove || gameMode==AnalyzeMode || gameMode == AnalyzeFile) { DisplayMove(currentMove - 1); DisplayAnalysis(); } @@ -4462,14 +4698,25 @@ HandleMachineMove(message, cps) } else if (thinkOutput[0] != NULLCHAR && strncmp(message, " ", 4) == 0) { + unsigned message_len; + p = message; while (*p && *p == ' ') p++; + + message_len = strlen( p ); + + /* [AS] Avoid buffer overflow */ + if( sizeof(thinkOutput) - strlen(thinkOutput) - 1 > message_len ) { strcat(thinkOutput, " "); strcat(thinkOutput, p); + } + + if( sizeof(programStats.movelist) - strlen(programStats.movelist) - 1 > message_len ) { strcat(programStats.movelist, " "); strcat(programStats.movelist, p); - if (currentMove == forwardMostMove || gameMode==AnalyzeMode || - gameMode == AnalyzeFile) { + } + + if (currentMove == forwardMostMove || gameMode==AnalyzeMode || gameMode == AnalyzeFile) { DisplayMove(currentMove - 1); DisplayAnalysis(); } @@ -4987,6 +5234,23 @@ NextMatchGame P((void)) TwoMachinesEventIfReady(); } +void UserAdjudicationEvent( int result ) +{ + ChessMove gameResult = GameIsDrawn; + + if( result > 0 ) { + gameResult = WhiteWins; + } + else if( result < 0 ) { + gameResult = BlackWins; + } + + if( gameMode == TwoMachinesPlay ) { + GameEnds( gameResult, "User adjudication", GE_XBOARD ); + } +} + + void GameEnds(result, resultDetails, whosays) ChessMove result; @@ -5166,7 +5430,9 @@ GameEnds(result, resultDetails, whosays) if (first.pr != NoProc) { ExitAnalyzeMode(); + DoSleep( appData.delayBeforeQuit ); SendToProgram("quit\n", &first); + DoSleep( appData.delayAfterQuit ); DestroyChildProcess(first.pr, first.useSigterm); } first.pr = NoProc; @@ -5189,7 +5455,9 @@ GameEnds(result, resultDetails, whosays) second.isr = NULL; if (second.pr != NoProc) { + DoSleep( appData.delayBeforeQuit ); SendToProgram("quit\n", &second); + DoSleep( appData.delayAfterQuit ); DestroyChildProcess(second.pr, second.useSigterm); } second.pr = NoProc; @@ -6526,6 +6794,7 @@ SaveGamePGN(f) char *movetext; char numtext[32]; int movelen, numlen, blank; + char move_buffer[100]; /* [AS] Buffer for move+PV info */ tm = time((time_t *) NULL); @@ -6585,6 +6854,17 @@ SaveGamePGN(f) /* Get move */ movetext = SavePart(parseList[i]); + + /* [AS] Add PV info if present */ + if( i > 0 && appData.saveExtendedInfoInPGN && pvInfoList[i].depth > 0 ) { + sprintf( move_buffer, "%s {%s%.2f/%d}", + movetext, + pvInfoList[i].score >= 0 ? "+" : "", + pvInfoList[i].score / 100.0, + pvInfoList[i].depth ); + movetext = move_buffer; + } + movelen = strlen(movetext); /* Print move */ @@ -7132,11 +7412,16 @@ ExitEvent(status) /* Kill off chess programs */ if (first.pr != NoProc) { ExitAnalyzeMode(); + + DoSleep( appData.delayBeforeQuit ); SendToProgram("quit\n", &first); + DoSleep( appData.delayAfterQuit ); DestroyChildProcess(first.pr, first.useSigterm); } if (second.pr != NoProc) { + DoSleep( appData.delayBeforeQuit ); SendToProgram("quit\n", &second); + DoSleep( appData.delayAfterQuit ); DestroyChildProcess(second.pr, second.useSigterm); } if (first.isr != NULL) { @@ -8834,6 +9119,13 @@ ReceiveFromProgram(isr, closure, message, count, error) "Error reading from %s chess program (%s)", cps->which, cps->program); RemoveInputSource(cps->isr); + + /* [AS] Program is misbehaving badly... kill it */ + if( count == -2 ) { + DestroyChildProcess( cps->pr, 9 ); + cps->pr = NoProc; + } + DisplayFatalError(buf, error, 1); } GameEnds((ChessMove) 0, NULL, GE_PLAYER); @@ -8865,6 +9157,12 @@ SendTimeControl(cps, mps, tc, inc, sd, st) char buf[MSG_SIZ]; int seconds = (tc / 1000) % 60; + if( timeControl_2 > 0 ) { + if( (gameMode == MachinePlaysBlack) || (gameMode == TwoMachinesPlay && cps->twoMachinesColor[0] == 'b') ) { + tc = timeControl_2; + } + } + if (st > 0) { /* Set exact time per move, normally using st command */ if (cps->stKludge) { @@ -9157,13 +9455,29 @@ DisplayMove(moveNumber) if (moveNumber == forwardMostMove - 1 || gameMode == AnalyzeMode || gameMode == AnalyzeFile) { - strcpy(cpThinkOutput, thinkOutput); - if (strchr(cpThinkOutput, '\n')) + safeStrCpy(cpThinkOutput, thinkOutput, sizeof(cpThinkOutput)); + + if (strchr(cpThinkOutput, '\n')) { *strchr(cpThinkOutput, '\n') = NULLCHAR; + } } else { *cpThinkOutput = NULLCHAR; } + /* [AS] Hide thinking from human user */ + if( appData.hideThinkingFromHuman && gameMode != TwoMachinesPlay ) { + *cpThinkOutput = NULLCHAR; + if( thinkOutput[0] != NULLCHAR ) { + int i; + + for( i=0; i<=hiddenThinkOutputState; i++ ) { + cpThinkOutput[i] = '.'; + } + cpThinkOutput[i] = NULLCHAR; + hiddenThinkOutputState = (hiddenThinkOutputState + 1) % 3; + } + } + if (moveNumber == forwardMostMove - 1 && gameInfo.resultDetails != NULL) { if (gameInfo.resultDetails[0] == NULLCHAR) { @@ -9214,6 +9528,7 @@ void DisplayAnalysis() { char buf[MSG_SIZ]; + char lst[MSG_SIZ / 2]; double nps; static char *xtra[] = { "", " (--)", " (++)" }; int h, m, s, cs; @@ -9223,8 +9538,10 @@ DisplayAnalysis() } if (programStats.got_only_move) { - strcpy(buf, programStats.movelist); + safeStrCpy(buf, programStats.movelist, sizeof(buf)); } else { + safeStrCpy( lst, programStats.movelist, sizeof(lst)); + nps = (((double)programStats.nodes) / (((double)programStats.time)/100.0)); @@ -9241,8 +9558,8 @@ DisplayAnalysis() programStats.depth, programStats.nr_moves-programStats.moves_left, programStats.nr_moves, programStats.move_name, - ((float)programStats.score)/100.0, programStats.movelist, - only_one_move(programStats.movelist)? + ((float)programStats.score)/100.0, lst, + only_one_move(lst)? xtra[programStats.got_fail] : "", programStats.nodes, (int)nps, h, m, s, cs); } else { @@ -9250,8 +9567,8 @@ DisplayAnalysis() programStats.depth, programStats.nr_moves-programStats.moves_left, programStats.nr_moves, ((float)programStats.score)/100.0, - programStats.movelist, - only_one_move(programStats.movelist)? + lst, + only_one_move(lst)? xtra[programStats.got_fail] : "", programStats.nodes, (int)nps, h, m, s, cs); } @@ -9259,8 +9576,8 @@ DisplayAnalysis() sprintf(buf, "depth=%d %+.2f %s%s\nNodes: %lu NPS: %d\nTime: %02d:%02d:%02d.%02d", programStats.depth, ((float)programStats.score)/100.0, - programStats.movelist, - only_one_move(programStats.movelist)? + lst, + only_one_move(lst)? xtra[programStats.got_fail] : "", programStats.nodes, (int)nps, h, m, s, cs); } @@ -9390,11 +9707,11 @@ CheckTimeControl() switch ((forwardMostMove + 1) % (movesPerSession * 2)) { case 0: /* White made time control */ - whiteTimeRemaining += timeControl; + whiteTimeRemaining += GetTimeControlForWhite(); break; case 1: /* Black made time control */ - blackTimeRemaining += timeControl; + blackTimeRemaining += GetTimeControlForBlack(); break; default: break; @@ -9498,7 +9815,8 @@ ResetClocks() if (appData.icsActive) { whiteTimeRemaining = blackTimeRemaining = 0; } else { - whiteTimeRemaining = blackTimeRemaining = timeControl; + whiteTimeRemaining = GetTimeControlForWhite(); + blackTimeRemaining = GetTimeControlForBlack(); } if (whiteFlag || blackFlag) { DisplayTitle(""); diff --git a/backend.h b/backend.h index 9e1fbb0..f311074 100644 --- a/backend.h +++ b/backend.h @@ -1,6 +1,6 @@ /* * backend.h -- Interface exported by XBoard back end - * $Id$ + * $Id: backend.h,v 2.1 2003/10/27 19:21:00 mann Exp $ * * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. * Enhancements Copyright 1992-95 Free Software Foundation, Inc. @@ -112,6 +112,7 @@ void DrawEvent P((void)); void AbortEvent P((void)); void AdjournEvent P((void)); void ResignEvent P((void)); +void UserAdjudicationEvent P((int result)); void StopObservingEvent P((void)); void StopExaminingEvent P((void)); void PonderNextMoveEvent P((int newState)); @@ -236,6 +237,7 @@ typedef struct _CPS { int analyzing; int protocolVersion; int initDone; + int scoreIsAbsolute; /* [AS] 0=don't know (standard), 1=score is always from white side */ } ChessProgramState; extern ChessProgramState first, second; diff --git a/common.h b/common.h index 62281a4..61741a1 100644 --- a/common.h +++ b/common.h @@ -1,6 +1,6 @@ /* * common.h -- Common definitions for X and Windows NT versions of XBoard - * $Id$ + * $Id: common.h,v 2.1 2003/10/27 19:21:00 mann Exp $ * * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. * Enhancements Copyright 1992-95 Free Software Foundation, Inc. @@ -407,6 +407,27 @@ typedef struct { int firstProtocolVersion; int secondProtocolVersion; Boolean showButtonBar; + /* [AS] New properties */ + Boolean firstScoreIsAbsolute; /* If true, engine score is always from white side */ + Boolean secondScoreIsAbsolute; /* If true, engine score is always from white side */ + Boolean saveExtendedInfoInPGN; /* If true, saved PGN games contain extended info */ + Boolean hideThinkingFromHuman; /* If true, program thinking is generated but not displayed in human/computer matches */ + char * liteBackTextureFile; /* Name of texture bitmap for lite squares */ + char * darkBackTextureFile; /* Name of texture bitmap for dark squares */ + int liteBackTextureMode; + int darkBackTextureMode; + char * renderPiecesWithFont; /* Name of font for rendering chess pieces */ + char * fontToPieceTable; /* Map to translate font character to chess pieces */ + int fontBackColorWhite; + int fontForeColorWhite; + int fontBackColorBlack; + int fontForeColorBlack; + int fontPieceSize; /* Size of font relative to square (percentage) */ + int overrideLineGap; /* If >= 0 overrides the lineGap value of the board size properties */ + int adjudicateLossThreshold; /* Adjudicate a two-machine game if both engines agree the score is below this for 6 plies */ + int delayBeforeQuit; + int delayAfterQuit; + char * nameOfDebugFile; #if ZIPPY char *zippyLines; char *zippyPinhead; diff --git a/readme.htm b/readme.htm new file mode 100644 index 0000000..ca59e5c --- /dev/null +++ b/readme.htm @@ -0,0 +1,223 @@ + + + + + +Tinkering with Winboard
+by Alessandro Scotti
+

+Last update: March 22, 2005.
+
+This readme is about some modifications I made to Winboard 4.2.7. Some +will work in Xboard too, while others are for Winboard only. +Regardless, everything here is absolutely experimental and has been +tested very little... so no warranties ok?
+
+All modified sources are included in this archive, the rest can be +downloaded from Tim +Mann's Xboard page. Please feel free to take my changes and use +them as you like, they are released under the GPL.
+
+Game adjudication
+
+User can adjudicate a game between two machines, using the "Action" +menu. Note that this only works if two machines are playing.
+
+Also, it is possible to adjudicate a game automatically with this +parameter:
+
+
/adjudicateLossThreshold=-700
+
+
+if set to a negative value, Winboard will adjudicate a game if a engine +can't get a score above the specified threshold for 3 full moves (6 +plies). Note that both engines must agree on the score value, and also +the game is only adjudicated after the last move from the losing engine.
+
+Adjudication is still under test!
+
+Background textures
+
+Add the following to winboard.ini:
+
+
/liteBackTextureFile="sandstone_w.bmp"
+/darkBackTextureFile="sandstone_b.bmp"
+/liteBackTextureMode=1
+/darkBackTextureMode=1
+
+
+Of course you can choose any file you like for texturing the light and +dark squares, as long as it's a valid BMP (Windows bitmap) file.
+
+Valid texture modes are 1 (default) and 2. In mode 1 the squares are +taken from portions of the texture bitmap and copied without further +processing. In mode 2, squares can also be rotated, mirrored and so on +in order to provide a little more variety to the texture. The +operations are selected at random so the board will look slightly +different every time the program is run.
+
+Note: to "comment out" a filename, put an asterisk in front of it, i.e. +"*sandstone.bmp" will be skipped.
+
+Additionally it is possible to override the size of the "gap" between +the squares, which is otherwise selected automatically. Add this to +winboard.ini:
+
+
/overrideLineGap=2
+
+
+I have added this because textures usually look better with a smaller +or no gap. Any negative value will ignore the override and use the +standard value from Winboard.
+
+The combination of these parameters can produce very interesting +effects, see for example Alex Guerrero's page.
+
+Font-based rendering of chess +pieces
+
+It is possible to use chess fonts to draw pieces, in place of the usual +bitmaps. You have to specify the font name by adding the following to +winboard.ini:
+
+
/renderPiecesWithFont="Chess Leipzig"
+
+
+Chances are the program will automatically recognize the font and +select the proper mapping, i.e. the correspondence between a chess +piece and the corresponding font character. So if the board looks good +you're set and there's nothing else to do, otherwise you'll have to +find the proper mapping and tell it to the program with  this +setting:
+
+
/fontPieceToCharTable="phbrqkojntwl"
+
+
+The piece are in order: white pawn, knight, bishop, rook, queen, king +and black pawn, knight, bishop, rook, queen, king. So the example above +tells the program to use the letter "p" for a white pawn, the letter +"h" for a white knight, the letter "t" for a black rook and so on.
+
+Note: to "comment out" a font name, put an asterisk in front of it, +i.e. "*Chess Merida" will be skipped because of the asterisk.
+
+It is possible to customize the font foreground and background color, +with these settings:
+
+
/fontPieceBackColorWhite=#ffffcc
+/fontPieceForeColorWhite=#402010
+/fontPieceBackColorBlack=#ffffcc
+/fontPieceForeColorBlack=#301008
+
+
+Colors are expressed in RGB notation. If you are not familiar with the +RGB notation  I would suggest to leave them alone until I manage +to update the GUI. In this case, the program will take the board +settings as for the usual piece set.
+
+It is also possible to control the size of the piece with respect to +the square, for example this entry:
+
+
/fontPieceSize=80
+
+
+tells the program to make the pieces about 20% smaller than a square +(i.e. the piece size is 80%). Note that different fonts may require +different values for this parameter. Usually values in the 70-80 range +provide the best values, however the program accepts anything from 50 +to 150.
+
+Font-based pieces are automatically given a "roundish" look. For now, +this option is not mapped to a user-definable setting.
+
+Fast clipboard pasting
+
+Press Ctrl-V to paste a PGN game or a FEN position from the clipboard, +the program will try to autodetect the proper type.
+
+Thread initialization bug
+
+I've tried to fix a bug reported (and fixed) by Anastasios Milikas (of +AICE), where a thread could try to access a not yet initialized +variable. I've used a different approach here, where threads are +started in a "suspended" state and then released only when the variable +has been initialized (this has the advantage of putting all the +required fix code in one place, and the disadvantage of not having been +tested by Anastasios).
+
+Protection from some buffer +overflows
+
+In just a few cases, I've tried to put some guard against buffer +overflows. These are just quick attempts... a lot more work would be +needed to provide some measurable benefits. I hope that bug **353 is +finally fixed now. The buffer overflows were propagated across several +functions so as soon as one was fixed another would crash!
+
+Absolute scores can be converted +to relative
+
+Some engines (e.g. Crafty, Delphi) always report scores from the white +side (i.e. absolute), rather than the engine side (i.e. relative). This +leads to confusion and breaks features such as automatic adjudication. +In order to convert the scores to relative add the following to +winboard.ini:
+
+
/firstScoreAbs=false
+
+
+If true, the score of the first program is absolute and will be negated +when playing black. And similarly:
+
+
/secondScoreAbs=false
+
+
+if true, the score of the second program is absolute and will be +negated when playing black.
+
+Engine search info can be saved +in a PGN file
+
+Add the following to winboard.ini:
+
+
/pgnExtendedInfo=true
+
+
+If true, and the PGN save game option is enabled, each move will be +followed by a comment  containing the engine score and thinking +depth (when available).
+
+Note: can also be set from the General options dialog.
+
+Engine search info can be hidden +in human-computer games
+
+When "show thinking" is disabled, engine thinking is not generated at +all, rather than simply hidden. It is now possible to generate the +think lines (e.g. for logging or saving in the PGN) yet hide them when +the engine is playing against a human player. Add the following to +winboard.ini:
+
+
/hideThinkingFromHuman=true
+
+
+Note: can also be set from the General options dialog.
+
+Asymmetric time controls
+
+Very experimental! You can enter two time controls in the usual dialog, +separated by "/". If so, white will be assigned the first time and +black the second. So for example "0:30/2:00" will give 30 seconds to +white and 2 minutes to black.
+
+Note: for now these times stay with black and white, rather than the +corresponding player.
+
+User interface
+
+Options to "hide thinking from human" and "save extended info in PGN" +now appears in the "General" options dialog.
+
+ + diff --git a/winboard/resource.h b/winboard/resource.h index 8da09ae..1f4411b 100644 --- a/winboard/resource.h +++ b/winboard/resource.h @@ -214,6 +214,9 @@ #define IDM_GeneralOptions 1299 #define IDM_BoardOptions 1300 #define IDM_Fonts 1301 +#define IDM_UserAdjudication_White 1302 +#define IDM_UserAdjudication_Black 1303 +#define IDM_UserAdjudication_Draw 1304 #define PB_King 1307 #define OPT_Bold 1312 #define OPT_Italic 1313 @@ -340,6 +343,8 @@ #define OPT_DefaultFonts 1419 #define OPT_AutoRaiseBoard 1421 #define OPT_ShowButtonBar 1422 +#define OPT_SaveExtPGN 1423 +#define OPT_HideThinkFromHuman 1424 #define IDC_STATIC -1 // Next default values for new objects @@ -348,8 +353,8 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 #define _APS_NEXT_RESOURCE_VALUE 457 -#define _APS_NEXT_COMMAND_VALUE 1302 -#define _APS_NEXT_CONTROL_VALUE 1423 +#define _APS_NEXT_COMMAND_VALUE 1305 +#define _APS_NEXT_CONTROL_VALUE 1425 #define _APS_NEXT_SYMED_VALUE 1404 #endif #endif diff --git a/winboard/wclipbrd.c b/winboard/wclipbrd.c index 79ff2a2..dbb47a7 100644 --- a/winboard/wclipbrd.c +++ b/winboard/wclipbrd.c @@ -1,6 +1,6 @@ /* * wclipbrd.c -- Clipboard routines for WinBoard - * $Id$ + * $Id: wclipbrd.c,v 2.1 2003/10/27 19:21:02 mann Exp $ * * Copyright 2000 Free Software Foundation, Inc. * @@ -194,6 +194,16 @@ CopyTextToClipboard(char *text) return TRUE; } +/* [AS] Reworked paste functions so they can work with strings too */ + +VOID PasteFENFromString( char * fen ) +{ + if (appData.debugMode) { + fprintf(debugFP, "PasteFenFromString(): fen '%s'\n", fen); + } + EditPositionPasteFEN(fen); /* call into backend */ + free(fen); +} VOID @@ -204,42 +214,68 @@ PasteFENFromClipboard() DisplayError("Unable to paste FEN from clipboard.", 0); return; } - if (appData.debugMode) { - fprintf(debugFP, "PasteFenFromClipboard(): fen '%s'\n", fen); - } - EditPositionPasteFEN(fen); /* call into backend */ - free(fen); + PasteFENFromString( fen ); } - -VOID -PasteGameFromClipboard() +VOID PasteGameFromString( char * buf ) { - /* Write the clipboard to a temp file, then let LoadGameFromFile() - * do all the work. */ - char *buf; FILE *f; size_t len; - if (!PasteTextFromClipboard(&buf)) { - return; - } if (!pasteTemp) { pasteTemp = tempnam(NULL, "wbpt"); } f = fopen(pasteTemp, "w"); if (!f) { DisplayError("Unable to create temporary file.", 0); + free(buf); /* [AS] */ return; } len = fwrite(buf, sizeof(char), strlen(buf), f); fclose(f); if (len != strlen(buf)) { DisplayError("Error writing to temporary file.", 0); + free(buf); /* [AS] */ return; } LoadGameFromFile(pasteTemp, 0, "Clipboard", TRUE); + free( buf ); /* [AS] */ +} + + +VOID +PasteGameFromClipboard() +{ + /* Write the clipboard to a temp file, then let LoadGameFromFile() + * do all the work. */ + char *buf; + if (!PasteTextFromClipboard(&buf)) { + return; + } + PasteGameFromString( buf ); } +/* [AS] Try to detect whether the clipboard contains FEN or PGN data */ +VOID PasteGameOrFENFromClipboard() +{ + char *buf; + char *tmp; + + if (!PasteTextFromClipboard(&buf)) { + return; + } + + tmp = buf; + while( *tmp == ' ' || *tmp == '\t' || *tmp == '\r' || *tmp == '\n' ) { + tmp++; + } + + if( *tmp == '[' ) { + PasteGameFromString( buf ); + } + else { + PasteFENFromString( buf ); + } +} int PasteTextFromClipboard(char **text) diff --git a/winboard/wclipbrd.h b/winboard/wclipbrd.h index c575d8a..03c2a56 100644 --- a/winboard/wclipbrd.h +++ b/winboard/wclipbrd.h @@ -1,6 +1,6 @@ /* * wclipbrd.c -- Clipboard routines for WinBoard - * $Id$ + * $Id: wclipbrd.h,v 2.1 2003/10/27 19:21:02 mann Exp $ * * Copyright 2000 Free Software Foundation, Inc. * @@ -30,3 +30,5 @@ VOID PasteGameFromClipboard(); int PasteTextFromClipboard(char **text); VOID DeleteClipboardTempFiles(); + +VOID PasteGameOrFENFromClipboard(); /* [AS] */ diff --git a/winboard/winboard.c b/winboard/winboard.c index 7bd3de0..2ad3bcf 100644 --- a/winboard/winboard.c +++ b/winboard/winboard.c @@ -1,6 +1,6 @@ /* * WinBoard.c -- Windows NT front end to XBoard - * $Id$ + * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $ * * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. * Enhancements Copyright 1992-2001 Free Software Foundation, Inc. @@ -57,6 +57,7 @@ #include #include +#include #include #include #include @@ -83,6 +84,9 @@ #include "wsockerr.h" #include "defaults.h" +int myrandom(void); +void mysrandom(unsigned int seed); + typedef struct { ChessSquare piece; POINT pos; /* window coordinates of current pos */ @@ -140,7 +144,7 @@ char *icsNames; char *firstChessProgramNames; char *secondChessProgramNames; -#define ARG_MAX 20000 +#define ARG_MAX 64*1024 /* [AS] For Roger Brown's very long list! */ #define PALETTESIZE 256 @@ -171,6 +175,18 @@ static int doingSizing = FALSE; static int lastSizing = 0; static int prevStderrPort; +/* [AS] Support for background textures */ +#define BACK_TEXTURE_MODE_DISABLED 0 +#define BACK_TEXTURE_MODE_PLAIN 1 +#define BACK_TEXTURE_MODE_FULL_RANDOM 2 + +static HBITMAP liteBackTexture = NULL; +static HBITMAP darkBackTexture = NULL; +static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN; +static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN; +static int backTextureSquareSize = 0; +static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE]; + #if __GNUC__ && !defined(_winmajor) #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */ #else @@ -557,7 +573,7 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) } InitAppData(lpCmdLine); /* Get run-time parameters */ if (appData.debugMode) { - debugFP = fopen("winboard.debug", "w"); + debugFP = fopen(appData.nameOfDebugFile, "w"); setbuf(debugFP, NULL); } @@ -594,6 +610,29 @@ InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine) InitMenuChecks(); buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS); + /* [AS] Load textures if specified */ + ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) ); + + if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) { + liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + liteBackTextureMode = appData.liteBackTextureMode; + + if (liteBackTexture == NULL && appData.debugMode) { + fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile ); + } + } + + if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) { + darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ); + darkBackTextureMode = appData.darkBackTextureMode; + + if (darkBackTexture == NULL && appData.debugMode) { + fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile ); + } + } + + mysrandom( (unsigned) time(NULL) ); + /* Make a console window if needed */ if (appData.icsActive) { ConsoleCreate(); @@ -1005,14 +1044,35 @@ ArgDescriptor argDescriptors[] = { { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE }, { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE }, { "variant", ArgString, (LPVOID) &appData.variant, FALSE }, - { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, - FALSE }, - { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion, - FALSE }, + { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE }, + { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE }, { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE }, { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE }, { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE }, { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE }, + /* [AS] New features */ + { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, TRUE }, + { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, TRUE }, + { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE }, + { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE }, + { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE }, + { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE }, + { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE }, + { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE }, + { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE }, + { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE }, + { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE }, + { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE }, + { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE }, + { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE }, + { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE }, + { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE }, + { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE }, + { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE }, + { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE }, + { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE }, + { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE }, + { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE }, #ifdef ZIPPY { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE }, { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE }, @@ -1667,6 +1727,30 @@ InitAppData(LPSTR lpCmdLine) appData.firstProtocolVersion = PROTOVER; appData.secondProtocolVersion = PROTOVER; appData.showButtonBar = TRUE; + + /* [AS] New properties (see comments in header file) */ + appData.firstScoreIsAbsolute = FALSE; + appData.secondScoreIsAbsolute = FALSE; + appData.saveExtendedInfoInPGN = FALSE; + appData.hideThinkingFromHuman = FALSE; + appData.liteBackTextureFile = ""; + appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN; + appData.darkBackTextureFile = ""; + appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN; + appData.renderPiecesWithFont = ""; + appData.fontToPieceTable = ""; + appData.fontBackColorWhite = 0; + appData.fontForeColorWhite = 0; + appData.fontBackColorBlack = 0; + appData.fontForeColorBlack = 0; + appData.fontPieceSize = 80; + appData.overrideLineGap = 1; + appData.adjudicateLossThreshold = 0; + appData.delayBeforeQuit = 0; + appData.delayAfterQuit = 0; + appData.nameOfDebugFile = "winboard.debug"; + appData.pgnEventHeader = "Computer Chess Game"; + #ifdef ZIPPY appData.zippyTalk = ZIPPY_TALK; appData.zippyPlay = ZIPPY_PLAY; @@ -1961,6 +2045,431 @@ SaveSettings(char* name) * \*---------------------------------------------------------------------------*/ +/* [AS] Draw square using background texture */ +static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy ) +{ + XFORM x; + + if( mode == 0 ) { + return; /* Should never happen! */ + } + + SetGraphicsMode( dst, GM_ADVANCED ); + + switch( mode ) { + case 1: + /* Identity */ + break; + case 2: + /* X reflection */ + x.eM11 = -1.0; + x.eM12 = 0; + x.eM21 = 0; + x.eM22 = 1.0; + x.eDx = (FLOAT) dw + dx - 1; + x.eDy = 0; + dx = 0; + SetWorldTransform( dst, &x ); + break; + case 3: + /* Y reflection */ + x.eM11 = 1.0; + x.eM12 = 0; + x.eM21 = 0; + x.eM22 = -1.0; + x.eDx = 0; + x.eDy = (FLOAT) dh + dy - 1; + dy = 0; + SetWorldTransform( dst, &x ); + break; + case 4: + /* X/Y flip */ + x.eM11 = 0; + x.eM12 = 1.0; + x.eM21 = 1.0; + x.eM22 = 0; + x.eDx = (FLOAT) dx; + x.eDy = (FLOAT) dy; + dx = 0; + dy = 0; + SetWorldTransform( dst, &x ); + break; + } + + BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY ); + + x.eM11 = 1.0; + x.eM12 = 0; + x.eM21 = 0; + x.eM22 = 1.0; + x.eDx = 0; + x.eDy = 0; + SetWorldTransform( dst, &x ); + + ModifyWorldTransform( dst, 0, MWT_IDENTITY ); +} + +/* [AS] */ +enum { + PM_WP = 0, + PM_WN = 1, + PM_WB = 2, + PM_WR = 3, + PM_WQ = 4, + PM_WK = 5, + PM_BP = 6, + PM_BN = 7, + PM_BB = 8, + PM_BR = 9, + PM_BQ = 10, + PM_BK = 11 +}; + +static HFONT hPieceFont = NULL; +static HBITMAP hPieceMask[12]; +static HBITMAP hPieceFace[12]; +static int fontBitmapSquareSize = 0; +static char pieceToFontChar[12] = { 'p', 'n', 'b', 'r', 'q', 'k', 'o', 'm', 'v', 't', 'w', 'l' }; + +static BOOL SetPieceToFontCharTable( const char * map ) +{ + BOOL result = FALSE; + + if( map != NULL && strlen(map) == 12 ) { + int i; + + for( i=0; i<12; i++ ) { + pieceToFontChar[i] = map[i]; + } + + result = TRUE; + } + + return result; +} + +static void SetPieceBackground( HDC hdc, COLORREF color, int mode ) +{ + HBRUSH hbrush; + BYTE r1 = GetRValue( color ); + BYTE g1 = GetGValue( color ); + BYTE b1 = GetBValue( color ); + BYTE r2 = r1 / 2; + BYTE g2 = g1 / 2; + BYTE b2 = b1 / 2; + RECT rc; + + /* Create a uniform background first */ + hbrush = CreateSolidBrush( color ); + SetRect( &rc, 0, 0, squareSize, squareSize ); + FillRect( hdc, &rc, hbrush ); + DeleteObject( hbrush ); + + if( mode == 1 ) { + /* Vertical gradient, good for pawn, knight and rook, less for queen and king */ + int steps = squareSize / 2; + int i; + + for( i=0; i= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) { + backColor = appData.fontBackColorBlack; + foreColor = appData.fontForeColorBlack; + } + + /* Mask */ + hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize ); + + hbm_old = SelectObject( hdc, hbm ); + + rc.left = 0; + rc.top = 0; + rc.right = squareSize; + rc.bottom = squareSize; + + /* Step 1: background is now black */ + FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) ); + + GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz ); + + pt.x = (squareSize - sz.cx) / 2; + pt.y = (squareSize - sz.cy) / 2; + + SetBkMode( hdc, TRANSPARENT ); + SetTextColor( hdc, chroma ); + /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */ + TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 ); + + SelectObject( hdc, GetStockObject(WHITE_BRUSH) ); + /* Step 3: the area outside the piece is filled with white */ + FloodFill( hdc, 0, 0, chroma ); + SelectObject( hdc, GetStockObject(BLACK_BRUSH) ); + /* + Step 4: this is the tricky part, the area inside the piece is filled with black, + but if the start point is not inside the piece we're lost! + There should be a better way to do this... if we could create a region or path + from the fill operation we would be fine for example. + */ + FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) ); + + SetTextColor( hdc, 0 ); + /* + Step 5: some fonts have "disconnected" areas that are skipped by the fill: + draw the piece again in black for safety. + */ + TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 ); + + SelectObject( hdc, hbm_old ); + + if( hPieceMask[index] != NULL ) { + DeleteObject( hPieceMask[index] ); + } + + hPieceMask[index] = hbm; + + /* Face */ + hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize ); + + SelectObject( hdc, hbm ); + + { + HDC dc1 = CreateCompatibleDC( hdc_window ); + HDC dc2 = CreateCompatibleDC( hdc_window ); + HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize ); + + SelectObject( dc1, hPieceMask[index] ); + SelectObject( dc2, bm2 ); + FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) ); + BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT ); + + /* + Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves + the piece background and deletes (makes transparent) the rest. + Thanks to that mask, we are free to paint the background with the greates + freedom, as we'll be able to mask off the unwanted parts when finished. + We use this, to make gradients and give the pieces a "roundish" look. + */ + SetPieceBackground( hdc, backColor, 2 ); + BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND ); + + DeleteDC( dc2 ); + DeleteDC( dc1 ); + DeleteObject( bm2 ); + } + + SetTextColor( hdc, foreColor ); + TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 ); + + SelectObject( hdc, hbm_old ); + + hPieceFace[index] = hbm; +} + +static int TranslatePieceToFontPiece( int piece ) +{ + switch( piece ) { + case BlackPawn: + return PM_BP; + case BlackKnight: + return PM_BN; + case BlackBishop: + return PM_BB; + case BlackRook: + return PM_BR; + case BlackQueen: + return PM_BQ; + case BlackKing: + return PM_BK; + case WhitePawn: + return PM_WP; + case WhiteKnight: + return PM_WN; + case WhiteBishop: + return PM_WB; + case WhiteRook: + return PM_WR; + case WhiteQueen: + return PM_WQ; + case WhiteKing: + return PM_WK; + } + + return 0; +} + +void CreatePiecesFromFont() +{ + LOGFONT lf; + HDC hdc_window = NULL; + HDC hdc = NULL; + HFONT hfont_old; + int fontHeight; + int i; + + if( fontBitmapSquareSize < 0 ) { + /* Something went seriously wrong in the past: do not try to recreate fonts! */ + return; + } + + if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) { + fontBitmapSquareSize = -1; + return; + } + + if( fontBitmapSquareSize != squareSize ) { + hdc_window = GetDC( hwndMain ); + hdc = CreateCompatibleDC( hdc_window ); + + if( hPieceFont != NULL ) { + DeleteObject( hPieceFont ); + } + else { + for( i=0; i<12; i++ ) { + hPieceMask[i] = NULL; + } + } + + fontHeight = 75; + + if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) { + fontHeight = appData.fontPieceSize; + } + + fontHeight = (fontHeight * squareSize) / 100; + + lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 ); + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + lf.lfWeight = FW_NORMAL; + lf.lfItalic = 0; + lf.lfUnderline = 0; + lf.lfStrikeOut = 0; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = PROOF_QUALITY; + lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) ); + lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0'; + + hPieceFont = CreateFontIndirect( &lf ); + + if( hPieceFont == NULL ) { + fontBitmapSquareSize = -2; + } + else { + /* Setup font-to-piece character table */ + if( ! SetPieceToFontCharTable(appData.fontToPieceTable) ) { + /* No (or wrong) global settings, try to detect the font */ + if( strstr(lf.lfFaceName,"Alpha") != NULL ) { + /* Alpha */ + SetPieceToFontCharTable("phbrqkojntwl"); + } + else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) { + /* DiagramTT* family */ + SetPieceToFontCharTable("PNLRQKpnlrqk"); + } + else { + /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */ + SetPieceToFontCharTable("pnbrqkomvtwl"); + } + } + + /* Create bitmaps */ + hfont_old = SelectObject( hdc, hPieceFont ); + + CreatePieceMaskFromFont( hdc_window, hdc, PM_WP ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_WN ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_WB ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_WR ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_WK ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_BP ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_BN ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_BB ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_BR ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ ); + CreatePieceMaskFromFont( hdc_window, hdc, PM_BK ); + + SelectObject( hdc, hfont_old ); + + fontBitmapSquareSize = squareSize; + } + } + + if( hdc != NULL ) { + DeleteDC( hdc ); + } + + if( hdc_window != NULL ) { + ReleaseDC( hwndMain, hdc_window ); + } +} + HBITMAP DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix) { @@ -2032,13 +2541,24 @@ InitDrawingColors() whitePieceBrush = CreateSolidBrush(whitePieceColor); blackPieceBrush = CreateSolidBrush(blackPieceColor); iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND)); + + /* [AS] Force rendering of the font-based pieces */ + if( fontBitmapSquareSize > 0 ) { + fontBitmapSquareSize = 0; + } } int BoardWidth(int boardSize) { - return (BOARD_SIZE + 1) * sizeInfo[boardSize].lineGap + + int lineGap = sizeInfo[boardSize].lineGap; + + if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) { + lineGap = appData.overrideLineGap; + } + + return (BOARD_SIZE + 1) * lineGap + BOARD_SIZE * sizeInfo[boardSize].squareSize; } @@ -2084,6 +2604,10 @@ InitDrawingSizes(BoardSize boardSize, int flags) squareSize = sizeInfo[boardSize].squareSize; lineGap = sizeInfo[boardSize].lineGap; + if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) { + lineGap = appData.overrideLineGap; + } + if (tinyLayout != oldTinyLayout) { long style = GetWindowLong(hwndMain, GWL_STYLE); if (tinyLayout) { @@ -2430,6 +2954,36 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, if (appData.blindfold) return; + /* [AS] Use font-based pieces if needed */ + if( fontBitmapSquareSize >= 0 && squareSize > 32 ) { + /* Create piece bitmaps, or do nothing if piece set is up to data */ + CreatePiecesFromFont(); + + if( fontBitmapSquareSize == squareSize ) { + int index = TranslatePieceToFontPiece( piece ); + + SelectObject( tmphdc, hPieceMask[ index ] ); + + BitBlt( hdc, + x, y, + squareSize, squareSize, + tmphdc, + 0, 0, + SRCAND ); + + SelectObject( tmphdc, hPieceFace[ index ] ); + + BitBlt( hdc, + x, y, + squareSize, squareSize, + tmphdc, + 0, 0, + SRCPAINT ); + + return; + } + } + if (appData.monoMode) { SelectObject(tmphdc, PieceBitmap(piece, color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE)); @@ -2477,12 +3031,93 @@ DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, } } +/* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */ +int GetBackTextureMode( int algo ) +{ + int result = BACK_TEXTURE_MODE_DISABLED; + + switch( algo ) + { + case BACK_TEXTURE_MODE_PLAIN: + result = 1; /* Always use identity map */ + break; + case BACK_TEXTURE_MODE_FULL_RANDOM: + result = 1 + (myrandom() % 3); /* Pick a transformation at random */ + break; + } + + return result; +} + +/* + [AS] Compute and save texture drawing info, otherwise we may not be able + to handle redraws cleanly (as random numbers would always be different). +*/ +VOID RebuildTextureSquareInfo() +{ + BITMAP bi; + int lite_w = 0; + int lite_h = 0; + int dark_w = 0; + int dark_h = 0; + int row; + int col; + + ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) ); + + if( liteBackTexture != NULL ) { + if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) { + lite_w = bi.bmWidth; + lite_h = bi.bmHeight; + } + } + + if( darkBackTexture != NULL ) { + if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) { + dark_w = bi.bmWidth; + dark_h = bi.bmHeight; + } + } + + for( row=0; row= squareSize && lite_h >= squareSize ) { + backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_SIZE; + backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_SIZE; + backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode); + } + } + else { + /* Dark square */ + if( dark_w >= squareSize && dark_h >= squareSize ) { + backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_SIZE; + backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_SIZE; + backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode); + } + } + } + } +} + VOID DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc) { int row, column, x, y, square_color, piece_color; ChessSquare piece; HBRUSH oldBrush; + HDC texture_hdc = NULL; + + /* [AS] Initialize background textures if needed */ + if( liteBackTexture != NULL || darkBackTexture != NULL ) { + if( backTextureSquareSize != squareSize ) { + backTextureSquareSize = squareSize; + RebuildTextureSquareInfo(); + } + + texture_hdc = CreateCompatibleDC( hdc ); + } for (row = 0; row < BOARD_SIZE; row++) { for (column = 0; column < BOARD_SIZE; column++) { @@ -2501,7 +3136,26 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc) } else { DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc); } - } else { + } + else if( backTextureSquareInfo[row][column].mode > 0 ) { + /* [AS] Draw the square using a texture bitmap */ + HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture ); + + DrawTile( x, y, + squareSize, squareSize, + hdc, + texture_hdc, + backTextureSquareInfo[row][column].mode, + backTextureSquareInfo[row][column].x, + backTextureSquareInfo[row][column].y ); + + SelectObject( texture_hdc, hbm ); + + if (piece != EmptySquare) { + DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc); + } + } + else { oldBrush = SelectObject(hdc, square_color ? lightSquareBrush : darkSquareBrush); BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY); @@ -2511,6 +3165,10 @@ DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc) } } } + + if( texture_hdc != NULL ) { + DeleteDC( texture_hdc ); + } } #define MAX_CLIPS 200 /* more than enough */ @@ -3559,6 +4217,24 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) PasteGameFromClipboard(); break; + /* [AS] Autodetect FEN or PGN data */ + case IDM_Paste: + PasteGameOrFENFromClipboard(); + break; + + /* [AS] User adjudication */ + case IDM_UserAdjudication_White: + UserAdjudicationEvent( +1 ); + break; + + case IDM_UserAdjudication_Black: + UserAdjudicationEvent( -1 ); + break; + + case IDM_UserAdjudication_Draw: + UserAdjudicationEvent( 0 ); + break; + case IDM_CopyPosition: CopyFENToClipboard(); break; @@ -3833,7 +4509,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) char dir[MSG_SIZ]; GetCurrentDirectory(MSG_SIZ, dir); SetCurrentDirectory(installDir); - debugFP = fopen("WinBoard.debug", "w"); + debugFP = fopen(appData.nameOfDebugFile, "w"); SetCurrentDirectory(dir); setbuf(debugFP, NULL); } else { @@ -4620,13 +5296,17 @@ StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0); SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf); } - if (chessProgram) { - CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED); - } else if (appData.icsActive) { + + if (appData.icsActive) { CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED); - } else if (appData.noChessProgram) { + } + else if (appData.noChessProgram) { CheckDlgButton(hDlg, OPT_View, BST_CHECKED); } + else { + CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED); + } + SetStartupDialogEnables(hDlg); return TRUE; @@ -5827,6 +6507,28 @@ DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount, return err; } +/* [AS] If input is line by line and a line exceed the buffer size, force an error */ +void CheckForInputBufferFull( InputSource * is ) +{ + if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) { + /* Look for end of line */ + char * p = is->buf; + + while( p < is->next && *p != '\n' ) { + p++; + } + + if( p >= is->next ) { + if (appData.debugMode) { + fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id ); + } + + is->error = ERROR_BROKEN_PIPE; /* [AS] Just a non-successful code! */ + is->count = (DWORD) -2; + is->next = is->buf; + } + } +} DWORD InputThread(LPVOID arg) @@ -5851,6 +6553,9 @@ InputThread(LPVOID arg) is->count = (DWORD) -1; } } + + CheckForInputBufferFull( is ); + SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is); if (is->count <= 0) break; /* Quit on EOF or error */ } @@ -5905,6 +6610,9 @@ NonOvlInputThread(LPVOID arg) is->count = (DWORD) -1; } } + + CheckForInputBufferFull( is ); + SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is); if (is->count < 0) break; /* Quit on error */ } @@ -5953,12 +6661,14 @@ InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) p = q; } } + /* Move any partial line to the start of the buffer */ q = is->buf; while (p < is->next) { *q++ = *p++; } is->next = q; + if (is->error != NO_ERROR || is->count == 0) { /* Notify backend of the error. Note: If there was a partial line at the end, it is not flushed through. */ @@ -6354,10 +7064,8 @@ DisplayMessage(char *str1, char *str2) VOID DisplayError(char *str, int error) { - FARPROC lpProc; char buf[MSG_SIZ*2], buf2[MSG_SIZ]; int len; - char *p, *q; if (error == 0) { strcpy(buf, str); @@ -6958,6 +7666,27 @@ DestroyChildProcess(ProcRef pr, int/*boolean*/ signal) we could arrange for this even though neither WinBoard nor the chess program uses a console for stdio? */ /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/ + + /* [AS] Special termination modes for misbehaving programs... */ + if( signal == 9 ) { + if ( appData.debugMode) { + fprintf( debugFP, "Terminating process %u\n", cp->pid ); + } + + TerminateProcess( cp->hProcess, 0 ); + } + else if( signal == 10 ) { + DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most + + if( dw != WAIT_OBJECT_0 ) { + if ( appData.debugMode) { + fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid ); + } + + TerminateProcess( cp->hProcess, 0 ); + } + } + CloseHandle(cp->hProcess); break; @@ -7344,7 +8073,7 @@ InputSourceRef AddInputSource(ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure) { - InputSource *is, *is2; + InputSource *is, *is2 = NULL; ChildProc *cp = (ChildProc *) pr; is = (InputSource *) calloc(1, sizeof(InputSource)); @@ -7358,13 +8087,18 @@ AddInputSource(ProcRef pr, int lineByLine, consoleInputSource = is; } else { is->kind = cp->kind; + /* + [AS] Try to avoid a race condition if the thread is given control too early: + we create all threads suspended to that the is->hThread variable can be + safely assigned, then let the threads start with ResumeThread. + */ switch (cp->kind) { case CPReal: is->hFile = cp->hFrom; cp->hFrom = NULL; /* now owned by InputThread */ is->hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread, - (LPVOID) is, 0, &is->id); + (LPVOID) is, CREATE_SUSPENDED, &is->id); break; case CPComm: @@ -7372,14 +8106,14 @@ AddInputSource(ProcRef pr, int lineByLine, cp->hFrom = NULL; /* now owned by InputThread */ is->hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread, - (LPVOID) is, 0, &is->id); + (LPVOID) is, CREATE_SUSPENDED, &is->id); break; case CPSock: is->sock = cp->sock; is->hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread, - (LPVOID) is, 0, &is->id); + (LPVOID) is, CREATE_SUSPENDED, &is->id); break; case CPRcmd: @@ -7391,13 +8125,22 @@ AddInputSource(ProcRef pr, int lineByLine, is2->second = is2; is->hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread, - (LPVOID) is, 0, &is->id); + (LPVOID) is, CREATE_SUSPENDED, &is->id); is2->hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread, - (LPVOID) is2, 0, &is2->id); + (LPVOID) is2, CREATE_SUSPENDED, &is2->id); break; } + + if( is->hThread != NULL ) { + ResumeThread( is->hThread ); } + + if( is2 != NULL && is2->hThread != NULL ) { + ResumeThread( is2->hThread ); + } + } + return (InputSourceRef) is; } diff --git a/winboard/winboard.ini b/winboard/winboard.ini new file mode 100644 index 0000000..5e2eb0a --- /dev/null +++ b/winboard/winboard.ini @@ -0,0 +1,266 @@ +; +; WinBoard 4.2.7 Save Settings file +; +; You can edit the values of options that are already set in this file, +; but if you add other options, the next Save Settings will not save them. +; Use a shortcut, an @indirection file, or a .bat file instead. +; +/whitePieceColor=#ffffcc +/blackPieceColor=#202020 +/lightSquareColor=#c8c365 +/darkSquareColor=#77a26d +/highlightSquareColor=#ffff00 +/premoveHighlightColor=#ff0000 +/movesPerSession=40 +/timeDelay=1 +/timeControl="5" +/timeIncrement=-1 +/saveGameFile="" +/autoSaveGames=false +/monoMode=false +/showCoords=false +/showThinking=false +/ponderNextMove=true +/periodicUpdates=true +/popupExitMessage=true +/popupMoveErrors=false +/size=tiny /clockFont="Arial:9 b" +/size=teeny /clockFont="Arial:9 b" +/size=dinky /clockFont="Arial:10 b" +/size=petite /clockFont="Arial:10 b" +/size=slim /clockFont="Arial:12 b" +/size=small /clockFont="Arial:14 b" +/size=mediocre /clockFont="Arial:14 b" +/size=middling /clockFont="Arial:14 b" +/size=average /clockFont="Arial:15 b" +/size=moderate /clockFont="Arial:16 b" +/size=medium /clockFont="Arial:16 b" +/size=bulky /clockFont="Arial:17 b" +/size=large /clockFont="Arial:19 b" +/size=big /clockFont="Arial:20 b" +/size=huge /clockFont="Arial:21 b" +/size=giant /clockFont="Arial:22 b" +/size=colossal /clockFont="Arial:23 b" +/size=titanic /clockFont="Arial:24 b" +/size=tiny /messageFont="Small Fonts:6" +/size=teeny /messageFont="Small Fonts:6" +/size=dinky /messageFont="Small Fonts:7" +/size=petite /messageFont="Small Fonts:7" +/size=slim /messageFont="Arial:8 b" +/size=small /messageFont="Arial:9 b" +/size=mediocre /messageFont="Arial:9 b" +/size=middling /messageFont="Arial:9 b" +/size=average /messageFont="Arial:10 b" +/size=moderate /messageFont="Arial:10 b" +/size=medium /messageFont="Arial:10 b" +/size=bulky /messageFont="Arial:10 b" +/size=large /messageFont="Arial:10 b" +/size=big /messageFont="Arial:11 b" +/size=huge /messageFont="Arial:11 b" +/size=giant /messageFont="Arial:11 b" +/size=colossal /messageFont="Arial:12 b" +/size=titanic /messageFont="Arial:12 b" +/size=tiny /coordFont="Small Fonts:4" +/size=teeny /coordFont="Small Fonts:4" +/size=dinky /coordFont="Small Fonts:5" +/size=petite /coordFont="Small Fonts:5" +/size=slim /coordFont="Small Fonts:6" +/size=small /coordFont="Small Fonts:7" +/size=mediocre /coordFont="Small Fonts:7" +/size=middling /coordFont="Small Fonts:7" +/size=average /coordFont="Arial:7 b" +/size=moderate /coordFont="Arial:7 b" +/size=medium /coordFont="Arial:7 b" +/size=bulky /coordFont="Arial:7 b" +/size=large /coordFont="Arial:7 b" +/size=big /coordFont="Arial:8 b" +/size=huge /coordFont="Arial:8 b" +/size=giant /coordFont="Arial:8 b" +/size=colossal /coordFont="Arial:9 b" +/size=titanic /coordFont="Arial:9 b" +/size=tiny /tagsFont="Courier New:8" +/size=teeny /tagsFont="Courier New:8" +/size=dinky /tagsFont="Courier New:8" +/size=petite /tagsFont="Courier New:8" +/size=slim /tagsFont="Courier New:8" +/size=small /tagsFont="Courier New:8" +/size=mediocre /tagsFont="Courier New:8" +/size=middling /tagsFont="Courier New:8" +/size=average /tagsFont="Courier New:8" +/size=moderate /tagsFont="Courier New:8" +/size=medium /tagsFont="Courier New:8" +/size=bulky /tagsFont="Courier New:8" +/size=large /tagsFont="Courier New:8" +/size=big /tagsFont="Courier New:8" +/size=huge /tagsFont="Courier New:8" +/size=giant /tagsFont="Courier New:8" +/size=colossal /tagsFont="Courier New:8" +/size=titanic /tagsFont="Courier New:8" +/size=tiny /commentFont="Arial:9" +/size=teeny /commentFont="Arial:9" +/size=dinky /commentFont="Arial:9" +/size=petite /commentFont="Arial:9" +/size=slim /commentFont="Arial:9" +/size=small /commentFont="Arial:9" +/size=mediocre /commentFont="Arial:9" +/size=middling /commentFont="Arial:9" +/size=average /commentFont="Arial:9" +/size=moderate /commentFont="Arial:9" +/size=medium /commentFont="Arial:9" +/size=bulky /commentFont="Arial:9" +/size=large /commentFont="Arial:9" +/size=big /commentFont="Arial:9" +/size=huge /commentFont="Arial:9" +/size=giant /commentFont="Arial:9" +/size=colossal /commentFont="Arial:9" +/size=titanic /commentFont="Arial:9" +/size=tiny /icsFont="Courier New:8" +/size=teeny /icsFont="Courier New:8" +/size=dinky /icsFont="Courier New:8" +/size=petite /icsFont="Courier New:8" +/size=slim /icsFont="Courier New:8" +/size=small /icsFont="Courier New:8" +/size=mediocre /icsFont="Courier New:8" +/size=middling /icsFont="Courier New:8" +/size=average /icsFont="Courier New:8" +/size=moderate /icsFont="Courier New:8" +/size=medium /icsFont="Courier New:8" +/size=bulky /icsFont="Courier New:8" +/size=large /icsFont="Courier New:8" +/size=big /icsFont="Courier New:8" +/size=huge /icsFont="Courier New:8" +/size=giant /icsFont="Courier New:8" +/size=colossal /icsFont="Courier New:8" +/size=titanic /icsFont="Courier New:8" +/boardSize=giant +/alwaysOnTop=false +/autoCallFlag=false +/autoComment=false +/autoObserve=false +/autoFlipView=true +/autoRaiseBoard=true +/alwaysPromoteToQueen=false +/oldSaveStyle=false +/quietPlay=false +/getMoveList=true +/testLegality=true +/premove=true +/premoveWhite=false +/premoveWhiteText="" +/premoveBlack=false +/premoveBlackText="" +/icsAlarm=true +/icsAlarmTime=5000 +/animateMoving=true +/animateSpeed=10 +/animateDragging=true +/blindfold=false +/highlightLastMove=true +/highlightDragging=false +/colorizeMessages=true +/colorShout="#209000" +/colorSShout="b #289808" +/colorChannel1="#2020e0" +/colorChannel="b #4040ff" +/colorKibitz="b #ff00ff" +/colorTell="b #ff0000" +/colorChallenge="bi #ff0000" +/colorRequest="bi #ff0000" +/colorSeek="#980808" +/colorNormal="#000000" +/colorBackground=#ffffff +/soundShout="" +/soundSShout="" +/soundChannel1="" +/soundChannel="" +/soundKibitz="" +/soundTell="" +/soundChallenge="" +/soundRequest="" +/soundSeek="" +/soundMove="" +/soundBell="$" +/soundIcsWin="" +/soundIcsLoss="" +/soundIcsDraw="" +/soundIcsUnfinished="" +/soundIcsAlarm="" +/comPortSettings=9600,7,Space,1,None +/x=0 +/y=2 +/icsX=-2147483648 +/icsY=-2147483648 +/icsW=-2147483648 +/icsH=-2147483648 +/analysisX=-2147483648 +/analysisY=-2147483648 +/analysisW=-2147483648 +/analysisH=-2147483648 +/commentX=-2147483648 +/commentY=-2147483648 +/commentW=-2147483648 +/commentH=-2147483648 +/tagsX=-2147483648 +/tagsY=-2147483648 +/tagsW=-2147483648 +/tagsH=-2147483648 +/gameListX=-2147483648 +/gameListY=-2147483648 +/gameListW=-2147483648 +/gameListH=-2147483648 +/saveSettingsOnExit=true +/icsMenu={- +&Who,who,0,1 +Playe&rs,players,0,1 +&Games,games,0,1 +&Sought,sought,0,1 +|&Tell (name),tell,1,0 +M&essage (name),message,1,0 +- +&Finger (name),finger,1,1 +&Vars (name),vars,1,1 +&Observe (name),observe,1,1 +&Match (name),match,1,1 +Pl&ay (name),play,1,1 +} +/icsNames={chessclub.com /icsport=5000 /icshelper=timestamp +freechess.org /icsport=5000 /icshelper=timeseal +global.chessparlor.com /icsport=6000 /icshelper=timeseal +chessanytime.com /icsport=5000 +chess.net /icsport=5000 +zics.org /icsport=5000 +jogo.cex.org.br /icsport=5000 +ajedrez.cec.uchile.cl /icsport=5000 +fly.cc.fer.hr /icsport=7890 +freechess.nl /icsport=5000 /icshelper=timeseal +jeu.echecs.com /icsport=5000 +chess.unix-ag.uni-kl.de /icsport=5000 /icshelper=timeseal +chess.mds.mdh.se /icsport=5000 +} +/firstChessProgramNames={GNUChess +"GNUChes5 xboard" +} +/secondChessProgramNames={GNUChess +"GNUChes5 xboard" +} +/showButtonBar=true +/firstScoreAbs=false +/secondScoreAbs=false +/pgnExtendedInfo=false +/hideThinkingFromHuman=false +/liteBackTextureFile="" +/darkBackTextureFile="" +/liteBackTextureMode=1 +/darkBackTextureMode=1 +/renderPiecesWithFont="" +/fontPieceToCharTable="" +/fontPieceBackColorWhite=#000000 +/fontPieceForeColorWhite=#000000 +/fontPieceBackColorBlack=#000000 +/fontPieceForeColorBlack=#000000 +/fontPieceSize=80 +/overrideLineGap=1 +/adjudicateLossThreshold=0 +/delayBeforeQuit=0 +/delayAfterQuit=0 +/pgnEventHeader="Computer Chess Game" diff --git a/winboard/winboard.rc b/winboard/winboard.rc index fa51d89..1908a1a 100644 --- a/winboard/winboard.rc +++ b/winboard/winboard.rc @@ -36,11 +36,7 @@ CAPTION "About WinBoard" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,131,47,32,14,WS_GROUP -#if __GNUC__ - ICON icon_white,-1,3,6,20,20,0 -#else - ICON "icon_white",-1,3,6,20,20,0 -#endif + ICON "icon_white",-1,3,6,20,20 LTEXT "Chessboard for Windows",400,25,15,121,8 LTEXT "Copyright 1991 Digital Equipment Corporation",201,6,34, 149,8 @@ -50,7 +46,7 @@ BEGIN LTEXT "WinBoard 0.0.0",ABOUTBOX_Version,25,5,142,8 END -DLG_TimeControl DIALOG DISCARDABLE 6, 18, 147, 113 +DLG_TimeControl DIALOG DISCARDABLE 6, 18, 165, 114 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Time Control" FONT 8, "MS Sans Serif" @@ -61,15 +57,15 @@ BEGIN BS_AUTORADIOBUTTON | WS_TABSTOP,6,42,107,10 EDITTEXT OPT_TCMoves,14,20,22,12,ES_AUTOHSCROLL | WS_GROUP LTEXT "moves in",OPT_TCtext1,40,22,30,8,NOT WS_GROUP - EDITTEXT OPT_TCTime,74,20,32,12,ES_AUTOHSCROLL - LTEXT "minutes",OPT_TCtext2,111,22,26,8,NOT WS_GROUP + EDITTEXT OPT_TCTime,74,20,50,12,ES_AUTOHSCROLL + LTEXT "minutes",OPT_TCtext2,129,22,26,8,NOT WS_GROUP EDITTEXT OPT_TCTime2,14,56,32,12,ES_AUTOHSCROLL | WS_GROUP LTEXT "minutes initially,",405,51,57,73,8,NOT WS_GROUP LTEXT "plus",406,19,74,15,8,NOT WS_GROUP EDITTEXT OPT_TCInc,37,72,32,12,ES_AUTOHSCROLL LTEXT "seconds per move",408,74,74,67,8,NOT WS_GROUP - PUSHBUTTON "OK",IDOK,32,95,40,14,WS_GROUP - PUSHBUTTON "Cancel",IDCANCEL,88,95,40,14 + PUSHBUTTON "OK",IDOK,34,95,40,14,WS_GROUP + PUSHBUTTON "Cancel",IDCANCEL,90,95,40,14 END DLG_LoadOptions DIALOG DISCARDABLE 10, 18, 144, 55 @@ -238,20 +234,16 @@ WBCONSOLE DIALOG DISCARDABLE 0, 0, 335, 133 STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "ICS Interaction" -#if __GNUC__ -CLASS WBConsole -#else CLASS "WBConsole" -#endif FONT 8, "Courier New" BEGIN CONTROL "",OPT_ConsoleText,"RICHEDIT",ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL | ES_READONLY | ES_NUMBER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,0,0,335,119 - CONTROL "",OPT_ConsoleInput,"RICHEDIT",ES_AUTOHSCROLL | - ES_AUTOVSCROLL | ES_MULTILINE | - ES_NOHIDESEL | ES_NUMBER | WS_BORDER | - WS_TABSTOP,0,120,335,13,WS_EX_TRANSPARENT + CONTROL "",OPT_ConsoleInput,"RICHEDIT",ES_MULTILINE | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_NOHIDESEL | + ES_NUMBER | WS_BORDER | WS_TABSTOP,0,120,335,13, + WS_EX_TRANSPARENT END DLG_Analysis DIALOG DISCARDABLE 0, 0, 294, 62 @@ -278,7 +270,7 @@ END DLG_Colorize DIALOGEX 0, 0, 183, 52 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ICS Interaction Colors" -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN PUSHBUTTON "&Choose Color...",OPT_ChooseColor,15,29,51,14,WS_GROUP CONTROL "&Bold",OPT_Bold,"Button",BS_AUTOCHECKBOX | WS_GROUP | @@ -336,12 +328,7 @@ BEGIN END DLG_IndexNumber DIALOG DISCARDABLE 0, 0, 236, 18 -#if __GNUC__ -STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | - NOT WS_POPUP | NOT WS_BORDER | NOT WS_SYSMENU -#else STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS -#endif FONT 8, "MS Sans Serif" BEGIN LTEXT "Inde&x number:",IDC_STATIC,5,2,46,8 @@ -384,7 +371,7 @@ BEGIN LTEXT "Event:",IDC_STATIC,19,9,26,9 END -DLG_GeneralOptions DIALOG DISCARDABLE 0, 0, 271, 135 +DLG_GeneralOptions DIALOG DISCARDABLE 0, 0, 271, 150 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "General Options" FONT 8, "MS Sans Serif" @@ -409,6 +396,8 @@ BEGIN WS_TABSTOP,16,104,79,10 CONTROL "&Highlight Dragging",OPT_HighlightDragging,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,16,118,79,10 + CONTROL "Extended PGN Info",OPT_SaveExtPGN,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,132,79,10 CONTROL "Highlight Last &Move",OPT_HighlightLastMove,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,109,6,79,10 CONTROL "Periodic &Updates",OPT_PeriodicUpdates,"Button", @@ -427,12 +416,14 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,109,104,79,10 CONTROL "Test &Legality",OPT_TestLegality,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,109,118,79,10 + CONTROL "Hide Thinking From Human",OPT_HideThinkFromHuman,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,109,132,102,10 END DLG_IcsOptions DIALOGEX 0, 0, 318, 271 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ICS Options" -FONT 8, "MS Sans Serif" +FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN DEFPUSHBUTTON "OK",IDOK,88,250,60,15 PUSHBUTTON "Cancel",IDCANCEL,168,250,60,15 @@ -638,7 +629,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 264 TOPMARGIN, 7 - BOTTOMMARGIN, 128 + BOTTOMMARGIN, 143 END DLG_IcsOptions, DIALOG @@ -744,6 +735,10 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Stop &Observing\tF10", IDM_StopObserving MENUITEM "Stop E&xamining\tF11", IDM_StopExamining + MENUITEM SEPARATOR + MENUITEM "Adjudicate to White", IDM_UserAdjudication_White + MENUITEM "Adjudicate to Black", IDM_UserAdjudication_Black + MENUITEM "Adjudicate Draw", IDM_UserAdjudication_Draw END POPUP "&Step" BEGIN @@ -902,11 +897,10 @@ BEGIN "1", IDM_DirectCommand1, VIRTKEY, ALT, NOINVERT "2", IDM_DirectCommand2, VIRTKEY, ALT, NOINVERT "C", IDM_CopyGame, VIRTKEY, ALT, NOINVERT - "C", IDM_CopyPosition, VIRTKEY, SHIFT, ALT, - NOINVERT + "C", IDM_CopyPosition, VIRTKEY, SHIFT, ALT, NOINVERT + "V", IDM_Paste, VIRTKEY, CONTROL, NOINVERT "V", IDM_PasteGame, VIRTKEY, ALT, NOINVERT - "V", IDM_PastePosition, VIRTKEY, SHIFT, ALT, - NOINVERT + "V", IDM_PastePosition, VIRTKEY, SHIFT, ALT, NOINVERT VK_DELETE, IDM_RetractMove, VIRTKEY, ALT, NOINVERT VK_DOWN, IDM_ToEnd, VIRTKEY, ALT, NOINVERT VK_END, IDM_TruncateGame, VIRTKEY, ALT, NOINVERT @@ -1353,7 +1347,6 @@ SSHOUT WAVE DISCARDABLE "..\\sounds\\sshout.wav" TELL WAVE DISCARDABLE "..\\sounds\\tell.wav" UNFINISHED WAVE DISCARDABLE "..\\sounds\\unfinished.wav" WIN WAVE DISCARDABLE "..\\sounds\\win.wav" - #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/winboard/woptions.c b/winboard/woptions.c index 3308f2d..d568cee 100644 --- a/winboard/woptions.c +++ b/winboard/woptions.c @@ -1,6 +1,6 @@ /* * woptions.c -- Options dialog box routines for WinBoard - * $Id$ + * $Id: woptions.c,v 2.1 2003/10/27 19:21:02 mann Exp $ * * Copyright 2000 Free Software Foundation, Inc. * @@ -167,6 +167,8 @@ GeneralOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) CHECK_BOX(OPT_ShowCoordinates, appData.showCoords); CHECK_BOX(OPT_ShowThinking, appData.showThinking); CHECK_BOX(OPT_TestLegality, appData.testLegality); + CHECK_BOX(OPT_HideThinkFromHuman, appData.hideThinkingFromHuman); + CHECK_BOX(OPT_SaveExtPGN, appData.saveExtendedInfoInPGN); #undef CHECK_BOX @@ -208,6 +210,8 @@ GeneralOptionsDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) appData.showCoords = IS_CHECKED(OPT_ShowCoordinates); ShowThinkingEvent( IS_CHECKED(OPT_ShowThinking)); appData.testLegality = IS_CHECKED(OPT_TestLegality); + appData.hideThinkingFromHuman= IS_CHECKED(OPT_HideThinkFromHuman); + appData.saveExtendedInfoInPGN= IS_CHECKED(OPT_SaveExtPGN); #undef IS_CHECKED