summaryrefslogtreecommitdiffstats
path: root/knights/match.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-17 01:24:36 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-17 01:24:36 +0000
commita8c9924456e5335c964e4e55b2dde1963c88726f (patch)
treef5bf107ba079ae460536da778ce2da5e6c68aa69 /knights/match.cpp
downloadknights-a8c9924456e5335c964e4e55b2dde1963c88726f.tar.gz
knights-a8c9924456e5335c964e4e55b2dde1963c88726f.zip
Added KDE3 version of Knights
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/knights@1091568 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'knights/match.cpp')
-rw-r--r--knights/match.cpp1120
1 files changed, 1120 insertions, 0 deletions
diff --git a/knights/match.cpp b/knights/match.cpp
new file mode 100644
index 0000000..21957e4
--- /dev/null
+++ b/knights/match.cpp
@@ -0,0 +1,1120 @@
+/***************************************************************************
+ match.cpp - description
+ -------------------
+ begin : Mon Jul 2 2001
+ copyright : (C) 2003 by Troy Corbin Jr.
+ email : tcorbin@users.sourceforge.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qregexp.h>
+#include <kmessagebox.h>
+#include "match.moc"
+#include "board_base.h"
+#include "board_2d.h"
+#include "audio.h"
+
+#define WHITE_INPUT Record->Param->type(WHITE)
+#define BLACK_INPUT Record->Param->type(BLACK)
+
+///////////////////////////////////////
+//
+// match::match
+//
+///////////////////////////////////////
+match::match( QWidget *parent, match_param *param, resource *Rsrc ) : QWidget(parent)
+{
+ Resource = Rsrc;
+
+ /* Init Children */
+ Record = new pgn( Resource, param );
+ Logic = new logic( Resource, param );
+ Board = new board_2d( parent, "Board", Resource, Logic );
+ Board->show();
+ connect( Board, SIGNAL( leftClick(int) ), this, SLOT( slot_Select(int) ) );
+ connect( Board, SIGNAL( rightClick(int) ), this, SLOT( slot_Preview(int) ) );
+ Clock = new chessclock( this, "Clock", Resource );
+ Record->init();
+ Logic->Init();
+ Clock->Reset();
+ clearSelections();
+
+ /* Init Variables */
+ Draw_Offered[WHITE] = FALSE;
+ Draw_Offered[BLACK] = FALSE;
+ Modified = FALSE;
+ Loading = FALSE;
+ Paused = FALSE;
+ JustMoved = FALSE;
+ preMoved = FALSE;
+ Current = FALSE;
+ loadTimer = 0;
+ StatusCode = READY;
+ StatusMessage = QString::null;
+ ICSGameMode = Null;
+ parseMatchParam();
+
+ /* Connect Signals and Slots */
+ connect( param, SIGNAL( valuesChanged() ), this, SLOT( parseMatchParam() ) );
+ connect( Record, SIGNAL( processMove(ChessMove) ), this, SLOT( move(ChessMove) ) );
+ connect( Record, SIGNAL( processSpecial() ), this, SLOT( loadSpecial() ) );
+ connect( Clock, SIGNAL( flagFell(const bool) ), this, SLOT( slot_flagFell(const bool) ) );
+ connect( this, SIGNAL( setStatusBar( const int&, const QString& ) ), this, SLOT( saveStatusBar( const int&, const QString& ) ) );
+
+}
+///////////////////////////////////////
+//
+// match::~match
+//
+///////////////////////////////////////
+match::~match()
+{
+ delete Clock;
+ if( Board != NULL ) delete Board;
+ delete Record;
+ delete Logic;
+}
+///////////////////////////////////////
+//
+// match::setVisibility
+//
+///////////////////////////////////////
+void match::setVisibility( const bool vis )
+{
+ if( vis == TRUE )
+ {
+ show();
+ Board->show();
+ setEnabled( TRUE );
+ }
+ else
+ {
+ hide();
+ Board->hide();
+ setEnabled( FALSE );
+ }
+}
+///////////////////////////////////////
+//
+// match::parseMatchParam
+//
+///////////////////////////////////////
+void match::parseMatchParam( void )
+{
+ switch( BLACK_INPUT )
+ {
+ case PLAYERLOCAL:
+ Board->setLocalArmy( BLACK );
+ break;
+ }
+ switch( WHITE_INPUT )
+ {
+ case PLAYERLOCAL:
+ Board->setLocalArmy( WHITE );
+ break;
+ }
+}
+///////////////////////////////////////
+//
+// match::tick
+//
+///////////////////////////////////////
+void match::tick(void)
+{
+ Clock->Tick();
+ emit setClocks();
+ if( Loading )
+ {
+ if( loadTimer )
+ loadTimer--;
+ else
+ {
+ /*
+ All this is for a match we just finished loading
+ */
+ if( !Record->loadNext() )
+ {
+ Loading = FALSE;
+ emit sendCMD( Command( myID, CMD_Play ) );
+ if( Record->TAG_Result == "*" )
+ {
+ /* Unfinished Game */
+ Clock->Set( Record->whiteTime, Record->blackTime, onMove() );
+ }
+ else
+ {
+ /* Finished Match */
+ Clock->Pause();
+ if( Record->TAG_Result == "1/2-1/2" )
+ emit setStatusBar( GAME_DRAW );
+ if( Record->TAG_Result == "1-0" )
+ emit setStatusBar( WHITE_WIN );
+ if( Record->TAG_Result == "0-1" )
+ emit setStatusBar( BLACK_WIN );
+ }
+ }
+ }
+ }
+}
+///////////////////////////////////////
+//
+// match::clearSelections
+//
+///////////////////////////////////////
+void match::clearSelections( void )
+{
+ bool commitFlag( FALSE );
+ register char tmp;
+
+ if( ICSGameMode == Null )
+ {
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ if( Logic->current[tmp].Note != NOTE_NONE )
+ {
+ Logic->current[tmp].Note = NOTE_NONE;
+ Board->drawPosition( tmp );
+ commitFlag = TRUE;
+ }
+ }
+ }
+ else
+ {
+ for( tmp = 0; tmp < 64; tmp++ )
+ {
+ Logic->current[tmp].Note = NOTE_NONE;
+ Board->drawPosition( tmp );
+ commitFlag = TRUE;
+ }
+ }
+ if( commitFlag )
+ {
+ Board->commit();
+ }
+}
+///////////////////////////////////////
+//
+// match::flip
+//
+///////////////////////////////////////
+void match::flip(void)
+{
+ Board->flipBoard();
+}
+///////////////////////////////////////
+//
+// match::resize
+//
+///////////////////////////////////////
+void match::resize(void)
+{
+ Board->resizeBoard();
+ setFixedSize( Board->width(), Board->height() );
+}
+///////////////////////////////////////
+//
+// match::redraw
+//
+///////////////////////////////////////
+void match::redraw(void)
+{
+ Board->redrawAll();
+}
+///////////////////////////////////////
+//
+// match::slot_flagFell
+//
+///////////////////////////////////////
+void match::slot_flagFell( const bool Army )
+{
+ if( Army == WHITE )
+ {
+ emit setStatusBar( WHITE_FLAG );
+ if( ( Resource->OPTION_Auto_Call_Flag ) && ( WHITE_INPUT != PLAYERLOCAL ) && ( BLACK_INPUT == PLAYERLOCAL ) )
+ {
+ emit sendCMD( Command( myID, CMD_Black_Called_Flag ) );
+ recvCMD( Command( myID, CMD_Black_Called_Flag ) );
+ }
+ }
+ else
+ {
+ emit setStatusBar( BLACK_FLAG );
+ if( ( Resource->OPTION_Auto_Call_Flag ) && ( BLACK_INPUT != PLAYERLOCAL ) && ( WHITE_INPUT == PLAYERLOCAL ) )
+ {
+ emit sendCMD( Command( myID, CMD_White_Called_Flag ) );
+ recvCMD( Command( myID, CMD_White_Called_Flag ) );
+ }
+ }
+}
+///////////////////////////////////////
+//
+// match::setPaused
+//
+///////////////////////////////////////
+void match::setPaused( const bool State )
+{
+ Paused = State;
+ Board->setPaused( State );
+ if( Paused )
+ {
+ Clock->Pause();
+ emit setStatusBar( PAUSED );
+ }
+ else
+ {
+ Clock->Resume();
+ if( onMove() == WHITE ) emit setStatusBar( WHITE_TURN );
+ else emit setStatusBar( BLACK_TURN );
+ }
+}
+///////////////////////////////////////
+//
+// match::inputOnMove
+//
+///////////////////////////////////////
+char match::inputOnMove( bool reverse )
+{
+ if( reverse )
+ {
+ if( Logic->OnMove == BLACK )
+ return WHITE_INPUT;
+ if( Logic->OnMove == WHITE )
+ return BLACK_INPUT;
+ }
+ else
+ {
+ if( Logic->OnMove == WHITE )
+ return WHITE_INPUT;
+ if( Logic->OnMove == BLACK )
+ return BLACK_INPUT;
+ }
+ return Null;
+}
+///////////////////////////////////////
+//
+// match::input
+//
+///////////////////////////////////////
+char match::input( char army )
+{
+ return Record->Param->type(army);
+}
+///////////////////////////////////////
+//
+// match::save
+//
+///////////////////////////////////////
+bool match::save( QString URL )
+{
+ Record->whiteTime = Clock->getCentiseconds(WHITE);
+ Record->blackTime = Clock->getCentiseconds(BLACK);
+ return Record->save( URL );
+}
+///////////////////////////////////////
+//
+// match::load
+//
+///////////////////////////////////////
+bool match::load( const QString URL, const int pos )
+{
+ bool Result;
+ Loading = TRUE;
+ loadTimer = 20;
+ if( !Record->open( URL ) )
+ {
+ return FALSE;
+ }
+ Result = Record->load( pos );
+ if( !Record->TAG_FEN.isEmpty() )
+ {
+ // We must set up the FEN position
+ Logic->setBoardFromFen( Record->TAG_FEN );
+ sendCMD( Command( myID, CMD_Set_Board, Record->TAG_FEN ) );
+ }
+ return Result;
+}
+///////////////////////////////////////
+//
+// match::loadSpecial
+//
+///////////////////////////////////////
+void match::loadSpecial( void )
+{
+ /*
+ As pointless as this function may seem ( in light of these variables and more
+ being setup in tick(), it is required to initialize a Chess Engine and feed it
+ the moves from a saved game so you can play it again later.
+ */
+ emit sendCMD( Command( myID, CMD_New_Players ) );
+}
+///////////////////////////////////////
+//
+// match::url
+//
+///////////////////////////////////////
+QString match::url( void )
+{
+ if( !Record->CurrentURL.isEmpty() )
+ return Record->CurrentURL;
+ if( Resource->OPTION_Reuse_PGN )
+ return Resource->PGN_Filename;
+ return QString::null;
+}
+///////////////////////////////////////
+//
+// match::clock
+//
+///////////////////////////////////////
+QString match::clock( const bool Army )
+{
+ if( Army == WHITE ) return Clock->whiteClock;
+ return Clock->blackClock;
+}
+///////////////////////////////////////
+//
+// match::slot_Select
+//
+///////////////////////////////////////
+void match::slot_Select( int position )
+{
+ bool preMoving(FALSE);
+ register char tmp, army, selected(Null);
+
+ if( Paused ) return;
+ /* Clear all non-SELECT notes */
+ for( tmp = 0;tmp < 64;tmp++ )
+ {
+ if( Logic->current[tmp].Note != NOTE_NONE )
+ {
+ if( Logic->current[tmp].Note != NOTE_SELECT )
+ {
+ Logic->current[tmp].Note = NOTE_NONE;
+ Board->drawPosition( tmp );
+ }
+ else
+ {
+ selected = tmp;
+ }
+ }
+ }
+ Board->commit();
+
+ /* Check to make sure it's our turn to select. */
+ if( !( inputOnMove() & PLAYERLOCAL ) )
+ {
+ if( ( inputOnMove(TRUE) == PLAYERLOCAL ) && ( Resource->OPTION_Premove ) )
+ {
+ preMoving = TRUE;
+ }
+ else
+ {
+ return;
+ }
+ }
+ /* If you left click on a selected square, it becomes unselected. */
+ if( Logic->current[position].Note == NOTE_SELECT )
+ {
+ Logic->current[position].Note = NOTE_NONE;
+ drawPosition( position );
+ playSound( SND_SELECT );
+ return;
+ }
+ if( preMoved )
+ {
+ preMoved = FALSE;
+ playSound( SND_SELECT );
+ Board->setPremovePositions( Null, Null );
+ Board->drawPosition( Logic->Pointer( preMove.fromFile, preMove.fromRank ) );
+ Board->drawPosition( Logic->Pointer( preMove.toFile, preMove.toRank ) );
+ Board->commit();
+ }
+ /* Check to see if there is already a selected square. */
+ if( selected != Null )
+ {
+ /*
+ If there is already a selected square, and you just clicked on another of your men,
+ we'll change your selection.
+ */
+ if( Logic->current[position].ManPtr != Null )
+ {
+ if( Logic->chessman[ Logic->current[selected].ManPtr ].Army == Logic->chessman[ Logic->current[position].ManPtr ].Army )
+ {
+ Logic->current[selected].Note = NOTE_NONE;
+ Logic->current[position].Note = NOTE_SELECT;
+ Board->drawPosition( selected );
+ drawPosition( position );
+ if( Resource->OPTION_Auto_Preview == TRUE )
+ slot_Preview( position );
+ else
+ playSound( SND_SELECT );
+ return;
+ }
+ }
+ /*
+ If there is already a selected square, but this one you just clicked
+ isn't one of your chessmen, you must want to move a piece.
+ */
+ if( ( Record->currentIndex != ( Record->Positions.count() - 1 ) ) && ( Record->currentIndex ) )
+ {
+ emit setStatusBar( NO_MOVE_WHILE_REVIEW );
+ return;
+ }
+ if( preMoving )
+ {
+ Command::clearMove( &preMove );
+ preMove.fromRank = Logic->current[selected].Rank;
+ preMove.fromFile = Logic->current[selected].File;
+ preMove.toRank = Logic->current[position].Rank;
+ preMove.toFile = Logic->current[position].File;
+ preMoved = TRUE;
+ playSound( SND_SELECT );
+ Board->setPremovePositions( selected, position );
+ }
+ else
+ {
+ Command::clearMove( &chessMove );
+ chessMove.fromRank = Logic->current[selected].Rank;
+ chessMove.fromFile = Logic->current[selected].File;
+ chessMove.toRank = Logic->current[position].Rank;
+ chessMove.toFile = Logic->current[position].File;
+ JustMoved = TRUE;
+ if( move() == FALSE )
+ {
+ Logic->current[selected].Note = NOTE_SELECT;
+ drawPosition( selected );
+ }
+ }
+ return;
+ }
+ tmp = Logic->current[position].ManPtr;
+
+ /* You can't select an empty square. */
+ if( tmp == Null )
+ {
+ return;
+ }
+ army = Logic->chessman[ tmp ].Army;
+
+ /* You can't select your enemy */
+ if( ( army != onMove() ) && ( preMoving == FALSE ) )
+ {
+ return;
+ }
+
+ /* If your clicking on one of your chessmen, you can select it. */
+ clearSelections();
+ if( ( army == WHITE ) && ( WHITE_INPUT & PLAYERLOCAL ) )
+ {
+ Logic->current[position].Note = NOTE_SELECT;
+ }
+ if( ( army == BLACK ) && ( BLACK_INPUT & PLAYERLOCAL ) )
+ {
+ Logic->current[position].Note = NOTE_SELECT;
+ }
+ drawPosition( position );
+ if( Resource->OPTION_Auto_Preview == TRUE )
+ {
+ slot_Preview( position );
+ }
+ else
+ {
+ /* Play the select sound if you selected a square & you didn't preview */
+ if( Logic->current[position].Note == NOTE_SELECT )
+ {
+ playSound( SND_SELECT );
+ }
+ }
+}
+///////////////////////////////////////
+//
+// match::slot_Preview
+//
+///////////////////////////////////////
+void match::slot_Preview( int position )
+{
+ char tmp;
+
+ if( Paused )
+ {
+ return;
+ }
+ clearSelections();
+ tmp = Logic->current[position].ManPtr;
+ if( tmp == Null ) return;
+
+ Logic->HashLegal( tmp );
+
+ /* If your clicking on one of your chessmen, you can select it. */
+ if( ( Logic->chessman[tmp].Army == Logic->OnMove ) && ( Record->Param->type( Logic->OnMove ) & PLAYERLOCAL ) )
+ Logic->current[position].Note = NOTE_SELECT;
+ for( tmp = 0;tmp < 64;tmp++ )
+ {
+ if( Logic->current[tmp].Note != NOTE_NONE )
+ {
+ Board->drawPosition( tmp );
+ }
+ }
+ drawPosition( 0 );
+ playSound( SND_SELECT );
+}
+///////////////////////////////////////
+//
+// match::recvCMD
+//
+///////////////////////////////////////
+void match::recvCMD( const Command &constCommand )
+{
+ Command cmd( constCommand );
+
+ if( cmd.getID() != myID )
+ return;
+ ChessMove newMove = cmd.getMove();
+
+ switch( cmd.getCommand() )
+ {
+ /* CMD_Move */
+ case CMD_Move:
+ if( newMove.ICS_Mode == Null )
+ {
+ /* Not an ICS Move */
+ move( newMove );
+ }
+ else
+ {
+ /* Do NOT accept a setBoard on a concluded match */
+ if( ( Logic->OnMove == -1 ) && ( newMove.ICS_Mode < ICS_Examine ) )
+ return;
+ ICSGameMode = newMove.ICS_Mode;
+ Logic->OnMove = newMove.ICS_OnMove;
+
+ if( ICSGameMode == ICS_Movelist )
+ {
+ /* Recieving Movelist */
+ Logic->chessMove = newMove;
+ Logic->parseSAN();
+ JustMoved = FALSE;
+ }
+ else
+ {
+ /* Recieving Standard Move */
+ Logic->setBoard( cmd.getData(), newMove.ICS_PawnPushFile );
+ Logic->MoveCounter = newMove.ICS_MoveCounter;
+ Logic->chessMove = newMove;
+ Logic->parseCAN( Logic->OnMove );
+ }
+ chessMove = Logic->chessMove;
+ /* Run through the Move function */
+ if( !JustMoved )
+ move();
+ else
+ {
+ JustMoved = FALSE;
+ Logic->OnMove = !Logic->OnMove;
+ }
+
+ Clock->Set( cmd.getWhiteTime(), cmd.getBlackTime(), !newMove.ICS_OnMove );
+ if( newMove.ICS_ClockTicking )
+ {
+ Clock->Resume();
+ }
+ else
+ {
+ Clock->Pause();
+ }
+ }
+ break;
+
+ /* CMD_Offer_Draw */
+ case CMD_Offer_Draw:
+ if( cmd.getData() == "W" )
+ {
+ Draw_Offered[WHITE] = 2;
+ emit setStatusBar( WHITE_DRAW_OFFER );
+ }
+ else
+ {
+ Draw_Offered[BLACK] = 2;
+ emit setStatusBar( BLACK_DRAW_OFFER );
+ }
+ break;
+
+ /* CMD_Illegal */
+ case CMD_Illegal:
+ retract();
+ emit setNotation();
+ break;
+
+ /* Lost Contact */
+ case CMD_Lost_Contact:
+ Clock->Pause();
+ Logic->OnMove = -1;
+ emit setStatusBar( LOST_CONTACT );
+ Record->TAG_Result = "*";
+ Record->TAG_Termination = "Lost Contact with Opponent";
+ break;
+
+ /* Result White */
+ case CMD_Result_White:
+ Clock->Pause();
+ Logic->OnMove = -1;
+ emit setStatusBar( WHITE_CHECKMATE );
+ Record->TAG_Result = "1-0";
+ Record->TAG_Termination = "Normal";
+ break;
+
+ /* Result Black */
+ case CMD_Result_Black:
+ Clock->Pause();
+ Logic->OnMove = -1;
+ emit setStatusBar( BLACK_CHECKMATE );
+ Record->TAG_Result = "0-1";
+ Record->TAG_Termination = "Normal";
+ break;
+
+ /* Result Draw */
+ case CMD_Result_Draw:
+ Clock->Pause();
+ Logic->OnMove = -1;
+ if( Logic->MoveCounter == 50 )
+ {
+ emit setStatusBar( GAME_50_MOVES );
+ }
+ else
+ {
+ emit setStatusBar( GAME_DRAW );
+ }
+ Record->TAG_Result = "1/2-1/2";
+ break;
+
+ /* White Resign */
+ case CMD_White_Resign:
+ Clock->Pause();
+ Logic->OnMove = -1;
+ emit setStatusBar( WHITE_RESIGN );
+ Record->TAG_Result = "0-1";
+ Record->TAG_Termination = "White resigned";
+ break;
+
+ /* Black Resign */
+ case CMD_Black_Resign:
+ Clock->Pause();
+ Logic->OnMove = -1;
+ emit setStatusBar( BLACK_RESIGN );
+ Record->TAG_Result = "1-0";
+ Record->TAG_Termination = "Black resigned";
+ break;
+
+ /* White Called Flag */
+ case CMD_White_Called_Flag:
+ Clock->Pause();
+ Logic->OnMove = -1;
+ emit setStatusBar( WHITE_CALL_FLAG );
+ Record->TAG_Result = "1-0";
+ Record->TAG_Termination = "Black's flag was called";
+ break;
+
+ /* Black Called Flag */
+ case CMD_Black_Called_Flag:
+ Clock->Pause();
+ Logic->OnMove = -1;
+ emit setStatusBar( BLACK_CALL_FLAG );
+ Record->TAG_Result = "0-1";
+ Record->TAG_Termination = "White's flag was called";
+ break;
+
+ default:
+ break;
+ }
+}
+///////////////////////////////////////
+//
+// match::move
+//
+///////////////////////////////////////
+bool match::move( ChessMove newMove )
+{
+ /* Clear selections from the board */
+ clearSelections();
+
+ Logic->chessMove = newMove;
+ if( Logic->parseCAN( onMove() ) != TRUE )
+ {
+ if( Logic->parseSAN() != TRUE )
+ {
+ kdDebug() << "#" << myID << ": Recieved bad data: " << newMove.CAN << endl;
+ return FALSE;
+ }
+ }
+ chessMove = Logic->chessMove;
+ JustMoved = TRUE;
+ return move();
+}
+bool match::move( void )
+{
+ int soundType( SND_MOVE );
+ int result(Null);
+ char manPtr(Null);
+ QString SAN;
+
+ /* Bring the display up to the latest move before we proceed */
+ if( ICSGameMode == Null )
+ {
+ if( Record->currentIndex != ( Record->Positions.count() - 1 ) )
+ {
+ review( Record->Moves.count() - 1 );
+ }
+ }
+
+ /* Clear selections from the board */
+ clearSelections();
+
+ /* Build Pointers */
+ char fromPtr = ( chessMove.fromRank << 3 ) + chessMove.fromFile;
+ char toPtr = ( chessMove.toRank << 3 ) + chessMove.toFile;
+
+ /* Skip all this if we're being called due to normal server moves */
+ if( ( JustMoved == TRUE ) || ( ICSGameMode == ICS_Movelist ) )
+ {
+ if( ( fromPtr > 63 ) || ( toPtr > 63 ) )
+ return FALSE;
+ if( ( fromPtr < 0 ) || ( toPtr < 0 ) )
+ return FALSE;
+ manPtr = Logic->current[fromPtr].ManPtr;
+ if( manPtr == Null )
+ return FALSE;
+ /* Make the move */
+ Logic->chessMove = chessMove;
+ if( Logic->Move() == FALSE )
+ return FALSE;
+ chessMove = Logic->chessMove;
+ }
+
+ /* Play sound for Promotion */
+ if( QString( chessMove.SAN ).contains( QChar( '=' ) ) )
+ {
+ soundType = SND_PROMOTE;
+ }
+
+ /* Check to see if the game is ended */
+ /* 50 Move Rule? */
+ if( Logic->MoveCounter == 50 )
+ {
+ result = CMD_Result_Draw;
+ }
+ /*
+ A Draw via 3 move repeat
+
+ if( Record->isThreeMoveDraw() )
+ {
+ result = CMD_Result_Draw;
+ Record->TAG_Result = "1/2-1/2";
+ emit setStatusBar( GAME_DRAW );
+ } */
+ /*
+ A Draw?
+
+ Condition 1 = White Material Draw
+ Condition 2 = Black Material Draw
+ Condition 3 = Both sides agree to a draw
+ */
+ if( ( Logic->OnMove == BLACK && Logic->isDraw( WHITE ) ) ||
+ ( Logic->OnMove == WHITE && Logic->isDraw( BLACK ) ) ||
+ ( Draw_Offered[WHITE] && Draw_Offered[BLACK] ) )
+ {
+ result = CMD_Result_Draw;
+ }
+
+ /* Is White under check? */
+ if( Logic->isCheck( WHITE ) )
+ {
+ if( !Logic->isLegal( WHITE ) )
+ {
+ SAN += '#';
+ result = CMD_Result_Black;
+ }
+ else
+ {
+ SAN += '+';
+ soundType = SND_CHECK;
+ }
+ }
+
+ /* Is Black under check? */
+ if( Logic->isCheck( BLACK ) )
+ {
+ if( !Logic->isLegal( BLACK ) )
+ {
+ SAN += '#';
+ result = CMD_Result_White;
+ }
+ else
+ {
+ SAN += '+';
+ soundType = SND_CHECK;
+ }
+ }
+
+ /* Check to make sure this isn't the starting position in an ICS match */
+ if( QString( chessMove.SAN ) != "none" )
+ {
+ if( !SAN.isEmpty() )
+ {
+ strcat( chessMove.SAN, SAN.latin1() );
+ }
+ Record->Positions << Logic->board();
+ Record->Moves << chessMove;
+ Record->currentIndex = Record->Moves.count() - 1;
+ if( JustMoved == TRUE )
+ {
+ /* Send this move to engines and servers */
+ emit sendCMD( Command( myID, CMD_Move, centiseconds( WHITE ), centiseconds( BLACK ),
+ chessMove, Record->notation(FALSE)->join(QString(" ")) ) );
+ }
+ /* Draw The Move */
+ if( ICSGameMode != ICS_Movelist )
+ Board->drawMove( chessMove );
+ }
+
+ /* Take care of changing turns, status messages, etc. */
+ if( result == Null )
+ {
+ Clock->Moved();
+ if( Paused )
+ Clock->Pause();
+
+ Logic->OnMove = !Logic->OnMove;
+ /* Set Status Bar */
+ if( Logic->OnMove == WHITE )
+ {
+ emit setStatusBar( WHITE_TURN );
+ }
+ if( Logic->OnMove == BLACK )
+ {
+ emit setStatusBar( BLACK_TURN );
+ }
+
+ /* Set Cursor */
+ if( ( inputOnMove(TRUE) == PLAYERLOCAL ) && ( inputOnMove() != PLAYERLOCAL ) )
+ {
+ Board->setCursor( Resource->CURSOR_Thinking );
+ }
+ else
+ {
+ Board->setCursor( Resource->CURSOR_Standard );
+ }
+
+ /* Deprecieate Draw Offers */
+ if( Draw_Offered[WHITE] )
+ {
+ Draw_Offered[WHITE]--;
+ }
+ if( Draw_Offered[BLACK] )
+ {
+ Draw_Offered[BLACK]--;
+ }
+
+ /* Display NAG Anotation */
+ if( chessMove.NAG != 0 )
+ {
+ emit setStatusBar( COMMENT + chessMove.NAG );
+ }
+ }
+ else
+ {
+ /* End of Match */
+ Board->setCursor( Resource->CURSOR_Standard );
+ recvCMD( Command( myID, result ) );
+ emit sendCMD( Command( myID, result ) );
+ soundType = SND_MATCH_OVER;
+ }
+ emit setNotation();
+
+ if( ICSGameMode != ICS_Movelist )
+ {
+ Board->redrawLights();
+ Board->commit();
+ }
+ /* Play the Sound */
+ playSound( soundType );
+
+ /* Handle special cases */
+ if( loading() )
+ {
+ loadTimer = 10; // Loading...
+ }
+ else
+ {
+ Modified = TRUE;
+ }
+ if( preMoved )
+ {
+ preMoved = FALSE;
+ Board->setPremovePositions( Null, Null );
+ chessMove = preMove;
+ JustMoved = TRUE;
+ move();
+ }
+/* if( inputOnMove() == PLAYEREMAIL )
+ {
+ Clock->Pause(); // Email
+ KMessageBox::questionYesNo( this,
+ i18n("Would you like to email this move?"),
+ i18n("Send Email?") );
+ }
+*/
+ return TRUE;
+}
+///////////////////////////////////////
+//
+// match::retract
+//
+///////////////////////////////////////
+void match::retract( void )
+{
+ emit setStatusBar(ILLEGAL_MOVE);
+ review( Record->Moves.count() - 2 );
+ _retract();
+}
+void match::_retract( void )
+{
+ if( Record->Moves.count() )
+ {
+ Record->Moves.remove( Record->Moves.at( Record->Moves.count() - 1 ) );
+ Record->Positions.remove( Record->Positions.at( Record->Positions.count() - 1 ) );
+ Record->currentIndex = Record->Moves.count() - 1;
+ }
+}
+///////////////////////////////////////
+//
+// match::review
+//
+///////////////////////////////////////
+void match::review( const int Index )
+{
+ int tmp(0), step;
+ QString tmpS;
+ if( ICSGameMode == ICS_Examine )
+ {
+ /* Examined Game: Use Examine Semantics */
+ if( Index < (signed)Record->currentIndex )
+ step = -1;
+ else
+ step = 1;
+ if( ( Record->currentIndex == 0 ) && ( Index == 0 ) && ( step == 1 ) )
+ {
+ emit sendCMD( Command( myID, CMD_Examine_Forward ) );
+ }
+ if( step == 1 )
+ {
+ for( tmp = Record->currentIndex; tmp != Index; tmp += step )
+ {
+ emit sendCMD( Command( myID, CMD_Examine_Forward ) );
+ }
+ }
+ else
+ {
+ for( tmp = Record->currentIndex; tmp != Index; tmp += step )
+ {
+ _retract();
+ _retract();
+ emit sendCMD( Command( myID, CMD_Examine_Backward ) );
+ }
+ }
+ }
+ else
+ {
+ /* Regular Game: Use Standard Review Semantics */
+ if( Record->Positions.count() == 0 )
+ return;
+ if( Index < 0 )
+ return;
+ if( Index > ( (signed int)Record->Positions.count() - 1 ) )
+ return;
+
+ /* Review differently depending on our Animation Option */
+ if( Resource->OPTION_Animate_Moves )
+ {
+ if( (unsigned)Index > Record->currentIndex )
+ {
+ /* Forward */
+ Logic->setBoard( Record->Positions[Index - 1] );
+ while( tmp < 64 )
+ Board->drawPosition( tmp++ );
+ Logic->setBoard( Record->Positions[Index] );
+ Board->drawMove( Record->Moves[Index] );
+ }
+ else if( (unsigned)Index < Record->currentIndex )
+ {
+ /* Reverse */
+ Logic->setBoard( Record->Positions[Index + 1] );
+ while( tmp < 64 )
+ Board->drawPosition( tmp++ );
+ Board->drawMove( Record->Moves[Index + 1], TRUE );
+ Logic->setBoard( Record->Positions[Index] );
+ }
+ }
+ else
+ {
+ /* No Animation */
+ Logic->setBoard( Record->Positions[Index] );
+ while( tmp < 64 )
+ Board->drawPosition( tmp++ );
+ Board->drawMove( Record->Moves[Index] );
+ }
+ Board->commit();
+
+ /* Statusbar shows NAG if available, otherwise Army to move */
+ if( Record->Moves[Index].NAG )
+ {
+ tmp = StatusCode;
+ tmpS = StatusMessage;
+ emit setStatusBar( COMMENT + Record->Moves[Index].NAG );
+ StatusCode = tmp;
+ StatusMessage = tmpS;
+ }
+ else
+ emit setStatusBar( StatusCode, StatusMessage );
+ Record->currentIndex = Index;
+ }
+}
+///////////////////////////////////////
+//
+// match::playSound
+//
+///////////////////////////////////////
+void match::playSound( const int snd )
+{
+ if( Resource->OPTION_Audio_Current_Only && !Current )
+ {
+ return;
+ }
+ Resource->play( snd );
+}
+///////////////////////////////////////
+//
+// match::drawPosition
+//
+///////////////////////////////////////
+void match::drawPosition( const int position )
+{
+ Board->drawPosition( position );
+ Board->commit();
+}
+///////////////////////////////////////
+//
+// match::requestHint
+//
+///////////////////////////////////////
+void match::requestHint( void )
+{
+ emit sendCMD( Command( myID, CMD_Hint ) );
+ emit sendCMD( Command( myID, CMD_UCI_Hint, centiseconds( WHITE ), centiseconds( BLACK ), Record->notation(FALSE)->join(QString(" ")) ) );
+}