diff options
Diffstat (limited to 'knights/match.cpp')
-rw-r--r-- | knights/match.cpp | 1120 |
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(" ")) ) ); +} |