|
|
|
/***************************************************************************
|
|
|
|
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(" ")) ) );
|
|
|
|
}
|