You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
knights/knights/match.cpp

1121 lines
25 KiB

/***************************************************************************
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 <tqregexp.h>
#include <tdemessagebox.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( TQWidget *parent, match_param *param, resource *Rsrc ) : TQWidget(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, TQT_SIGNAL( leftClick(int) ), this, TQT_SLOT( slot_Select(int) ) );
connect( Board, TQT_SIGNAL( rightClick(int) ), this, TQT_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 = TQString();
ICSGameMode = Null;
parseMatchParam();
/* Connect Signals and Slots */
connect( param, TQT_SIGNAL( valuesChanged() ), this, TQT_SLOT( parseMatchParam() ) );
connect( Record, TQT_SIGNAL( processMove(ChessMove) ), this, TQT_SLOT( move(ChessMove) ) );
connect( Record, TQT_SIGNAL( processSpecial() ), this, TQT_SLOT( loadSpecial() ) );
connect( Clock, TQT_SIGNAL( flagFell(const bool) ), this, TQT_SLOT( slot_flagFell(const bool) ) );
connect( this, TQT_SIGNAL( setStatusBar( const int&, const TQString& ) ), this, TQT_SLOT( saveStatusBar( const int&, const TQString& ) ) );
}
///////////////////////////////////////
//
// 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( TQString URL )
{
Record->whiteTime = Clock->getCentiseconds(WHITE);
Record->blackTime = Clock->getCentiseconds(BLACK);
return Record->save( URL );
}
///////////////////////////////////////
//
// match::load
//
///////////////////////////////////////
bool match::load( const TQString 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
//
///////////////////////////////////////
TQString match::url( void )
{
if( !Record->CurrentURL.isEmpty() )
return Record->CurrentURL;
if( Resource->OPTION_Reuse_PGN )
return Resource->PGN_Filename;
return TQString();
}
///////////////////////////////////////
//
// match::clock
//
///////////////////////////////////////
TQString 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);
TQString 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( TQString( chessMove.SAN ).contains( TQChar( '=' ) ) )
{
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( TQString( 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(TQString(" ")) ) );
}
/* 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;
TQString 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(TQString(" ")) ) );
}