/*************************************************************************** * Copyright (C) 1980-2005 Artur Wiebe * * artur@wiebenet.de * * * * 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. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "pdn.h" #include "pdnpreview.h" #include "echeckers.h" #include "rcheckers.h" #include "view.h" #include "config.h" #include "player.h" #include "console.h" #include #include #include #include #include #define ERR_TIMEOUT 2000 #define ERR_TIMEOUT2 4000 myView::myView(QWidget* parent) : QFrame(parent) { setFrameStyle(QFrame::WinPanel | QFrame::Sunken); QHBoxLayout* hb = new QHBoxLayout(this, 5); hb->addWidget(create_board(), 0, Qt::AlignCenter); hb->addWidget(create_info(), 1); game = 0; m_player = m_current = 0; xpmPat1 = xpmPat2 = xpmFrame = 0; xpmMan1 = xpmMan2 = xpmKing1 = xpmKing2 = 0; xpmManBlack = xpmManWhite = xpmKingBlack = xpmKingWhite = 0; } myView::~myView() { if(m_player) { delete m_player; delete m_player->opponent(); } } void myView::setEnabled(bool b) { m_board->setEnabled(b); } QWidget* myView::create_board() { m_board = new QFrame(this); m_board->setFrameStyle(QFrame::Box|QFrame::Plain); // m_board->setFrameStyle(QFrame::WinPanel | QFrame::Sunken); for(int i=0; i<64; i++) field[i] = new Field(m_board, i); QGridLayout* grid = new QGridLayout(m_board, 8, 8, 1, 0); for(int i=0; i<4; i++) { for(int k=0; k<4; k++) { grid->addWidget(field[i*8+k+32], i*2, k*2 ); grid->addWidget(field[i*8+k ], i*2, k*2+1); grid->addWidget(field[i*8+k+4 ], i*2+1,k*2 ); grid->addWidget(field[i*8+k+36], i*2+1,k*2+1); } } for(int i=0; i<32; i++) connect(field[i], SIGNAL(click(int)), this, SLOT(slotClick(int))); //awQWhatsThis::add(frame,tr("A checkers board")); return m_board; } QWidget* myView::create_info() { QFrame* frm = new QFrame(this); frm->setMinimumWidth(250); frm->setFont(QFont(font().family(), 9)); frm->setFrameStyle(QFrame::Panel | QFrame::Raised); // m_rules = new QLabel(frm); m_rules->setFont(QFont(font().family(), 14, QFont::Bold)); m_rules->setMargin(5); m_rules->setAlignment(AlignCenter); m_rules->setPaletteForegroundColor(white); m_rules->setPaletteBackgroundColor(blue); // m_white.frm = new QHBox(frm); m_white.frm->setMargin(5); m_white.frm->setSpacing(20); QLabel* tmp_white = new QLabel(m_white.frm); tmp_white->setPixmap(QPixmap::fromMimeSource("small_manwhite.png")); m_white.name = new QLabel(m_white.frm); m_white.rounds = new QLabel(m_white.frm); m_white.frm->setStretchFactor(tmp_white, 0); m_white.frm->setStretchFactor(m_white.name, 1); m_white.frm->setStretchFactor(m_white.rounds, 0); m_black.frm = new QHBox(frm); m_black.frm->setMargin(5); m_black.frm->setSpacing(20); QLabel* tmp_black = new QLabel(m_black.frm); tmp_black->setPixmap(QPixmap::fromMimeSource("small_manblack.png")); m_black.name = new QLabel(m_black.frm); m_black.rounds = new QLabel(m_black.frm); m_black.frm->setStretchFactor(tmp_black, 0); m_black.frm->setStretchFactor(m_black.name, 1); m_black.frm->setStretchFactor(m_black.rounds, 0); // misc m_error = new QLabel(frm); m_error->setPaletteForegroundColor(red); m_error->setAlignment(Qt::WordBreak | Qt::AlignCenter); m_error->setFont(QFont(font().family(), 10, QFont::Bold)); //aw??? m_error->setFrameStyle(QFrame::Box | QFrame::Plain); m_status = new QLabel(frm); m_status->setPaletteForegroundColor(blue); m_status->setAlignment(Qt::WordBreak | Qt::AlignCenter); m_status->setFont(QFont(font().family(), 10, QFont::Bold)); //aw?? m_status->setFrameStyle(QFrame::Box | QFrame::Plain); // layout QVBoxLayout* vb = new QVBoxLayout(frm, 5); vb->addWidget(m_rules); vb->addWidget(m_white.frm); vb->addWidget(m_black.frm); //aw??? vb->addStretch(1); vb->addWidget(m_error, 1); vb->addWidget(m_status, 1); return frm; } void myView::setPattern(const QString& pat, const QString& size) { /* qDebug("myView::setPattern(%s, %s) is_white %d", size.latin1(), pat.latin1(), (m_cur_player?m_cur_player->isWhite() : -1)); */ // delete them later. QPixmap* p1 = xpmManWhite; QPixmap* p2 = xpmManBlack; QPixmap* p3 = xpmKingWhite; QPixmap* p4 = xpmKingBlack; QPixmap* p5 = xpmPat1; QPixmap* p6 = xpmPat2; QPixmap* p7 = xpmFrame; xpmManWhite = new QPixmap(QPixmap::fromMimeSource(size+"_manwhite.png")); xpmManBlack = new QPixmap(QPixmap::fromMimeSource(size+"_manblack.png")); xpmKingWhite= new QPixmap(QPixmap::fromMimeSource(size+"_kingwhite.png")); xpmKingBlack= new QPixmap(QPixmap::fromMimeSource(size+"_kingblack.png")); xpmPat1 = new QPixmap(QPixmap::fromMimeSource(size+"_"+pat+"1.png")); xpmPat2 = new QPixmap(QPixmap::fromMimeSource(size+"_"+pat+"2.png")); xpmFrame= new QPixmap(QPixmap::fromMimeSource(size+"_"+pat+"3.png")); setColorWhite(m_player ? m_player->isWhite() : true); for(int i=0; i<32; i++) field[i]->setPattern(xpmPat2); for(int i=32; i<64; i++) field[i]->setPattern(xpmPat1); for(int i=0; i<32; i++) field[i]->setFrame(xpmFrame); m_board->setMinimumSize(xpmMan1->width()*8, xpmMan1->height()*8); if(game) draw_board(); // now delete. if(p1) delete p1; if(p2) delete p2; if(p3) delete p3; if(p4) delete p4; if(p5) delete p5; if(p6) delete p6; if(p7) delete p7; } void myView::reset_board(int board[32]) { int new_board[32]; int* setupBoard = new_board; if(board) { setupBoard = board; } else { // reset board. for(int i=0; i<12; i++) setupBoard[i]=MAN2; for(int i=12; i<20; i++) setupBoard[i]=FREE; for(int i=20; i<32; i++) setupBoard[i]=MAN1; } // reset frames. for(int i=0; i<32; i++) field[i]->showFrame(false); if(game) game->setup(setupBoard); } void myView::drawNotation() { if(!game) return; QString notation; if(game->type()==ENGLISH) notation = QString(ENOTATION); else notation = QString(RNOTATION).upper(); if(m_player->isWhite()) for(int i=0; i<32; i++) field[i]->setLabel(notation.mid(i*2,2)); else for(int i=0; i<32; i++) field[i]->setLabel(notation.mid(62-i*2,2)); } void myView::draw_board() { for(int i=0; i<32; i++) { switch(game->item(i)) { case MAN1: field[i]->setPicture(xpmMan1); break; case MAN2: field[i]->setPicture(xpmMan2); break; case KING1: field[i]->setPicture(xpmKing1); break; case KING2: field[i]->setPicture(xpmKing2); break; default: field[i]->setPicture(NULL); } } } void myView::init_game(myPlayer* plr, myPlayer* opp, int skill, int rules) { m_player = plr; emit working(true); /* * set up player stuff. slots/signals. */ plr->disconnect(); opp->disconnect(); connect(plr, SIGNAL(moveDone(const QString&)), this, SLOT(slotMoveDone(const QString&))); connect(plr, SIGNAL(stopped()), this, SLOT(slotStopped())); connect(plr, SIGNAL(message(const QString&)), this, SLOT(slotPlayerMessage(const QString&))); connect(plr, SIGNAL(nextRound()), this, SLOT(slotNextRound())); connect(opp, SIGNAL(moveDone(const QString&)), this, SLOT(slotMoveDone(const QString&))); connect(opp, SIGNAL(stopped()), this, SLOT(slotStopped())); connect(opp, SIGNAL(message(const QString&)), this, SLOT(slotPlayerMessage(const QString&))); connect(opp, SIGNAL(nextRound()), this, SLOT(slotNextRound())); connect(this, SIGNAL(sendText(const QString&)), opp, SLOT(sendMessage(const QString&))); /* * create game board. */ if(game) delete game; if(rules==ENGLISH) { game = new ECheckers(skill); } else { game = new RCheckers(skill); } // board reset_board(0); draw_board(); if(m_notation) drawNotation(); begin_game(true); } void myView::begin_game(bool white) { // other gui m_white.rounds->setText("0"); m_black.rounds->setText("0"); m_rules->setText(PdnPreview::typeToString(game->type())); // pdn pdnEvent = APPNAME" Game"; pdnSite = m_player->opponent()->site(); pdnDate = QDate::currentDate().toString("yyyy.MM.dd"); pdnResult= "*"; /**** if(isNetworkGame()) pdnMode = "TC"; else pdnMode = "OTB"; */ /* * go! */ // determine last player. myPlayer* last_player = m_player; if(white) { // select white if(m_player->isWhite()) last_player = m_player->opponent(); } else { // select black if(!m_player->isWhite()) last_player = m_player->opponent(); } m_game_over = false; m_aborted = false; m_current = last_player; // setup names if(m_player->isWhite()) { m_white.name->setText(m_player->name()); m_black.name->setText(m_player->opponent()->name()); } else { m_white.name->setText(m_player->opponent()->name()); m_black.name->setText(m_player->name()); } m_player->opponent()->sendNextRound(); // go! if(isNetworkGame()) slotMoveDone(QString::null); else slotMoveDone(game->toString(true)); } void myView::slotStopped() { stop_game(isNetworkGame() ? tr("Connection closed.") : QString::null); } void myView::setColorWhite(bool b) { if(b) { xpmMan1 = xpmManWhite; xpmMan2 = xpmManBlack; xpmKing1= xpmKingWhite; xpmKing2= xpmKingBlack; } else { xpmMan1 = xpmManBlack; xpmMan2 = xpmManWhite; xpmKing1= xpmKingBlack; xpmKing2= xpmKingWhite; } } bool myView::check_game_over() { if(m_game_over) // no further checks return true; m_game_over = true; bool player_can = game->checkMove1() || game->checkCapture1(); bool opp_can = game->checkMove2() || game->checkCapture2(); // player cannot go but opponent can -> player lost. if(!player_can && opp_can) { you_won(false); return m_game_over; } // player can go but opponent cannot -> player won. if(player_can && !opp_can) { you_won(true); return m_game_over; } // neither of the player can go -> draw. if(!player_can && !opp_can) { m_status->setText(tr("Drawn game.")); pdnResult = "1/2-1/2"; return m_game_over; } m_game_over = false; return m_game_over; } void myView::slotClick(int fieldNumber) { if(m_game_over || m_aborted) return; bool select = false; QString err_msg; if(!m_current->fieldClicked(fieldNumber, &select, err_msg)) setError(tr("Invalid move.")+"\n"+err_msg, ERR_TIMEOUT); else { for(int i=0; i<32; i++) if(i==fieldNumber) field[i]->showFrame(select); else field[i]->showFrame(false); } } void myView::slotShowNotation(bool b) { m_notation = b; if(b) drawNotation(); else for(int i=0; i<32; i++) field[i]->setLabel(""); } void myView::newGame(myPlayer* first, myPlayer* second, int skill) { if(m_player) { delete m_player; delete m_player->opponent(); } setColorWhite(first->isWhite()); pdnRound = "1"; init_game(first, second, skill, second->rules()); } void myView::undo() { if(isNetworkGame()) return; m_current->undo(); draw_board(); emit enableUndo(false); } void myView::getPdn(Pdn* pdn) { pdn->set(Pdn::Event, pdnEvent); pdn->set(Pdn::Site, pdnSite); pdn->set(Pdn::Date, pdnDate); pdn->set(Pdn::Round, pdnRound); pdn->set(Pdn::Result,pdnResult); pdn->set(Pdn::Type, QString::number(game->type())); pdn->set(Pdn::White, m_white.name->text()); pdn->set(Pdn::Black, m_black.name->text()); // active player pdn->setWhite(m_current->isWhite()); //aw?? pdn->setWhite(m_player->isWhite()); for(int i=0; i<32; i++) pdn->setItem(i, game->item(i)); } void myView::openGame(Pdn* pdn, bool board_only) { if(board_only) { int board[32]; for(int i=0; i<32; i++) board[i] = pdn->item(i); reset_board(board); draw_board(); begin_game(pdn->isWhite()); } /* int rules = 0; for(int i=0; i<32; i++) setupBoard[i] = pdn->item(i); setColorWhite(pdn->isWhite()); pdnEvent = pdn->get(Pdn::Event); pdnSite = pdn->get(Pdn::Site); pdnDate = pdn->get(Pdn::Date); pdnRound = pdn->get(Pdn::Round); pdnResult = pdn->get(Pdn::Result); m_white->setText(pdn->get(Pdn::White)); m_black->setText(pdn->get(Pdn::Black)); rules = pdn->get(Pdn::Type).toInt(); if(rules != ENGLISH && rules != RUSSIAN) rules = game->type(); // local int skill = 0; // parse opponents name to set skill properly QString p; if(pdn->isWhite()) p = m_black->text(); else p = m_white->text(); // aha, kcheckers saved game, try to get kcheckers skill level if(p.startsWith(APPNAME)) { int pos = p.findRev('('); skill = p.mid(pos+1, p.length()-(pos+2)).toInt(); } if(skill == 0) skill = game->getLevel(); emit working(false); startGame(rules, skill); m_white->setText(pdn->get(Pdn::White)); m_black->setText(pdn->get(Pdn::Black)); */ } void myView::slotNextRound() { if(m_aborted) return; m_player->setWhite(!m_player->isWhite()); m_player->opponent()->setWhite(!m_player->isWhite()); //aw?? m_player->opponent()->sendNextRound(); setColorWhite(m_player->isWhite()); reset_board(0); draw_board(); QString black = m_black.rounds->text(); QString white = m_white.rounds->text(); pdnRound = QString::number(pdnRound.toInt()+1); begin_game(true); m_white.rounds->setText(black); m_black.rounds->setText(white); } void myView::slotStopGame() { m_player->stop(); m_player->opponent()->stop(); } void myView::stop_game(const QString& msg) { m_game_over = true; //aw??? m_aborted = true; QString text(tr("Game aborted.")+(!msg.isEmpty() ? QString("\n") +msg : QString(""))); m_status->setText(text); emit working(false); /* if(!msg.isEmpty()) emit message(MSG_SYSTEM, text); */ } bool myView::isNetworkGame() const { if(!m_player) return false; return (m_player->isNetwork() || m_player->opponent()->isNetwork()); } bool myView::isServer() const { if(!m_player) return false; return (m_player->isServer() || m_player->opponent()->isServer()); } void myView::slotMoveDone(const QString& board_str) { emit working(false); // next player m_current = m_current->opponent(); m_current->sendMove(board_str); // draw stuff draw_board(); if(check_game_over()) return; /* * show who is next. */ if(m_current->isNetwork()) m_status->setText(tr("Waiting for opponent to move...")); else m_status->setText(tr("Go!")+"\n"+m_current->name()); if(m_current->isWhite()) { m_white.frm->setFrameStyle(QFrame::Box | QFrame::Plain); m_black.frm->setFrameStyle(QFrame::NoFrame); //m_white.frm->setPaletteBackgroundColor(green); //m_black.frm->unsetPalette(); } else { m_black.frm->setFrameStyle(QFrame::Box | QFrame::Plain); m_white.frm->setFrameStyle(QFrame::NoFrame); //m_black.frm->setPaletteBackgroundColor(green); //m_white.frm->unsetPalette(); } /* * NEXT */ // next player's turn if(!m_current->isHuman()) { emit working(true); } emit enableUndo(m_current->isUndoAvailable()); m_current->yourTurn(game); if(check_game_over()) emit working(false); } void myView::setError(const QString& text, int msec) { m_error->setText(text); QTimer::singleShot(msec, m_error, SLOT(clear())); } void myView::you_won(bool yes) { if(yes&&m_player->isWhite() || !yes&&!m_player->isWhite()) { pdnResult = "1-0"; // white wins m_status->setText(tr("White wins!")); m_white.rounds->setNum(m_white.rounds->text().toInt()+1); } else { pdnResult = "0-1"; // black wins m_status->setText(tr("Black wins!")); m_black.rounds->setNum(m_black.rounds->text().toInt()+1); } emit working(false); } void myView::slotPlayerMessage(const QString& msg) { emit message(MSG_OPPONENT, m_player->opponent()->name()+": "+msg); }