|
|
|
/* Yo Emacs, this -*- C++ -*-
|
|
|
|
|
|
|
|
Copyright (C) 1999-2001 Jens Hoefkens
|
|
|
|
jens@hoefkens.com
|
|
|
|
|
|
|
|
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
$Id$
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kbgoffline.moc"
|
|
|
|
#include "kbgoffline.h"
|
|
|
|
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqbuttongroup.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqspinbox.h>
|
|
|
|
#include <tqwhatsthis.h>
|
|
|
|
#include <tqlineedit.h>
|
|
|
|
#include <tqvbox.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kstdaction.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmainwindow.h>
|
|
|
|
#include <klineeditdlg.h>
|
|
|
|
#include <kaction.h>
|
|
|
|
#include <krandomsequence.h>
|
|
|
|
#include <ktabctl.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "version.h"
|
|
|
|
|
|
|
|
class KBgEngineOfflinePrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Various flags, representing the current status of the game
|
|
|
|
*/
|
|
|
|
bool mRollFlag, mUndoFlag, mDoneFlag, mCubeFlag, mGameFlag, mRedoFlag;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store two copies of the game: one backup and a working copy
|
|
|
|
*/
|
|
|
|
KBgtqStatus mGame[2];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the standard method of obtaining random numbers
|
|
|
|
*/
|
|
|
|
KRandomSequence *mRandom;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Game actions
|
|
|
|
*/
|
|
|
|
KAction *mNew, *mSwap;
|
|
|
|
KToggleAction *mEdit;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Player's names
|
|
|
|
*/
|
|
|
|
TQString mName[2];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Who did the last roll
|
|
|
|
*/
|
|
|
|
int mRoll;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* How many checkers to move
|
|
|
|
*/
|
|
|
|
int mMove;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Count the number of available undos
|
|
|
|
*/
|
|
|
|
int mUndo;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Entry fields for the names
|
|
|
|
*/
|
|
|
|
TQLineEdit *mLe[2];
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// == constructor, destructor and other ========================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Constructor
|
|
|
|
*/
|
|
|
|
KBgEngineOffline::KBgEngineOffline(TQWidget *parent, TQString *name, TQPopupMenu *pmenu)
|
|
|
|
: KBgEngine(parent, name, pmenu)
|
|
|
|
{
|
|
|
|
d = new KBgEngineOfflinePrivate();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get some entropy for the dice
|
|
|
|
*/
|
|
|
|
d->mRandom = new KRandomSequence;
|
|
|
|
d->mRandom->setSeed(0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create engine specific actions
|
|
|
|
*/
|
|
|
|
d->mNew = new KAction(i18n("&New Game..."), 0, this, TQT_SLOT(newGame()), this);
|
|
|
|
d->mSwap = new KAction(i18n("&Swap Colors"), 0, this, TQT_SLOT(swapColors()), this);
|
|
|
|
|
|
|
|
d->mEdit = new KToggleAction(i18n("&Edit Mode"), 0, this,
|
|
|
|
TQT_SLOT(toggleEditMode()), this);
|
|
|
|
d->mEdit->setChecked(false);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* create & initialize the menu
|
|
|
|
*/
|
|
|
|
d->mNew->plug(menu);
|
|
|
|
d->mEdit->plug(menu);
|
|
|
|
d->mSwap->plug(menu);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get standard board and set it
|
|
|
|
*/
|
|
|
|
initGame();
|
|
|
|
emit newState(d->mGame[0]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* initialize the commit timeout
|
|
|
|
*/
|
|
|
|
ct = new TQTimer(this);
|
|
|
|
connect(ct, TQT_SIGNAL(timeout()), this, TQT_SLOT(done()));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* internal statue variables
|
|
|
|
*/
|
|
|
|
d->mRollFlag = d->mUndoFlag = d->mGameFlag = d->mDoneFlag = false;
|
|
|
|
connect(this, TQT_SIGNAL(allowCommand(int, bool)), this, TQT_SLOT(setAllowed(int, bool)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Restore last stored settings
|
|
|
|
*/
|
|
|
|
readConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Destructor. The only child is the popup menu.
|
|
|
|
*/
|
|
|
|
KBgEngineOffline::~KBgEngineOffline()
|
|
|
|
{
|
|
|
|
saveConfig();
|
|
|
|
delete d->mRandom;
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// == configuration handling ===================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put the engine specific details in the setup dialog
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::getSetupPages(KDialogBase *nb)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Main Widget
|
|
|
|
*/
|
|
|
|
TQVBox *vbp = nb->addVBoxPage(i18n("Offline Engine"), i18n("Use this to configure the Offline engine"),
|
|
|
|
kapp->iconLoader()->loadIcon(PROG_NAME "_engine", KIcon::Desktop));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get a multi page work space
|
|
|
|
*/
|
|
|
|
KTabCtl *tc = new KTabCtl(vbp, "offline tabs");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Player names
|
|
|
|
*/
|
|
|
|
TQWidget *w = new TQWidget(tc);
|
|
|
|
TQGridLayout *gl = new TQGridLayout(w, 2, 1, nb->spacingHint());
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Group boxes
|
|
|
|
*/
|
|
|
|
TQGroupBox *gbn = new TQGroupBox(i18n("Names"), w);
|
|
|
|
|
|
|
|
gl->addWidget(gbn, 0, 0);
|
|
|
|
|
|
|
|
gl = new TQGridLayout(gbn, 2, 2, 20);
|
|
|
|
|
|
|
|
d->mLe[0] = new TQLineEdit(d->mName[0], gbn);
|
|
|
|
d->mLe[1] = new TQLineEdit(d->mName[1], gbn);
|
|
|
|
|
|
|
|
TQLabel *lb[2];
|
|
|
|
lb[0] = new TQLabel(i18n("First player:"), gbn);
|
|
|
|
lb[1] = new TQLabel(i18n("Second player:"), gbn);
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
gl->addWidget(lb[i], i, 0);
|
|
|
|
gl->addWidget(d->mLe[i], i, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQWhatsThis::add(d->mLe[0], i18n("Enter the name of the first player."));
|
|
|
|
TQWhatsThis::add(d->mLe[1], i18n("Enter the name of the second player."));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Done with the page, put it in
|
|
|
|
*/
|
|
|
|
gl->activate();
|
|
|
|
tc->addTab(w, i18n("&Player Names"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called when the setup dialog is positively closed
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::setupOk()
|
|
|
|
{
|
|
|
|
d->mName[0] = d->mLe[0]->text();
|
|
|
|
d->mName[1] = d->mLe[1]->text();
|
|
|
|
}
|
|
|
|
void KBgEngineOffline::setupDefault()
|
|
|
|
{
|
|
|
|
d->mName[0] = i18n("South");
|
|
|
|
d->mName[1] = i18n("North");
|
|
|
|
}
|
|
|
|
void KBgEngineOffline::setupCancel()
|
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Restore settings
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::readConfig()
|
|
|
|
{
|
|
|
|
KConfig* config = kapp->config();
|
|
|
|
config->setGroup("offline engine");
|
|
|
|
|
|
|
|
d->mName[0] = config->readEntry("player-one", i18n("South")); // same as above
|
|
|
|
d->mName[1] = config->readEntry("player-two", i18n("North")); // same as above
|
|
|
|
cl = config->readNumEntry("timer", 2500);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save the engine specific settings
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::saveConfig()
|
|
|
|
{
|
|
|
|
KConfig* config = kapp->config();
|
|
|
|
config->setGroup("offline engine");
|
|
|
|
|
|
|
|
config->writeEntry("player-one", d->mName[0] );
|
|
|
|
config->writeEntry("player-two", d->mName[1]);
|
|
|
|
config->writeEntry("timer", cl);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// == start and init games =====================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start a new game.
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::newGame()
|
|
|
|
{
|
|
|
|
int u = 0;
|
|
|
|
int t = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is a game running we warn the user first
|
|
|
|
*/
|
|
|
|
if (d->mGameFlag && (KMessageBox::warningYesNo((TQWidget *)parent(),
|
|
|
|
i18n("A game is currently in progress. "
|
|
|
|
"Starting a new one will terminate it."),
|
|
|
|
TQString(), i18n("Start New Game"),
|
|
|
|
i18n("Continue Old Game"))
|
|
|
|
== KMessageBox::No))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Separate from the previous game
|
|
|
|
*/
|
|
|
|
emit infoText("<br/><br/><br/>");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get player's names - user can still cancel
|
|
|
|
*/
|
|
|
|
if (!queryPlayerName(US) || !queryPlayerName(THEM))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* let the games begin
|
|
|
|
*/
|
|
|
|
d->mGameFlag = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the board
|
|
|
|
*/
|
|
|
|
initGame();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out who starts by rolling
|
|
|
|
*/
|
|
|
|
while (u == t) {
|
|
|
|
u = getRandom();
|
|
|
|
t = getRandom();
|
|
|
|
emit infoText(i18n("%1 rolls %2, %3 rolls %4.").
|
|
|
|
tqarg(d->mName[0]).tqarg(u).tqarg(d->mName[1]).tqarg(t));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (u > t) {
|
|
|
|
emit infoText(i18n("%1 makes the first move.").tqarg(d->mName[0]));
|
|
|
|
d->mRoll = US;
|
|
|
|
} else {
|
|
|
|
emit infoText(i18n("%1 makes the first move.").tqarg(d->mName[1]));
|
|
|
|
d->mRoll = THEM;
|
|
|
|
int n = u; u = t; t = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set the dice and tell the board
|
|
|
|
*/
|
|
|
|
rollDiceBackend(d->mRoll, u, t);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* tell the user
|
|
|
|
*/
|
|
|
|
emit statText(i18n("%1 vs. %2").tqarg(d->mName[0]).tqarg(d->mName[1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the state descriptors mGame[0|1]
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::initGame()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* nobody rolled yet
|
|
|
|
*/
|
|
|
|
d->mRoll = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set up a standard game
|
|
|
|
*/
|
|
|
|
d->mGame[0].setCube(1, true, true);
|
|
|
|
d->mGame[0].setDirection(+1);
|
|
|
|
d->mGame[0].setColor(+1);
|
|
|
|
for (int i = 1; i < 25; i++)
|
|
|
|
d->mGame[0].setBoard(i, US, 0);
|
|
|
|
d->mGame[0].setBoard( 1, US, 2); d->mGame[0].setBoard( 6, THEM, 5);
|
|
|
|
d->mGame[0].setBoard( 8, THEM, 3); d->mGame[0].setBoard(12, US, 5);
|
|
|
|
d->mGame[0].setBoard(13, THEM, 5); d->mGame[0].setBoard(17, US, 3);
|
|
|
|
d->mGame[0].setBoard(19, US, 5); d->mGame[0].setBoard(24, THEM, 2);
|
|
|
|
d->mGame[0].setHome(US, 0); d->mGame[0].setHome(THEM, 0);
|
|
|
|
d->mGame[0].setBar(US, 0); d->mGame[0].setBar(THEM, 0);
|
|
|
|
d->mGame[0].setDice(US , 0, 0); d->mGame[0].setDice(US , 1, 0);
|
|
|
|
d->mGame[0].setDice(THEM, 0, 0); d->mGame[0].setDice(THEM, 1, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* save backup of the game state
|
|
|
|
*/
|
|
|
|
d->mGame[1] = d->mGame[0];
|
|
|
|
|
|
|
|
emit allowCommand(Load, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open a dialog to query for the name of player w. Return true unless
|
|
|
|
* the dialog was canceled.
|
|
|
|
*/
|
|
|
|
bool KBgEngineOffline::queryPlayerName(int w)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
TQString *name;
|
|
|
|
TQString text;
|
|
|
|
|
|
|
|
if (w == US) {
|
|
|
|
name = &d->mName[0];
|
|
|
|
text = i18n("Please enter the nickname of the player whose home\n"
|
|
|
|
"is in the lower half of the board:");
|
|
|
|
} else {
|
|
|
|
name = &d->mName[1];
|
|
|
|
text = i18n("Please enter the nickname of the player whose home\n"
|
|
|
|
"is in the upper half of the board:");
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
*name = KLineEditDlg::getText(text, *name, &ret, (TQWidget *)parent());
|
|
|
|
if (!ret) break;
|
|
|
|
|
|
|
|
} while (name->isEmpty());
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// == moving ===================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Finish the last move - called by the timer and directly by the used
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::done()
|
|
|
|
{
|
|
|
|
ct->stop();
|
|
|
|
|
|
|
|
emit allowMoving(false);
|
|
|
|
emit allowCommand(Done, false);
|
|
|
|
emit allowCommand(Undo, false);
|
|
|
|
|
|
|
|
if (abs(d->mGame[0].home(d->mRoll)) == 15) {
|
|
|
|
|
|
|
|
emit infoText(i18n("%1 wins the game. Congratulations!").
|
|
|
|
arg((d->mRoll == US) ? d->mName[0] : d->mName[1]));
|
|
|
|
d->mGameFlag = false;
|
|
|
|
emit allowCommand(Roll, false);
|
|
|
|
emit allowCommand(Cube, false);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
emit allowCommand(Roll, true);
|
|
|
|
if (d->mGame[0].cube((d->mRoll == US ? THEM : US)) > 0) {
|
|
|
|
|
|
|
|
d->mGame[0].setDice(US , 0, 0); d->mGame[0].setDice(US , 1, 0);
|
|
|
|
d->mGame[0].setDice(THEM, 0, 0); d->mGame[0].setDice(THEM, 1, 0);
|
|
|
|
|
|
|
|
emit newState(d->mGame[0]);
|
|
|
|
emit getState(&d->mGame[0]);
|
|
|
|
|
|
|
|
d->mGame[1] = d->mGame[0];
|
|
|
|
|
|
|
|
emit infoText(i18n("%1, please roll or double.").
|
|
|
|
arg((d->mRoll == THEM) ? d->mName[0] : d->mName[1]));
|
|
|
|
emit allowCommand(Cube, true);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
roll();
|
|
|
|
emit allowCommand(Cube, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Undo the last move
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::undo()
|
|
|
|
{
|
|
|
|
ct->stop();
|
|
|
|
|
|
|
|
d->mRedoFlag = true;
|
|
|
|
++d->mUndo;
|
|
|
|
|
|
|
|
emit allowMoving(true);
|
|
|
|
emit allowCommand(Done, false);
|
|
|
|
emit allowCommand(Redo, true);
|
|
|
|
emit undoMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Redo the last move
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::redo()
|
|
|
|
{
|
|
|
|
--d->mUndo;
|
|
|
|
emit redoMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Take the move string and make the changes on the working copy
|
|
|
|
* of the state.
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::handleMove(TQString *s)
|
|
|
|
{
|
|
|
|
int index = 0;
|
|
|
|
TQString t = s->mid(index, s->find(' ', index));
|
|
|
|
index += 1 + t.length();
|
|
|
|
int moves = t.toInt();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allow undo and possibly start the commit timer
|
|
|
|
*/
|
|
|
|
d->mRedoFlag &= ((moves < d->mMove) && (d->mUndo > 0));
|
|
|
|
emit allowCommand(Undo, moves > 0);
|
|
|
|
emit allowCommand(Redo, d->mRedoFlag);
|
|
|
|
emit allowCommand(Done, moves == d->mMove);
|
|
|
|
if (moves == d->mMove && cl) {
|
|
|
|
emit allowMoving(false);
|
|
|
|
ct->start(cl, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Apply moves to d->mGame[1] and store results in d->mGame[0]
|
|
|
|
*/
|
|
|
|
d->mGame[0] = d->mGame[1];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* process each individual move
|
|
|
|
*/
|
|
|
|
for (int i = 0; i < moves; i++) {
|
|
|
|
bool kick = false;
|
|
|
|
t = s->mid(index, s->find(' ', index) - index);
|
|
|
|
index += 1 + t.length();
|
|
|
|
char c = '-';
|
|
|
|
if (t.contains('+')) {
|
|
|
|
c = '+';
|
|
|
|
kick = true;
|
|
|
|
}
|
|
|
|
TQString r = t.left(t.find(c));
|
|
|
|
if (r.contains("bar")) {
|
|
|
|
d->mGame[0].setBar(d->mRoll, abs(d->mGame[0].bar(d->mRoll)) - 1);
|
|
|
|
} else {
|
|
|
|
int from = r.toInt();
|
|
|
|
d->mGame[0].setBoard(from, d->mRoll, abs(d->mGame[0].board(from)) - 1);
|
|
|
|
}
|
|
|
|
t.remove(0, 1 + r.length());
|
|
|
|
if (t.contains("off")) {
|
|
|
|
d->mGame[0].setHome(d->mRoll, abs(d->mGame[0].home(d->mRoll)) + 1);
|
|
|
|
} else {
|
|
|
|
int to = t.toInt();
|
|
|
|
if (kick) {
|
|
|
|
d->mGame[0].setBoard(to, d->mRoll, 0);
|
|
|
|
int el = ((d->mRoll == US) ? THEM : US);
|
|
|
|
d->mGame[0].setBar(el, abs(d->mGame[0].bar(el)) + 1);
|
|
|
|
}
|
|
|
|
d->mGame[0].setBoard(to, d->mRoll, abs(d->mGame[0].board(to)) + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// == dice & rolling ===========================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Roll random dice for the player whose turn it is
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::roll()
|
|
|
|
{
|
|
|
|
rollDice((d->mRoll == US) ? THEM : US);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If possible, roll random dice for player w
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::rollDice(const int w)
|
|
|
|
{
|
|
|
|
if ((d->mRoll != w) && d->mRollFlag) {
|
|
|
|
rollDiceBackend(w, getRandom(), getRandom());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
emit infoText(i18n("It's not your turn to roll!"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return a random integer between 1 and 6. According to the man
|
|
|
|
* page of rand(), this is the way to go...
|
|
|
|
*/
|
|
|
|
int KBgEngineOffline::getRandom()
|
|
|
|
{
|
|
|
|
return 1+d->mRandom->getLong(6);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the dice for player w to a and b. Reload the board and determine the
|
|
|
|
* maximum number of moves
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::rollDiceBackend(const int w, const int a, const int b)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This is a special case that stems from leaving the edit
|
|
|
|
* mode.
|
|
|
|
*/
|
|
|
|
if (a == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the dice and tel the board about the new state
|
|
|
|
*/
|
|
|
|
d->mGame[0].setDice(w, 0, a);
|
|
|
|
d->mGame[0].setDice(w, 1, b);
|
|
|
|
d->mGame[0].setDice((w == US) ? THEM : US, 0, 0);
|
|
|
|
d->mGame[0].setDice((w == US) ? THEM : US, 1, 0);
|
|
|
|
d->mGame[0].setTurn(w);
|
|
|
|
|
|
|
|
d->mGame[1] = d->mGame[0];
|
|
|
|
|
|
|
|
d->mRoll = w;
|
|
|
|
emit newState(d->mGame[0]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No more roling until Done and no Undo yet
|
|
|
|
*/
|
|
|
|
emit allowCommand(Undo, false);
|
|
|
|
emit allowCommand(Roll, false);
|
|
|
|
d->mRedoFlag = false;
|
|
|
|
d->mUndo = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tell the players how many checkers to move
|
|
|
|
*/
|
|
|
|
switch (d->mMove = d->mGame[0].moves()) {
|
|
|
|
case -1:
|
|
|
|
emit infoText(i18n("Game over!"));
|
|
|
|
d->mGameFlag = false;
|
|
|
|
emit allowCommand(Roll, false);
|
|
|
|
emit allowCommand(Cube, false);
|
|
|
|
emit allowMoving(false);
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
emit infoText(i18n("%1, you cannot move.").
|
|
|
|
arg((w == US) ? d->mName[0] : d->mName[1]));
|
|
|
|
if (cl)
|
|
|
|
ct->start(cl, true);
|
|
|
|
emit allowMoving(false);
|
|
|
|
break;
|
|
|
|
// case 1:
|
|
|
|
default:
|
|
|
|
emit infoText(TQString((w == US) ? d->mName[0] : d->mName[1]) +
|
|
|
|
i18n(", please move 1 piece.",", please move %n pieces.",d->mMove));
|
|
|
|
emit allowMoving(true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// == cube =====================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Double the cube for the player that can double - asks player
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::cube()
|
|
|
|
{
|
|
|
|
int w = ((d->mRoll == US) ? THEM : US);
|
|
|
|
|
|
|
|
if (d->mRollFlag && d->mGame[0].cube(w) > 0) {
|
|
|
|
emit allowCommand(Cube, false);
|
|
|
|
if (KMessageBox::questionYesNo((TQWidget *)parent(),
|
|
|
|
i18n("%1 has doubled. %2, do you accept the double?").
|
|
|
|
arg((w == THEM) ? d->mName[1] : d->mName[0]).
|
|
|
|
arg((w == US) ? d->mName[1] : d->mName[0]),
|
|
|
|
i18n("Doubling"), i18n("Accept"), i18n("Reject")) != KMessageBox::Yes) {
|
|
|
|
d->mGameFlag = false;
|
|
|
|
emit allowCommand(Roll, false);
|
|
|
|
emit allowCommand(Cube, false);
|
|
|
|
emit infoText(i18n("%1 wins the game. Congratulations!").
|
|
|
|
arg((w == US) ? d->mName[0] : d->mName[1]));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit infoText(i18n("%1 has accepted the double. The game continues.").
|
|
|
|
arg((w == THEM) ? d->mName[0] : d->mName[1]));
|
|
|
|
|
|
|
|
if (d->mGame[0].cube(US)*d->mGame[0].cube(THEM) > 0)
|
|
|
|
d->mGame[0].setCube(2, w == THEM, w == US);
|
|
|
|
else
|
|
|
|
d->mGame[0].setCube(2*d->mGame[0].cube(w), w == THEM, w == US);
|
|
|
|
|
|
|
|
emit newState(d->mGame[0]);
|
|
|
|
emit getState(&d->mGame[0]);
|
|
|
|
|
|
|
|
d->mGame[1] = d->mGame[0];
|
|
|
|
|
|
|
|
roll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Double the cube for player w
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::doubleCube(const int)
|
|
|
|
{
|
|
|
|
cube();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// == various slots & functions ================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check with the user if we should really quit in the middle of a
|
|
|
|
* game.
|
|
|
|
*/
|
|
|
|
bool KBgEngineOffline::queryClose()
|
|
|
|
{
|
|
|
|
if (!d->mGameFlag)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
switch (KMessageBox::warningContinueCancel((TQWidget *)parent(),
|
|
|
|
i18n("In the middle of a game. "
|
|
|
|
"Really quit?"), TQString(), KStdGuiItem::quit())) {
|
|
|
|
case KMessageBox::Continue :
|
|
|
|
return TRUE;
|
|
|
|
case KMessageBox::Cancel :
|
|
|
|
return FALSE;
|
|
|
|
default: // cancel
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Quitting is fine at any time
|
|
|
|
*/
|
|
|
|
bool KBgEngineOffline::queryExit()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle textual commands. Right now, all commands are ignored
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::handleCommand(const TQString& cmd)
|
|
|
|
{
|
|
|
|
emit infoText(i18n("Text commands are not yet working. "
|
|
|
|
"The command '%1' has been ignored.").tqarg(cmd));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Load the last known sane state of the board
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::load()
|
|
|
|
{
|
|
|
|
if (d->mEdit->isChecked())
|
|
|
|
emit newState(d->mGame[1]);
|
|
|
|
else {
|
|
|
|
// undo up to four moves
|
|
|
|
undo();
|
|
|
|
undo();
|
|
|
|
undo();
|
|
|
|
undo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store if cmd is allowed or not
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::setAllowed(int cmd, bool f)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case Roll:
|
|
|
|
d->mRollFlag = f;
|
|
|
|
return;
|
|
|
|
case Undo:
|
|
|
|
d->mUndoFlag = f;
|
|
|
|
return;
|
|
|
|
case Cube:
|
|
|
|
d->mCubeFlag = f;
|
|
|
|
return;
|
|
|
|
case Done:
|
|
|
|
d->mDoneFlag = f;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Swaps the used colors on the board
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::swapColors()
|
|
|
|
{
|
|
|
|
d->mGame[1].setDice(US, 0, d->mGame[0].dice(US, 0));
|
|
|
|
d->mGame[1].setDice(US, 1, d->mGame[0].dice(US, 1));
|
|
|
|
d->mGame[1].setDice(THEM, 0, d->mGame[0].dice(THEM, 0));
|
|
|
|
d->mGame[1].setDice(THEM, 1, d->mGame[0].dice(THEM, 1));
|
|
|
|
d->mGame[1].setColor(d->mGame[1].color(THEM), US);
|
|
|
|
emit newState(d->mGame[1]);
|
|
|
|
emit getState(&d->mGame[1]);
|
|
|
|
d->mGame[0] = d->mGame[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Switch back and forth between edit and play mode
|
|
|
|
*/
|
|
|
|
void KBgEngineOffline::toggleEditMode()
|
|
|
|
{
|
|
|
|
emit setEditMode(d->mEdit->isChecked());
|
|
|
|
if (d->mEdit->isChecked()) {
|
|
|
|
ct->stop();
|
|
|
|
d->mNew->setEnabled(false);
|
|
|
|
d->mSwap->setEnabled(false);
|
|
|
|
emit allowCommand(Undo, false);
|
|
|
|
emit allowCommand(Roll, false);
|
|
|
|
emit allowCommand(Done, false);
|
|
|
|
emit allowCommand(Cube, false);
|
|
|
|
emit statText(i18n("%1 vs. %2 - Edit Mode").tqarg(d->mName[0]).tqarg(d->mName[1]));
|
|
|
|
} else {
|
|
|
|
d->mNew->setEnabled(true);
|
|
|
|
d->mSwap->setEnabled(true);
|
|
|
|
emit statText(i18n("%1 vs. %2").tqarg(d->mName[0]).tqarg(d->mName[1]));
|
|
|
|
emit getState(&d->mGame[1]);
|
|
|
|
d->mGame[0] = d->mGame[1];
|
|
|
|
emit allowCommand(Done, d->mDoneFlag);
|
|
|
|
emit allowCommand(Cube, d->mCubeFlag);
|
|
|
|
emit allowCommand(Undo, d->mUndoFlag);
|
|
|
|
emit allowCommand(Roll, d->mRollFlag);
|
|
|
|
int w =((d->mGame[0].dice(US, 0) && d->mGame[0].dice(US, 1)) ? US : THEM);
|
|
|
|
rollDiceBackend(w, d->mGame[0].dice(w, 0), d->mGame[0].dice(w, 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// EOF
|