summaryrefslogtreecommitdiffstats
path: root/kbackgammon/engines/offline
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitc90c389a8a8d9d8661e9772ec4144c5cf2039f23 (patch)
tree6d8391395bce9eaea4ad78958617edb20c6a7573 /kbackgammon/engines/offline
downloadtdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.tar.gz
tdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegames@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kbackgammon/engines/offline')
-rw-r--r--kbackgammon/engines/offline/Makefile.am9
-rw-r--r--kbackgammon/engines/offline/kbgoffline.cpp810
-rw-r--r--kbackgammon/engines/offline/kbgoffline.h213
3 files changed, 1032 insertions, 0 deletions
diff --git a/kbackgammon/engines/offline/Makefile.am b/kbackgammon/engines/offline/Makefile.am
new file mode 100644
index 00000000..82d7a681
--- /dev/null
+++ b/kbackgammon/engines/offline/Makefile.am
@@ -0,0 +1,9 @@
+noinst_LTLIBRARIES = libkbgoffline.la
+
+libkbgoffline_la_SOURCES = kbgoffline.cpp
+
+INCLUDES= -I$(top_srcdir)/kbackgammon -I$(top_srcdir)/kbackgammon/engines \
+ $(all_includes)
+
+METASOURCES = AUTO
+
diff --git a/kbackgammon/engines/offline/kbgoffline.cpp b/kbackgammon/engines/offline/kbgoffline.cpp
new file mode 100644
index 00000000..920dc741
--- /dev/null
+++ b/kbackgammon/engines/offline/kbgoffline.cpp
@@ -0,0 +1,810 @@
+/* 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 <qlayout.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qtimer.h>
+#include <qspinbox.h>
+#include <qwhatsthis.h>
+#include <qlineedit.h>
+#include <qvbox.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
+ */
+ KBgStatus mGame[2];
+
+ /*
+ * Use the standard method of obtaining random numbers
+ */
+ KRandomSequence *mRandom;
+
+ /*
+ * Game actions
+ */
+ KAction *mNew, *mSwap;
+ KToggleAction *mEdit;
+
+ /*
+ * Player's names
+ */
+ QString 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
+ */
+ QLineEdit *mLe[2];
+
+};
+
+
+// == constructor, destructor and other ========================================
+
+/*
+ * Constructor
+ */
+KBgEngineOffline::KBgEngineOffline(QWidget *parent, QString *name, QPopupMenu *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, SLOT(newGame()), this);
+ d->mSwap = new KAction(i18n("&Swap Colors"), 0, this, SLOT(swapColors()), this);
+
+ d->mEdit = new KToggleAction(i18n("&Edit Mode"), 0, this,
+ 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 QTimer(this);
+ connect(ct, SIGNAL(timeout()), this, SLOT(done()));
+
+ /*
+ * internal statue variables
+ */
+ d->mRollFlag = d->mUndoFlag = d->mGameFlag = d->mDoneFlag = false;
+ connect(this, SIGNAL(allowCommand(int, bool)), this, 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
+ */
+ QVBox *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
+ */
+ QWidget *w = new QWidget(tc);
+ QGridLayout *gl = new QGridLayout(w, 2, 1, nb->spacingHint());
+
+ /*
+ * Group boxes
+ */
+ QGroupBox *gbn = new QGroupBox(i18n("Names"), w);
+
+ gl->addWidget(gbn, 0, 0);
+
+ gl = new QGridLayout(gbn, 2, 2, 20);
+
+ d->mLe[0] = new QLineEdit(d->mName[0], gbn);
+ d->mLe[1] = new QLineEdit(d->mName[1], gbn);
+
+ QLabel *lb[2];
+ lb[0] = new QLabel(i18n("First player:"), gbn);
+ lb[1] = new QLabel(i18n("Second player:"), gbn);
+
+ for (int i = 0; i < 2; i++) {
+ gl->addWidget(lb[i], i, 0);
+ gl->addWidget(d->mLe[i], i, 1);
+ }
+
+ QWhatsThis::add(d->mLe[0], i18n("Enter the name of the first player."));
+ QWhatsThis::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((QWidget *)parent(),
+ i18n("A game is currently in progress. "
+ "Starting a new one will terminate it."),
+ QString::null, 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.").
+ arg(d->mName[0]).arg(u).arg(d->mName[1]).arg(t));
+ }
+
+ if (u > t) {
+ emit infoText(i18n("%1 makes the first move.").arg(d->mName[0]));
+ d->mRoll = US;
+ } else {
+ emit infoText(i18n("%1 makes the first move.").arg(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").arg(d->mName[0]).arg(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;
+ QString *name;
+ QString 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, (QWidget *)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(QString *s)
+{
+ int index = 0;
+ QString 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;
+ }
+ QString 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(QString((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((QWidget *)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((QWidget *)parent(),
+ i18n("In the middle of a game. "
+ "Really quit?"), QString::null, 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 QString& cmd)
+{
+ emit infoText(i18n("Text commands are not yet working. "
+ "The command '%1' has been ignored.").arg(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").arg(d->mName[0]).arg(d->mName[1]));
+ } else {
+ d->mNew->setEnabled(true);
+ d->mSwap->setEnabled(true);
+ emit statText(i18n("%1 vs. %2").arg(d->mName[0]).arg(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
diff --git a/kbackgammon/engines/offline/kbgoffline.h b/kbackgammon/engines/offline/kbgoffline.h
new file mode 100644
index 00000000..db2bdc03
--- /dev/null
+++ b/kbackgammon/engines/offline/kbgoffline.h
@@ -0,0 +1,213 @@
+/* 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$
+
+*/
+
+#ifndef __KBGOFFLINE_H
+#define __KBGOFFLINE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <generic/kbgengine.h>
+
+#include "kbgboard.h"
+#include "kbgstatus.h"
+
+class KBgEngineOfflinePrivate;
+
+/**
+ *
+ * The interface of an offline backgammon engine. The engine is inherently
+ * stupid and doesn't play - it just manages the games betweeen two humans
+ * sitting at the same computer. Network enabled games will be part of the
+ * next generation engine (KBgNg).
+ *
+ * @short The offline backgammon engine
+ * @author Jens Hoefkens <jens@hoefkens.com>
+ *
+ */
+class KBgEngineOffline : public KBgEngine
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * Constructor
+ */
+ KBgEngineOffline(QWidget *parent = 0, QString *name = 0, QPopupMenu *pmenu = 0);
+
+ /**
+ * Destructor
+ */
+ virtual ~KBgEngineOffline();
+
+ /**
+ * Fills the engine-specific page into the notebook
+ */
+ virtual void getSetupPages(KDialogBase *nb);
+
+ /**
+ * Save new steup
+ */
+ virtual void setupOk();
+
+ /**
+ * Load default setup
+ */
+ virtual void setupDefault();
+
+ /**
+ * Cancel the changes to the setup
+ */
+ virtual void setupCancel();
+
+ /**
+ * Check with the engine if we can quit. This may require user
+ * interaction.
+ */
+ virtual bool queryClose();
+
+ /**
+ * About to be closed. Let the engine exit properly.
+ */
+ virtual bool queryExit();
+
+public slots:
+
+ /**
+ * Read user settings from the config file
+ */
+ virtual void readConfig();
+
+ /**
+ * Save user settings to the config file
+ */
+ virtual void saveConfig();
+
+ /**
+ * Roll dice for the player w
+ */
+ virtual void rollDice(const int w);
+
+ /**
+ * Double the cube of player w
+ */
+ virtual void doubleCube(const int w);
+
+ /**
+ * A move has been made on the board - see the board class
+ * for the format of the string s
+ */
+ virtual void handleMove(QString *s);
+
+ /**
+ * Undo the last move
+ */
+ virtual void undo();
+
+ /**
+ * Redo the last move
+ */
+ virtual void redo();
+
+ /**
+ * Roll dice for whoevers turn it is
+ */
+ virtual void roll();
+
+ /**
+ * Double the cube for whoevers can double right now
+ */
+ virtual void cube();
+
+ /**
+ * Reload the board to the last known sane state
+ */
+ virtual void load();
+
+ /**
+ * Commit a move
+ */
+ virtual void done();
+
+ /**
+ * Process the string cmd
+ */
+ virtual void handleCommand(const QString& cmd);
+
+ /**
+ * Start a new game.
+ */
+ virtual void newGame();
+ virtual bool haveNewGame() {return true;}
+
+
+protected slots:
+
+ /**
+ * Initialize the state descriptors game[0] and game[1]
+ */
+ void initGame();
+
+ /**
+ * Switch back and forth between edit and play mode
+ */
+ void toggleEditMode();
+
+ /**
+ * Store if cmd is allowed or not
+ */
+ void setAllowed(int cmd, bool f);
+
+ /**
+ * Swaps the used colors on the board
+ */
+ void swapColors();
+
+protected:
+
+ /**
+ * Returns a random integer between 1 and 6
+ */
+ int getRandom();
+
+ /**
+ * Set the dice for player w to a and b. Reload the board and determine the
+ * maximum number of moves
+ */
+ void rollDiceBackend(const int w, const int a, const int b);
+
+ /**
+ * Open a dialog to query for the name of player w. Return true unless
+ * the dialog was canceled.
+ */
+ bool queryPlayerName(int w);
+
+private:
+
+ KBgEngineOfflinePrivate *d;
+
+};
+
+#endif // __KBGOFFLINE_H