summaryrefslogtreecommitdiffstats
path: root/libksirtet/common
diff options
context:
space:
mode:
Diffstat (limited to 'libksirtet/common')
-rw-r--r--libksirtet/common/Makefile.am28
-rw-r--r--libksirtet/common/README1
-rw-r--r--libksirtet/common/ai.cpp356
-rw-r--r--libksirtet/common/ai.h122
-rw-r--r--libksirtet/common/board.cpp286
-rw-r--r--libksirtet/common/board.h75
-rw-r--r--libksirtet/common/commonprefs.kcfgc9
-rw-r--r--libksirtet/common/factory.cpp28
-rw-r--r--libksirtet/common/factory.h36
-rw-r--r--libksirtet/common/field.cpp243
-rw-r--r--libksirtet/common/field.h68
-rw-r--r--libksirtet/common/highscores.cpp60
-rw-r--r--libksirtet/common/highscores.h20
-rw-r--r--libksirtet/common/inter.cpp150
-rw-r--r--libksirtet/common/inter.h62
-rw-r--r--libksirtet/common/libksirtet2.kcfg36
-rw-r--r--libksirtet/common/main.cpp60
-rw-r--r--libksirtet/common/main.h22
-rw-r--r--libksirtet/common/misc_ui.cpp194
-rw-r--r--libksirtet/common/misc_ui.h81
-rw-r--r--libksirtet/common/settings.cpp54
-rw-r--r--libksirtet/common/settings.h28
-rw-r--r--libksirtet/common/types.cpp16
-rw-r--r--libksirtet/common/types.h26
24 files changed, 2061 insertions, 0 deletions
diff --git a/libksirtet/common/Makefile.am b/libksirtet/common/Makefile.am
new file mode 100644
index 00000000..1c11265d
--- /dev/null
+++ b/libksirtet/common/Makefile.am
@@ -0,0 +1,28 @@
+INCLUDES = -I$(top_builddir)/libksirtet -I$(top_srcdir)/libksirtet -I$(srcdir)/../base -I$(top_srcdir)/libkdegames/highscore -I$(top_srcdir)/libkdegames $(all_includes)
+
+# Don't compile with hidden symbols since we are a library.
+if disable_VISIBILITY
+KDE_CXXFLAGS = -fvisibility=default
+endif
+
+noinst_LTLIBRARIES = libksirtetcommon.la
+libksirtetcommon_la_LDFLAGS = $(all_libraries) -no-undefined
+libksirtetcommon_la_DEPENDENCIES = $(LIB_KDEGAMES_DEP) $(top_builddir)/libksirtet/lib/libksirtetmultiplayers.la $(top_builddir)/libksirtet/base/libksirtetbase.la
+libksirtetcommon_la_LIBADD = $(LIB_KDEGAMES) $(top_builddir)/libksirtet/lib/libksirtetmultiplayers.la $(top_builddir)/libksirtet/base/libksirtetbase.la
+
+noinst_HEADERS = types.h factory.h misc_ui.h highscores.h \
+ board.h ai.h field.h settings.h inter.h main.h
+libksirtetcommon_la_SOURCES = types.cpp factory.cpp misc_ui.cpp \
+ highscores.cpp \
+ board.cpp ai.cpp field.cpp settings.cpp \
+ inter.cpp main.cpp commonprefs.kcfgc
+METASOURCES = misc_ui.moc board.moc ai.moc field.moc \
+ settings.moc inter.moc main.moc
+
+ai.lo: ../base/baseprefs.h
+board.lo: ../base/baseprefs.h
+commonprefs.lo: ../base/baseprefs.h
+field.lo: ../base/baseprefs.h
+inter.lo: ../base/baseprefs.h
+misc_ui.lo: ../base/baseprefs.h
+
diff --git a/libksirtet/common/README b/libksirtet/common/README
new file mode 100644
index 00000000..03ffa387
--- /dev/null
+++ b/libksirtet/common/README
@@ -0,0 +1 @@
+This directory contains code shared between ksirtet and kfouleggs.
diff --git a/libksirtet/common/ai.cpp b/libksirtet/common/ai.cpp
new file mode 100644
index 00000000..bc1c6722
--- /dev/null
+++ b/libksirtet/common/ai.cpp
@@ -0,0 +1,356 @@
+#include "ai.h"
+#include "ai.moc"
+
+#include <assert.h>
+
+#include <qlabel.h>
+#include <qhbox.h>
+#include <qvbox.h>
+#include <qlayout.h>
+#include <qgrid.h>
+#include <qwhatsthis.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kapplication.h>
+
+#include "commonprefs.h"
+#include "board.h"
+#include "base/piece.h"
+#include "base/factory.h"
+
+
+//-----------------------------------------------------------------------------
+AIPiece::AIPiece()
+ : _current(0)
+{}
+
+AIPiece::~AIPiece()
+{
+ delete _current;
+}
+
+void AIPiece::init(const Piece *piece, Board *b)
+{
+ _piece = piece;
+ _board = b;
+ if ( _current==0 ) _current = new Piece;
+ reset();
+}
+
+void AIPiece::reset()
+{
+ curPos = 0;
+ curRot = 0;
+ if (_piece) _current->copy(_piece);
+// else _current->generateNext(0);
+ nbRot = _current->nbConfigurations() - 1;
+ nbPos = _board->matrix().width() - _current->size().first + 1;
+}
+
+bool AIPiece::increment()
+{
+ curPos++;
+ if ( curPos==nbPos ) {
+ if ( curRot==nbRot ) {
+// if ( _piece || _current->type()==Piece::info().nbTypes() ) {
+ reset();
+ return false;
+// }
+// _current->generateNext(_current->type()+1);
+// nbRot = _current->nbConfigurations() - 1;
+// curRot = 0;
+ }
+ _current->rotate(true, QPoint(0, 0));
+ nbPos = _board->matrix().width() - _current->size().first + 1;
+ curRot++;
+ curPos = 0;
+ }
+ return true;
+}
+
+bool AIPiece::place()
+{
+ if ( curRot==3 ) {
+ if ( !_board->rotateRight() ) return false;
+ } else for (uint i=0; i<curRot; i++)
+ if ( !_board->rotateLeft() ) return false;
+ curDec = curPos - _board->currentPos().first - _current->min().first;
+ if ( curDec!=0 && _board->moveRight(curDec)!=(uint)kAbs(curDec) )
+ return false;
+ _board->dropDown();
+ return !_board->isGameOver();
+}
+
+//-----------------------------------------------------------------------------
+const AI::Data AI::LastData = { 0, 0, 0, false, 0 };
+
+AI::AI(uint tTime, uint oTime, const Data *DATA)
+ : timer(this), thinkTime(tTime), orderTime(oTime), stopped(false),
+ board(0)
+{
+ connect(&timer, SIGNAL(timeout()), SLOT(timeout()));
+
+ for (uint i=0; DATA[i].name; i++) {
+ Element element;
+ element.coefficient = 0.;
+ element.trigger = 0;
+ element.data = &DATA[i];
+ _elements.append(element);
+ }
+ settingsChanged();
+}
+
+void AI::resizePieces(uint size)
+{
+ uint oldSize = pieces.size();
+ for (uint i=size; i<oldSize; i++) delete pieces[i];
+ pieces.resize(size);
+ for (uint i=oldSize; i<size; i++) pieces[i] = new AIPiece;
+}
+
+AI::~AI()
+{
+ delete board;
+ resizePieces(0);
+}
+
+void AI::initThink()
+{
+ board->copy(*main);
+}
+
+void AI::launch(Board *m)
+{
+ main = m;
+ if ( board==0 )
+ board = static_cast<Board *>(bfactory->createBoard(false, 0));
+
+ pieces[0]->init(main->currentPiece(), board); // current
+ if ( pieces.size()>=2 ) pieces[1]->init(main->nextPiece(), board); // next
+
+ state = Thinking;
+ hasBestPoints = false;
+ startTimer();
+}
+
+void AI::stop()
+{
+ timer.stop();
+ stopped = true;
+}
+
+void AI::start()
+{
+ if (stopped) {
+ startTimer();
+ stopped = false;
+ }
+}
+
+void AI::startTimer()
+{
+ switch (state) {
+ case Thinking: timer.start(thinkTime, true); break;
+ case GivingOrders: timer.start(orderTime, true); break;
+ }
+}
+
+void AI::timeout()
+{
+ switch (state) {
+ case Thinking:
+ if ( think() ) state = GivingOrders;
+ break;
+ case GivingOrders:
+ if ( emitOrder() ) return;
+ break;
+ }
+
+ startTimer();
+}
+
+bool AI::emitOrder()
+{
+ if ( bestRot==3 ) {
+ bestRot = 0;
+ main->pRotateRight();
+ } else if (bestRot) {
+ bestRot--;
+ main->pRotateLeft();
+ } else if ( bestDec>0 ) {
+ bestDec--;
+ main->pMoveRight();
+ } else if ( bestDec<0 ) {
+ bestDec++;
+ main->pMoveLeft();
+ } else {
+ main->pDropDownStart();
+ return true;
+ }
+ return false;
+}
+
+bool AI::think()
+{
+ initThink();
+ bool moveOk = true;
+ for (uint i=0; i<pieces.size(); i++)
+ if ( !pieces[i]->place() ) {
+ moveOk = false;
+ break;
+ }
+ if (moveOk) {
+ double p = points();
+ if ( !hasBestPoints || p>bestPoints
+ || (p==hasBestPoints && random.getBool()) ) {
+ hasBestPoints = true;
+ bestPoints = p;
+ bestDec = pieces[0]->dec();
+ bestRot = pieces[0]->rot();
+ }
+ }
+
+ for (uint i=pieces.size(); i>0; i--)
+ if ( pieces[i-1]->increment() ) return false;
+ return true;
+}
+
+double AI::points() const
+{
+ double pts = 0;
+ for (uint i=0; i<_elements.size(); i++) {
+ if ( _elements[i].coefficient==0.0 ) continue;
+ double v = _elements[i].data->function(*main, *board);
+ if ( _elements[i].data->triggered && qRound(v)<_elements[i].trigger )
+ continue;
+ pts += _elements[i].coefficient * v;
+ }
+ return pts;
+}
+
+void AI::settingsChanged()
+{
+ int d = CommonPrefs::thinkingDepth();
+ resizePieces(d);
+ for (uint i=0; i<_elements.size(); i++) {
+ const Data &data = *_elements[i].data;
+ _elements[i].coefficient = AIConfig::coefficient(data);
+ if (data.triggered) _elements[i].trigger = AIConfig::trigger(data);
+ }
+ if ( timer.isActive() ) launch(main);
+}
+
+double AI::nbOccupiedLines(const Board &, const Board &current)
+{
+ return current.matrix().height() - current.nbClearLines();
+}
+
+double AI::nbHoles(const Board &, const Board &current)
+{
+ uint nb = 0;
+ for (uint i=0; i<current.matrix().width(); i++) {
+ for (int j=current.firstColumnBlock(i)-1; j>=0; j--) {
+ KGrid2D::Coord c(i, j);
+ if ( current.matrix()[c]==0 ) nb++;
+ }
+ }
+ return nb;
+}
+
+double AI::peakToPeak(const Board &, const Board &current)
+{
+ int min = current.matrix().height()-1;
+ for (uint i=0; i<current.matrix().width(); i++)
+ min = kMin(min, current.firstColumnBlock(i));
+ return (int)current.firstClearLine()-1 - min;
+}
+
+double AI::mean(const Board &, const Board &current)
+{
+ double mean = 0;
+ for (uint i=0; i<current.matrix().width(); i++)
+ mean += current.firstColumnBlock(i);
+ return mean / current.matrix().width();
+}
+
+double AI::nbSpaces(const Board &main, const Board &current)
+{
+ double nb = 0;
+ double m = mean(main, current);
+ for (uint i=0; i<current.matrix().width(); i++) {
+ int j = current.firstColumnBlock(i);
+ if ( j<m ) nb += m - j;
+ }
+ return nb;
+}
+
+double AI::nbRemoved(const Board &main, const Board &current)
+{
+ return current.nbRemoved() - main.nbRemoved();
+}
+
+
+//-----------------------------------------------------------------------------
+const uint AIConfig::minThinkingDepth = 1;
+const uint AIConfig::maxThinkingDepth = 2;
+
+AIConfig::AIConfig(const QValueVector<AI::Element> &elements)
+ : QWidget(0, "ai config")
+{
+ QGridLayout *top = new QGridLayout(this, 3, 2, KDialog::marginHint(),
+ KDialog::spacingHint());
+
+ QLabel *label = new QLabel(i18n("Thinking depth:"), this);
+ top->addWidget(label, 0, 0);
+ KIntNumInput *in = new KIntNumInput(this, "kcfg_ThinkingDepth");
+ in->setRange(minThinkingDepth, maxThinkingDepth);
+ top->addWidget(in, 0, 1);
+
+ top->addRowSpacing(1, KDialog::spacingHint());
+
+ QGrid *grid = new QGrid(2, this);
+ top->addMultiCellWidget(grid, 2, 2, 0, 1);
+ for (uint i=0; i<elements.size(); i++) {
+ const AI::Data &data = *elements.at(i).data;
+ QLabel *label = new QLabel(i18n(data.label), grid);
+ if (data.whatsthis) QWhatsThis::add(label, i18n(data.whatsthis));
+ label->setFrameStyle(QFrame::Panel | QFrame::Plain);
+
+ QVBox *vb = new QVBox(grid);
+ if (data.whatsthis) QWhatsThis::add(vb, i18n(data.whatsthis));
+ vb->setMargin(KDialog::spacingHint());
+ vb->setSpacing(KDialog::spacingHint());
+ vb->setFrameStyle(QFrame::Panel | QFrame::Plain);
+ if (data.triggered) {
+ KIntNumInput *trig = new KIntNumInput(vb, triggerKey(data.name));
+ trig->setRange(0, 10, 1, true);
+ }
+ KDoubleNumInput *coeff = new KDoubleNumInput(vb, coefficientKey(data.name));
+ coeff->setRange(0.0, 1.0, 1.0, true);
+ }
+}
+
+QCString AIConfig::triggerKey(const char *name)
+{
+ return "kcfg_Trigger_" + QCString(name);
+}
+
+QCString AIConfig::coefficientKey(const char *name)
+{
+ return "kcfg_Coefficient_" + QCString(name);
+}
+
+double AIConfig::coefficient(const AI::Data &data)
+{
+ KConfigSkeletonItem *item = CommonPrefs::self()->findItem( QString("Coefficient_%1").arg(data.name) );
+ assert(item);
+ return item->property().toDouble();
+}
+
+int AIConfig::trigger(const AI::Data &data)
+{
+ KConfigSkeletonItem *item = CommonPrefs::self()->findItem( QString("Trigger_%1").arg(data.name) );
+ assert(item);
+ return item->property().toInt();
+}
diff --git a/libksirtet/common/ai.h b/libksirtet/common/ai.h
new file mode 100644
index 00000000..da298abc
--- /dev/null
+++ b/libksirtet/common/ai.h
@@ -0,0 +1,122 @@
+#ifndef COMMON_AI_H
+#define COMMON_AI_H
+
+#include <qtimer.h>
+#include <qvaluevector.h>
+
+#include <kdialogbase.h>
+#include <knuminput.h>
+#include <krandomsequence.h>
+#include "lib/libksirtet_export.h"
+
+class Board;
+class Piece;
+
+
+//-----------------------------------------------------------------------------
+class LIBKSIRTET_EXPORT AIPiece
+{
+ public:
+ AIPiece();
+ ~AIPiece();
+
+ void init(const Piece *p, Board *b);
+ bool place();
+ bool increment();
+
+ int dec() const { return curDec; }
+ uint rot() const { return curRot; }
+
+ private:
+ uint nbPos, nbRot, curPos, curRot;
+ int curDec;
+ const Piece *_piece;
+ Piece *_current;
+ Board *_board;
+
+ void reset();
+};
+
+//-----------------------------------------------------------------------------
+class LIBKSIRTET_EXPORT AI : public QObject
+{
+ Q_OBJECT
+ public:
+ struct Data {
+ const char *name, *label, *whatsthis;
+ bool triggered;
+ double (*function)(const Board &, const Board &);
+ };
+ static const Data LastData;
+
+ AI(uint thinkTime, uint orderTime, const Data *DATA);
+ virtual ~AI();
+
+ void launch(Board *main);
+ void stop();
+ void start();
+
+ class Element {
+ public:
+ const Data *data;
+ double coefficient;
+ int trigger;
+ };
+ const QValueVector<Element> &elements() const { return _elements; }
+
+ void settingsChanged();
+
+ private slots:
+ void timeout();
+
+ protected:
+ virtual void initThink();
+
+ static double nbOccupiedLines(const Board &, const Board &);
+ static double nbHoles(const Board &, const Board &);
+ static double nbSpaces(const Board &, const Board &);
+ static double peakToPeak(const Board &, const Board &);
+ static double mean(const Board &, const Board &);
+ static double nbRemoved(const Board &, const Board &);
+
+ private:
+ bool think();
+ void startTimer();
+ bool emitOrder();
+ double points() const;
+ void resizePieces(uint size);
+
+ QTimer timer;
+ enum ThinkState { Thinking, GivingOrders };
+ ThinkState state;
+ uint thinkTime, orderTime;
+ bool stopped;
+ QMemArray<AIPiece *> pieces;
+ QValueVector<Element> _elements;
+ Board *main, *board;
+ KRandomSequence random;
+
+ bool hasBestPoints;
+ double bestPoints;
+ int bestDec;
+ uint bestRot;
+};
+
+//-----------------------------------------------------------------------------
+class LIBKSIRTET_EXPORT AIConfig : public QWidget
+{
+ Q_OBJECT
+ public:
+ AIConfig(const QValueVector<AI::Element> &elements);
+
+ static double coefficient(const AI::Data &data);
+ static int trigger(const AI::Data &data);
+
+ private:
+ static QCString triggerKey(const char *name);
+ static QCString coefficientKey(const char *name);
+
+ static const uint minThinkingDepth, maxThinkingDepth;
+};
+
+#endif
diff --git a/libksirtet/common/board.cpp b/libksirtet/common/board.cpp
new file mode 100644
index 00000000..f5f011a6
--- /dev/null
+++ b/libksirtet/common/board.cpp
@@ -0,0 +1,286 @@
+#include "board.h"
+#include "board.moc"
+
+#include <knotifyclient.h>
+#include <klocale.h>
+
+#include "factory.h"
+#include "base/piece.h"
+#include "misc_ui.h"
+#include "ai.h"
+#include "commonprefs.h"
+
+
+Board::Board(bool graphic, GiftPool *gp, QWidget *parent)
+ : BaseBoard(graphic, parent),
+ _giftPool(gp), aiEngine(0)
+{}
+
+Board::~Board()
+{
+ delete aiEngine;
+}
+
+void Board::setType(bool _ai)
+{
+ Q_ASSERT( graphic() );
+ if (_ai) {
+ if ( aiEngine==0 ) aiEngine = cfactory->createAI();
+ } else {
+ delete aiEngine;
+ aiEngine = 0;
+ }
+}
+
+void Board::start(const GTInitData &data)
+{
+ randomGarbage.setSeed(data.seed);
+ _giftPool->reset();
+ BaseBoard::start(data);
+}
+
+void Board::stop()
+{
+ BaseBoard::stop();
+ if (aiEngine) aiEngine->stop();
+}
+
+void Board::showBoard(bool show)
+{
+ BaseBoard::showBoard(show);
+ showCanvas(_next, show);
+}
+
+void Board::unpause()
+{
+ BaseBoard::unpause();
+ if (aiEngine) aiEngine->start(); // eventually restart thinking
+}
+
+void Board::updateLevel()
+{
+ uint nb = cfactory->cbi.nbRemovedToLevel;
+ if ( nbRemoved()>=level()*nb ) updateLevel(level()+1);
+}
+
+void Board::updateLevel(uint newLevel)
+{
+ BaseBoard::updateLevel(newLevel);
+ emit levelUpdated();
+ if ( graphic() ) startTimer();
+}
+
+void Board::settingsChanged()
+{
+ BaseBoard::settingsChanged();
+ if (aiEngine) aiEngine->settingsChanged();
+}
+
+/*****************************************************************************/
+void Board::pMoveLeft()
+{
+ if ( state!=Normal ) return;
+ moveLeft();
+ main->update();
+}
+
+void Board::pMoveRight()
+{
+ if ( state!=Normal ) return;
+ moveRight();
+ main->update();
+}
+
+void Board::pMoveLeftTotal()
+{
+ if ( state!=Normal ) return;
+ moveLeft(bfactory->bbi.width);
+ main->update();
+}
+
+void Board::pMoveRightTotal()
+{
+ if ( state!=Normal ) return;
+ moveRight(bfactory->bbi.width);
+ main->update();
+}
+
+void Board::pOneLineDown()
+{
+ if ( state!=Normal ) return;
+ oneLineDown();
+ main->update();
+}
+
+void Board::pDropDownStart()
+{
+ if ( state!=Normal ) return;
+ _dropHeight = 0;
+ oneLineDown();
+ if ( state==Normal ) {
+ state = DropDown;
+ startTimer();
+ }
+ main->update();
+}
+
+void Board::pDropDownStop()
+{
+ if ( state!=DropDown || CommonPrefs::directDropDownEnabled() ) return;
+ state = Normal;
+ startTimer();
+ main->update();
+}
+
+void Board::pRotateLeft()
+{
+ if ( state!=Normal ) return;
+ rotateLeft();
+ main->update();
+}
+
+void Board::pRotateRight()
+{
+ if ( state!=Normal ) return;
+ rotateRight();
+ main->update();
+}
+
+void Board::pieceDropped(uint dropHeight)
+{
+ if ( state==DropDown ) state = Normal;
+ else _dropHeight = dropHeight;
+ _beforeGlue(true);
+}
+
+void Board::_beforeGlue(bool first)
+{
+ if ( graphic() ) {
+ state = (beforeGlue(_dropHeight>=1, first) ? BeforeGlue : Normal);
+ if ( state==BeforeGlue ) {
+ startTimer();
+ return;
+ }
+ }
+ gluePiece();
+}
+
+void Board::gluePiece()
+{
+ BaseBoard::gluePiece();
+ _afterGlue(true);
+ if ( graphic() ) KNotifyClient::event(winId(), "glued", i18n("Piece glued"));
+}
+
+void Board::_afterGlue(bool first)
+{
+ bool b = afterGlue(!graphic(), first);
+ if ( graphic() ) {
+ state = (b ? AfterGlue : Normal);
+ if ( state==AfterGlue ) {
+ startTimer();
+ return;
+ }
+ }
+
+ updateScore(score() + _dropHeight);
+ if ( needRemoving() ) _beforeRemove(true);
+ else _afterAfterRemove();
+}
+
+bool Board::afterAfterRemove()
+{
+ // checkGift
+ if ( graphic() && _giftPool->pending() ) {
+ if ( putGift(_giftPool->take()) ) {
+ computeInfos();
+ _afterGift(true);
+ return true;
+ } else return false;
+ }
+ return newPiece();
+}
+
+void Board::_afterGift(bool first)
+{
+ Q_ASSERT( graphic() );
+ state = (afterGift(first) ? AfterGift : Normal);
+ if ( state==AfterGift ) startTimer();
+ else afterAfterRemove();
+}
+
+bool Board::newPiece()
+{
+ Q_ASSERT( !graphic() || state==Normal );
+ if ( !BaseBoard::newPiece() ) return false;
+ if ( graphic() ) {
+ main->update();
+ _next->update();
+ if (aiEngine) aiEngine->launch(this);
+ // else : a human player can think by himself ...
+ }
+ return true;
+}
+
+bool Board::timeout()
+{
+ if ( BaseBoard::timeout() ) return true;
+
+ switch (state) {
+ case DropDown: _dropHeight++;
+ case Normal: oneLineDown(); break;
+ case BeforeGlue: _beforeGlue(false); break;
+ case AfterGlue: _afterGlue(false); break;
+ case AfterGift: _afterGift(false); break;
+ default: return false;
+ }
+ main->update();
+ return true;
+}
+
+uint Board::normalTime() const
+{
+ return cfactory->cbi.baseTime / (1 + level());
+}
+
+bool Board::startTimer()
+{
+ if ( BaseBoard::startTimer() ) return true;
+
+ switch (state) {
+ case Normal:
+ timer.start(normalTime());
+ break;
+ case DropDown:
+ timer.start(cfactory->cbi.dropDownTime);
+ break;
+ case BeforeGlue:
+ timer.start(cfactory->cbi.beforeGlueTime, true);
+ break;
+ case AfterGlue:
+ timer.start(cfactory->cbi.afterGlueTime, true);
+ break;
+ case AfterGift:
+ timer.start(cfactory->cbi.afterGiftTime, true);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+bool Board::beforeGlue(bool bump, bool first)
+{
+ if ( !bump ) return false;
+ if (first) {
+ loop = 0;
+ return true;
+ } else loop++;
+
+ float dec = BasePrefs::blockSize() * (loop+1) * -0.1;
+ if ( BasePrefs::animationsEnabled() ) bumpCurrentPiece((int)dec);
+
+ return ( loop!=cfactory->cbi.nbBumpStages );
+}
diff --git a/libksirtet/common/board.h b/libksirtet/common/board.h
new file mode 100644
index 00000000..97c37c17
--- /dev/null
+++ b/libksirtet/common/board.h
@@ -0,0 +1,75 @@
+#ifndef COMMON_BOARD_H
+#define COMMON_BOARD_H
+
+#include "base/board.h"
+
+#include "lib/libksirtet_export.h"
+
+class GiftPool;
+class AI;
+
+class LIBKSIRTET_EXPORT Board : public BaseBoard
+{
+ Q_OBJECT
+ public:
+ Board(bool graphic, GiftPool *, QWidget *parent);
+ virtual ~Board();
+
+ void setType(bool computer);
+ virtual void start(const GTInitData &);
+ void unpause();
+ void stop();
+
+ virtual uint gift() = 0;
+ virtual bool needRemoving() = 0;
+
+ GiftPool *giftPool() const { return _giftPool; }
+
+ public slots:
+ void pMoveLeft();
+ void pMoveRight();
+ void pDropDownStart();
+ void pDropDownStop();
+ void pOneLineDown();
+ void pRotateLeft();
+ void pRotateRight();
+ void pMoveLeftTotal();
+ void pMoveRightTotal();
+
+ private slots:
+ bool timeout();
+
+ signals:
+ void levelUpdated();
+
+ protected:
+ KRandomSequence randomGarbage;
+
+ virtual bool beforeGlue(bool bump, bool first);
+ virtual void gluePiece();
+ virtual bool afterGlue(bool /*doAll*/, bool /*first*/) { return false; }
+ virtual bool afterGift(bool /*first*/) { return false; }
+ virtual bool putGift(uint) = 0;
+
+ virtual uint normalTime() const;
+ void updateLevel();
+
+ void settingsChanged();
+
+ private:
+ uint _dropHeight;
+ GiftPool *_giftPool;
+ AI *aiEngine;
+
+ bool newPiece();
+ void pieceDropped(uint dropHeight);
+ void _afterGift(bool first);
+ void _beforeGlue(bool first);
+ void _afterGlue(bool first);
+ bool afterAfterRemove();
+ bool startTimer();
+ void showBoard(bool show);
+ void updateLevel(uint newLevel);
+};
+
+#endif
diff --git a/libksirtet/common/commonprefs.kcfgc b/libksirtet/common/commonprefs.kcfgc
new file mode 100644
index 00000000..8e41b16f
--- /dev/null
+++ b/libksirtet/common/commonprefs.kcfgc
@@ -0,0 +1,9 @@
+# Code generation options for kconfig_compiler
+File=libksirtet2.kcfg
+IncludeFiles=base/baseprefs.h
+ClassName=CommonPrefs
+Inherits=BasePrefs
+Singleton=true
+#Mutators=true
+#CustomAdditions=true
+Mutators=false
diff --git a/libksirtet/common/factory.cpp b/libksirtet/common/factory.cpp
new file mode 100644
index 00000000..1b239a82
--- /dev/null
+++ b/libksirtet/common/factory.cpp
@@ -0,0 +1,28 @@
+#include "factory.h"
+
+#include "ai.h"
+#include "settings.h"
+
+
+CommonFactory::CommonFactory(const MainData &md, const BaseBoardInfo &bbi,
+ const CommonBoardInfo &ci)
+ : BaseFactory(md, bbi), cbi(ci)
+{}
+
+QWidget *CommonFactory::createAppearanceConfig()
+{
+ return new AppearanceConfig;
+}
+
+QWidget *CommonFactory::createGameConfig()
+{
+ return new GameConfig;
+}
+
+QWidget *CommonFactory::createAIConfig()
+{
+ AI *ai = createAI();
+ QWidget *cw = new AIConfig(ai->elements());
+ delete ai;
+ return cw;
+}
diff --git a/libksirtet/common/factory.h b/libksirtet/common/factory.h
new file mode 100644
index 00000000..c0b40d66
--- /dev/null
+++ b/libksirtet/common/factory.h
@@ -0,0 +1,36 @@
+#ifndef COMMON_FACTORY_H
+#define COMMON_FACTORY_H
+
+#include "base/factory.h"
+
+#include "lib/libksirtet_export.h"
+
+struct CommonBoardInfo {
+ uint baseTime, dropDownTime, beforeGlueTime, afterGlueTime;
+ uint afterGiftTime, nbBumpStages;
+ uint nbRemovedToLevel;
+ uint nbGiftLeds, maxGiftsToSend, giftShowerTimeout, giftPoolTimeout;
+};
+
+class BaseField;
+class AI;
+
+#define cfactory static_cast<CommonFactory *>(BaseFactory::self())
+
+class LIBKSIRTET_EXPORT CommonFactory : public BaseFactory
+{
+ public:
+ CommonFactory(const MainData &, const BaseBoardInfo &,
+ const CommonBoardInfo &);
+
+ const CommonBoardInfo &cbi;
+
+ virtual BaseField *createField(QWidget *parent) = 0;
+ virtual AI *createAI() = 0;
+
+ QWidget *createAIConfig();
+ virtual QWidget *createAppearanceConfig();
+ virtual QWidget *createGameConfig();
+};
+
+#endif
diff --git a/libksirtet/common/field.cpp b/libksirtet/common/field.cpp
new file mode 100644
index 00000000..2d67062e
--- /dev/null
+++ b/libksirtet/common/field.cpp
@@ -0,0 +1,243 @@
+#include "field.h"
+#include "field.moc"
+
+#include <qwhatsthis.h>
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <klocale.h>
+#include <kprogress.h>
+#include <kgameprogress.h>
+#include <kcanvasrootpixmap.h>
+#include <kgamelcd.h>
+
+#include "base/baseprefs.h"
+#include "factory.h"
+#include "highscores.h"
+#include "misc_ui.h"
+#include "board.h"
+#include "commonprefs.h"
+
+
+Field::Field(QWidget *parent)
+: MPSimpleBoard(parent), BaseField(this)
+{
+// column 1
+ // score LCD
+ scoreList = new KGameLCDList(this);
+ showScore = new KGameLCD(6, scoreList);
+ scoreList->append(showScore);
+ showTime = new KGameLCDClock(scoreList);
+ scoreList->append(showTime);
+ lcds->addWidget(scoreList, 1, 0);
+ lcds->setRowStretch(2, 1);
+
+ // removed LCD
+ removedList = new KGameLCDList(i18n(bfactory->mainData.removedLabel), this);
+ lcds->addWidget(removedList, 3, 0);
+ lcds->setRowStretch(4, 1);
+
+ // level progress
+ levelLabel = new QLabel(this);
+ levelLabel->setAlignment(AlignCenter);
+ lcds->addWidget(levelLabel, 5, 0);
+ toLevel = new KProgress(this);
+ toLevel->setTextEnabled(true);
+ toLevel->setFormat("1");
+ QWhatsThis::add(toLevel, i18n("Display the progress to complete the current level or stage."));
+ lcds->addWidget(toLevel, 6, 0);
+ lcds->setRowStretch(7, 1);
+
+// column 2
+ // previous player height
+ prevHeight = new PlayerProgress(board, this, "prev_progress");
+ QWhatsThis::add(prevHeight, i18n("Previous player's height"));
+ top->addWidget(prevHeight, 1, 1, AlignHCenter);
+
+// column 3
+ // pending gift shower
+ Board *b = static_cast<Board *>(board);
+ top->addWidget(b->giftPool(), 0, 2, AlignCenter);
+
+ // shadow piece
+ shadow = new Shadow(board, this);
+ QWhatsThis::add(shadow, i18n("Shadow of the current piece"));
+ top->addWidget(shadow, 2, 2);
+
+// column 4
+ // next player height
+ nextHeight = new PlayerProgress(board, this, "next_progress");
+ QWhatsThis::add(nextHeight, i18n("Next player's height"));
+ top->addWidget(nextHeight, 1, 3, AlignHCenter);
+
+// column 5
+ // next piece shower
+ QVBoxLayout *vbl = new QVBoxLayout(10);
+ top->addLayout(vbl, 1, 4);
+ vbl->addStretch(1);
+
+ labShowNext = new QLabel(i18n("Next Tile"), this);
+ labShowNext->setAlignment(AlignCenter);
+ vbl->addWidget(labShowNext, 0);
+ showNext = new ShowNextPiece(board, this);
+ _snRootPixmap = new KCanvasRootPixmap(showNext);
+ _snRootPixmap->start();
+ vbl->addWidget(showNext, 0);
+ vbl->addStretch(4);
+
+ connect(board, SIGNAL(scoreUpdated()), SLOT(scoreUpdatedSlot()));
+ connect(board, SIGNAL(levelUpdated()), SLOT(levelUpdated()));
+ connect(board, SIGNAL(removedUpdated()), SLOT(removedUpdated()));
+
+ initVariableGUI();
+}
+
+void Field::levelUpdated()
+{
+ toLevel->setFormat(QString::number(board->level()));
+ // necessary to update string ...
+ int p = toLevel->progress();
+ toLevel->setProgress(p+1);
+ toLevel->setProgress(p);
+}
+
+void Field::removedUpdated()
+{
+ uint nb = cfactory->cbi.nbRemovedToLevel;
+ toLevel->setProgress(isArcade() ? board->arcadeDone()
+ : board->nbRemoved() % nb);
+}
+
+void Field::showOpponents(bool show)
+{
+ Board *b = static_cast<Board *>(board);
+ if (show) {
+ prevHeight->show();
+ nextHeight->show();
+ b->giftPool()->show();
+ } else {
+ prevHeight->hide();
+ nextHeight->hide();
+ b->giftPool()->hide();
+ }
+}
+
+void Field::settingsChanged()
+{
+ BaseField::settingsChanged();
+ QColor color = BasePrefs::fadeColor();
+ double s = BasePrefs::fadeIntensity();
+ _snRootPixmap->setFadeEffect(s, color);
+ showNext->canvas()->setBackgroundColor(color);
+ bool b = CommonPrefs::showNextPiece();
+ if (b) {
+ showNext->show();
+ labShowNext->show();
+ } else {
+ showNext->hide();
+ labShowNext->hide();
+ }
+ b = CommonPrefs::showPieceShadow();
+ if (b) shadow->show();
+ else shadow->hide();
+}
+
+void Field::_init(bool AI, bool multiplayer, bool server, bool first,
+ const QString &name)
+{
+ BaseField::init(AI, multiplayer, server, first, name);
+ showOpponents(multiplayer);
+ static_cast<Board *>(board)->setType(AI);
+}
+
+void Field::_initFlag(QDataStream &s)
+{
+ ServerInitData sid;
+ s >> sid;
+ GTInitData data;
+ data.seed = sid.seed;
+ data.initLevel = sid.initLevel;
+
+ shadow->setDisplay(true);
+ toLevel->setValue(0);
+ showTime->reset();
+ showTime->start();
+
+ BaseField::start(data);
+ initVariableGUI();
+}
+
+void Field::initVariableGUI()
+{
+ if ( board->isArcade() ) {
+ scoreList->title()->setText(i18n("Elapsed time"));
+ showScore->hide();
+ showTime->show();
+ QWhatsThis::add(scoreList, i18n("Display the elapsed time."));
+ levelLabel->setText(i18n("Stage"));
+ toLevel->setTotalSteps( board->arcadeTodo() );
+ } else {
+ scoreList->title()->setText(i18n("Score"));
+ showScore->show();
+ showTime->hide();
+ QWhatsThis::add(scoreList, i18n("<qt>Display the current score.<br/>It turns <font color=\"blue\">blue</font> if it is a highscore and <font color=\"red\">red</font> if it is the best local score.</qt>"));
+ levelLabel->setText(i18n("Level"));
+ toLevel->setTotalSteps(cfactory->cbi.nbRemovedToLevel);
+ }
+}
+
+void Field::_playFlag(QDataStream &s)
+{
+ ServerPlayData spd;
+ s >> spd;
+ prevHeight->setValue(spd.prevHeight);
+ nextHeight->setValue(spd.nextHeight);
+ if (spd.gift)
+ static_cast<Board *>(board)->giftPool()->put(spd.gift);
+}
+
+void Field::_pauseFlag(bool p)
+{
+ pause(p);
+ shadow->setDisplay(!p);
+ if (p) showTime->stop();
+ else showTime->start();
+}
+
+void Field::_stopFlag(bool gameover)
+{
+ BaseField::stop(gameover);
+ showTime->stop();
+}
+
+void Field::_dataOut(QDataStream &s)
+{
+ _cpd.height = board->firstClearLine();
+ _cpd.end = static_cast<Board *>(board)->isGameOver();
+ _cpd.gift = static_cast<Board *>(board)->gift();
+ s << _cpd;
+}
+
+KExtHighscore::Score Field::currentScore() const
+{
+ KExtHighscore::Score score(_cpd.end ? KExtHighscore::Lost : KExtHighscore::Won);
+ score.setScore(board->score());
+ score.setData("level", board->level());
+ score.setData("removed", board->nbRemoved());
+ return score;
+}
+
+void Field::_gameOverDataOut(QDataStream &s)
+{
+ s << currentScore();
+}
+
+void Field::moveLeft() { static_cast<Board *>(board)->pMoveLeft(); }
+void Field::moveRight() { static_cast<Board *>(board)->pMoveRight(); }
+void Field::dropDownStart() { static_cast<Board *>(board)->pDropDownStart(); }
+void Field::dropDownStop() { static_cast<Board *>(board)->pDropDownStop(); }
+void Field::oneLineDown() { static_cast<Board *>(board)->pOneLineDown(); }
+void Field::rotateLeft() { static_cast<Board *>(board)->pRotateLeft(); }
+void Field::rotateRight() { static_cast<Board *>(board)->pRotateRight(); }
+void Field::moveLeftTotal() { static_cast<Board *>(board)->pMoveLeftTotal(); }
+void Field::moveRightTotal() { static_cast<Board *>(board)->pMoveRightTotal();}
diff --git a/libksirtet/common/field.h b/libksirtet/common/field.h
new file mode 100644
index 00000000..8179539b
--- /dev/null
+++ b/libksirtet/common/field.h
@@ -0,0 +1,68 @@
+#ifndef COMMON_FIELD_H
+#define COMMON_FIELD_H
+
+#include "lib/mp_simple_board.h"
+#include "base/field.h"
+#include "types.h"
+
+#include "lib/libksirtet_export.h"
+
+
+class ShowNextPiece;
+class GiftShower;
+class Shadow;
+class KProgress;
+class KGameProgress;
+class KGameLCDClock;
+
+class LIBKSIRTET_EXPORT Field : public MPSimpleBoard, public BaseField
+{
+ Q_OBJECT
+ public:
+ Field(QWidget *parent);
+
+ public slots:
+ void moveLeft();
+ void moveRight();
+ void dropDownStart();
+ void dropDownStop();
+ void oneLineDown();
+ void rotateLeft();
+ void rotateRight();
+ void moveLeftTotal();
+ void moveRightTotal();
+
+ virtual void settingsChanged();
+
+ protected slots:
+ void scoreUpdatedSlot() { scoreUpdated(); }
+ virtual void levelUpdated();
+ virtual void removedUpdated();
+
+ private:
+ KGameLCDClock *showTime;
+ ShowNextPiece *showNext;
+ KProgress *toLevel;
+ QLabel *labShowNext, *levelLabel;
+ KGameProgress *prevHeight, *nextHeight;
+ Shadow *shadow;
+ KCanvasRootPixmap *_snRootPixmap;
+ ClientPlayData _cpd;
+
+ void _init(bool AI, bool multiplayer, bool server, bool first,
+ const QString &name);
+ void showOpponents(bool show);
+ void initVariableGUI();
+
+ void _initFlag(QDataStream &);
+ void _playFlag(QDataStream &);
+ void _pauseFlag(bool pause);
+ void _stopFlag(bool gameover);
+ void _dataOut(QDataStream &);
+ void _gameOverDataOut(QDataStream &);
+ void _initDataOut(QDataStream &) {}
+
+ KExtHighscore::Score currentScore() const;
+};
+
+#endif
diff --git a/libksirtet/common/highscores.cpp b/libksirtet/common/highscores.cpp
new file mode 100644
index 00000000..799a31b9
--- /dev/null
+++ b/libksirtet/common/highscores.cpp
@@ -0,0 +1,60 @@
+#include "highscores.h"
+
+#include <klocale.h>
+#include <kapplication.h>
+#include <kconfig.h>
+
+#include "base/factory.h"
+
+
+using namespace KExtHighscore;
+
+CommonHighscores::CommonHighscores()
+{
+ Item *item = new Item((uint)1, i18n("Level"), Qt::AlignRight);
+ addScoreItem("level", item);
+ item = new Item((uint)0, i18n(bfactory->mainData.removedLabel),
+ Qt::AlignRight);
+ addScoreItem("removed", item);
+}
+
+void CommonHighscores::convertLegacy(uint)
+{
+ KConfigGroupSaver cg(kapp->config(), "High Scores");
+ for (uint i=0; i<10; i++) {
+ QString name
+ = cg.config()->readEntry(QString("name%1").arg(i), QString::null);
+ if ( name.isNull() ) break;
+ if ( name.isEmpty() ) name = i18n("anonymous");
+ uint score
+ = cg.config()->readUnsignedNumEntry(QString("score%1").arg(i), 0);
+ uint level
+ = cg.config()->readUnsignedNumEntry(QString("level%1").arg(i), 1);
+ Score s(Won);
+ s.setScore(score);
+ s.setData("name", name);
+ s.setData("level", level);
+ submitLegacyScore(s);
+ }
+}
+
+bool CommonHighscores::isStrictlyLess(const Score &s1, const Score &s2) const
+{
+ uint l1 = s1.data("level").toUInt();
+ uint r1 = s1.data("removed").toUInt();
+ uint l2 = s2.data("level").toUInt();
+ uint r2 = s2.data("removed").toUInt();
+
+ if ( s1.score()==s2.score() ) {
+ if ( l1==l2 ) return r1<r2;
+ else return l1<l2;
+ } else return BaseHighscores::isStrictlyLess(s1, s2);
+}
+
+void CommonHighscores::additionalQueryItems(KURL &url, const Score &s) const
+{
+ uint l = s.data("level").toUInt();
+ addToQueryURL(url, "scoreLevel", QString::number(l));
+ uint r = s.data("removed").toUInt();
+ addToQueryURL(url, "scoreRemoved", QString::number(r));
+}
diff --git a/libksirtet/common/highscores.h b/libksirtet/common/highscores.h
new file mode 100644
index 00000000..f04c0d2e
--- /dev/null
+++ b/libksirtet/common/highscores.h
@@ -0,0 +1,20 @@
+#ifndef COMMON_HIGHSCORES_H
+#define COMMON_HIGHSCORES_H
+
+#include "base/highscores.h"
+
+#include "lib/libksirtet_export.h"
+
+class LIBKSIRTET_EXPORT CommonHighscores : public BaseHighscores
+{
+ public:
+ CommonHighscores();
+
+ private:
+ void convertLegacy(uint level);
+ bool isStrictlyLess(const KExtHighscore::Score &,
+ const KExtHighscore::Score &) const;
+ void additionalQueryItems(KURL &, const KExtHighscore::Score &) const;
+};
+
+#endif
diff --git a/libksirtet/common/inter.cpp b/libksirtet/common/inter.cpp
new file mode 100644
index 00000000..e9f1688b
--- /dev/null
+++ b/libksirtet/common/inter.cpp
@@ -0,0 +1,150 @@
+#include "inter.h"
+#include "inter.moc"
+
+#include <klocale.h>
+#include <kaction.h>
+#include <kapplication.h>
+
+#include "factory.h"
+#include "field.h"
+#include "commonprefs.h"
+#include "main.h"
+
+
+const ActionData Interface::ACTION_DATA[Nb_Actions] = {
+ { I18N_NOOP("Move Left"), "move left", SLOT(moveLeft()), 0 },
+ { I18N_NOOP("Move Right"), "move right", SLOT(moveRight()), 0 },
+ { I18N_NOOP("Drop Down"), "drop down", SLOT(dropDownStart()),
+ SLOT(dropDownStop()) },
+ { I18N_NOOP("One Line Down"), "one line down", SLOT(oneLineDown()), 0 },
+ { I18N_NOOP("Rotate Left"), "rotate left", SLOT(rotateLeft()), 0 },
+ { I18N_NOOP("Rotate Right"), "rotate right", SLOT(rotateRight()), 0 },
+ { I18N_NOOP("Move to Left Column"), "move left total",
+ SLOT(moveLeftTotal()), 0 },
+ { I18N_NOOP("Move to Right Column"), "move right total",
+ SLOT(moveRightTotal()), 0 }
+};
+
+const int Interface::KEYCODE_ONE[Nb_Actions] = {
+ Key_Left, Key_Right, Key_Down, Key_Shift, Key_Up, Key_Return,
+ CTRL+Key_Left, CTRL+Key_Right
+};
+const int Interface::KEYCODE_TWO[Nb_Actions] = {
+ Key_F, Key_G, Key_D, Key_Space, Key_E, Key_C, SHIFT+Key_F, SHIFT+Key_G
+};
+
+Interface::Interface(const MPGameInfo &gi, QWidget *parent)
+ : MPSimpleInterface(gi, Nb_Actions, ACTION_DATA, parent)
+{
+ setDefaultKeycodes(1, 0, KEYCODE_ONE);
+ setDefaultKeycodes(2, 0, KEYCODE_TWO);
+ setDefaultKeycodes(2, 1, KEYCODE_ONE);
+}
+
+MPBoard *Interface::newBoard(uint i)
+{
+ Field *f = static_cast<Field *>(cfactory->createField(this));
+ f->settingsChanged();
+ connect(this, SIGNAL(settingsChanged()), f, SLOT(settingsChanged()));
+ if ( i==0 ) _firstField = f;
+ return f;
+}
+
+void Interface::normalGame()
+{
+ singleHuman();
+}
+
+void Interface::arcadeGame()
+{
+ singleHuman();
+ _firstField->setArcade();
+}
+
+void Interface::_init()
+{
+ if ( !server() ) return;
+ _data.resize(nbPlayers());
+ _scores.setPlayerCount( nbPlayers() );
+ for (uint i=0; i<nbPlayers(); i++)
+ _scores.setName(i, playerName(i));
+}
+
+bool Interface::_readPlayData()
+{
+ bool end = false;
+ for (uint i=0; i<nbPlayers(); i++) {
+ readingStream(i) >> _data[i];
+ if (_data[i].end) end = true;
+ }
+ return end;
+}
+
+void Interface::_sendPlayData()
+{
+ ServerPlayData sd;
+ for(uint i=0; i<nbPlayers(); i++) {
+ sd.prevHeight = _data[prev(i)].height;
+ sd.nextHeight = _data[next(i)].height;
+ sd.gift = _data[prev(i)].gift;
+ writingStream(i) << sd;
+ }
+}
+
+void Interface::_showHighscores(QWidget *parent)
+{
+ if ( !server() || nbPlayers()!=1 ) _scores.show(parent);
+ else BaseInterface::_showHighscores(parent);
+}
+
+void Interface::_showGameOverData()
+{
+ if ( !server() || nbPlayers()!=1 ) _scores.show(this);
+ else if ( !_firstField->isArcade() ) {
+ _score.setType(KExtHighscore::Won);
+ BaseField::gameOver(_score, this);
+ }
+}
+
+uint Interface::prev(uint i) const
+{
+ if ( i==0 ) return nbPlayers()-1;
+ else return i-1;
+}
+
+uint Interface::next(uint i) const
+{
+ if ( i==(nbPlayers()-1) ) return 0;
+ else return i+1;
+}
+
+// server only
+void Interface::_treatInit()
+{
+ ServerInitData sid;
+ sid.seed = kapp->random();
+ sid.initLevel = CommonPrefs::initialGameLevel();
+ for (uint i=0; i<nbPlayers(); i++) {
+ sid.prevName = playerName(prev(i));
+ sid.nextName = playerName(next(i));
+ sid.name = playerName(i);
+ writingStream(i) << sid;
+ }
+}
+
+void Interface::_sendGameOverData(QDataStream &s)
+{
+ bool multiplayers = ( nbPlayers()>1 );
+ for (uint i=0; i<nbPlayers(); i++) {
+ readingStream(i) >> _score;
+ if (multiplayers) _scores.addScore(i, _score);
+ }
+ if (multiplayers) s << _scores;
+ // else no need to send anything
+}
+
+// client only
+void Interface::_readGameOverData(QDataStream &s)
+{
+ s >> _scores;
+}
diff --git a/libksirtet/common/inter.h b/libksirtet/common/inter.h
new file mode 100644
index 00000000..e38c2ed5
--- /dev/null
+++ b/libksirtet/common/inter.h
@@ -0,0 +1,62 @@
+#ifndef COMMON_INTER_H
+#define COMMON_INTER_H
+
+#include <kexthighscore.h>
+#include "lib/libksirtet_export.h"
+
+#include "lib/mp_simple_interface.h"
+#include "base/inter.h"
+#include "types.h"
+#include "board.h"
+
+
+class Field;
+
+class LIBKSIRTET_EXPORT Interface : public MPSimpleInterface, public BaseInterface
+{
+ Q_OBJECT
+public:
+ Interface(const MPGameInfo &, QWidget *parent);
+
+signals:
+ void settingsChanged();
+
+public slots:
+ void normalGame();
+ void arcadeGame();
+ void settingsChangedSlot() { emit settingsChanged(); }
+
+protected:
+ void _showHighscores(QWidget *parent);
+
+private:
+ QMemArray<ClientPlayData> _data;
+ KExtHighscore::Score _score;
+ KExtHighscore::MultiplayerScores _scores;
+ Field *_firstField;
+
+ enum Action { Nb_Actions = 8 };
+ static const ActionData ACTION_DATA[Nb_Actions];
+ static const int KEYCODE_ONE[Nb_Actions];
+ static const int KEYCODE_TWO[Nb_Actions];
+
+ MPBoard *newBoard(uint);
+ void setInitData(uint player, ServerInitData &);
+ uint prev(uint i) const;
+ uint next(uint i) const;
+
+ void _readGameOverData(QDataStream &s);
+ void _sendGameOverData(QDataStream &s);
+ void _firstInit() {}
+ void _treatInit();
+ void _init();
+ void _showGameOverData();
+ bool _readPlayData();
+ void _sendPlayData();
+
+ void _start() { MPSimpleInterface::start(); }
+ void _pause() { MPSimpleInterface::pause(); }
+ bool _isPaused() const { return MPSimpleInterface::isPaused(); }
+};
+
+#endif
diff --git a/libksirtet/common/libksirtet2.kcfg b/libksirtet/common/libksirtet2.kcfg
new file mode 100644
index 00000000..27ee72e3
--- /dev/null
+++ b/libksirtet/common/libksirtet2.kcfg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <group name="Options">
+ <entry name="ShowNextPiece" type="Bool" key="show next piece">
+ <label>Show next piece.</label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowPieceShadow" type="Bool" key="show piece shadow">
+ <label>Show the shadow of a piece.</label>
+ <default>true</default>
+ </entry>
+ <entry name="ShowDetailedRemoved" type="Bool" key="show detailed removed">
+ <label>Show detailed 'removed lines'.</label>
+ <default>false</default>
+ </entry>
+ <entry name="InitialGameLevel" type="Int" key="init level" min="1" max="20">
+ <label>The inital level of new games.</label>
+ <default>1</default>
+ <min>1</min>
+ <max>20</max>
+ </entry>
+ <entry name="DirectDropDownEnabled" type="Bool" key="direct drop down">
+ <label>Enable direct dropping of pieces.</label>
+ <default>false</default>
+ </entry>
+ </group>
+ <group name="AI">
+ <entry name="ThinkingDepth" type="Int" key="thinking depth" min="1" max="2">
+ <label>The thinking depth</label>
+ <default>2</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/libksirtet/common/main.cpp b/libksirtet/common/main.cpp
new file mode 100644
index 00000000..004b86ca
--- /dev/null
+++ b/libksirtet/common/main.cpp
@@ -0,0 +1,60 @@
+#include "main.h"
+#include "main.moc"
+
+#include <klocale.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kkeydialog.h>
+#include <kconfigdialog.h>
+
+#include "inter.h"
+#include "factory.h"
+
+void MainWindow::addConfig(KConfigDialog *dialog)
+{
+ QWidget *w = cfactory->createAIConfig();
+ if (w) dialog->addPage(w, i18n("A.I."), "personal");
+}
+
+void MainWindow::init()
+{
+ Interface *inter = static_cast<Interface *>(_inter);
+ inter->normalGame();
+ setFocusPolicy(StrongFocus);
+
+ // Modes
+ bool ama = ( bfactory->bbi.nbArcadeStages!=0 );
+ QString s = (ama ? i18n("&Single Human (Normal)") : i18n("&Single Human"));
+ (void)new KAction(s, 0, inter, SLOT(normalGame()),
+ actionCollection(), "mp_single_human");
+ if (ama) (void)new KAction(i18n("&Single Human (Arcade)"), 0,
+ inter, SLOT(arcadeGame()),
+ actionCollection(), "mp_arcade");
+ (void)new KAction(i18n("Human vs &Human"), 0, inter, SLOT(humanVsHuman()),
+ actionCollection(), "mp_human_vs_human");
+ (void)new KAction(i18n("Human vs &Computer"), 0,
+ inter, SLOT(humanVsComputer()),
+ actionCollection(), "mp_human_vs_computer");
+ (void)new KAction(i18n("&More..."), 0, inter, SLOT(dialog()),
+ actionCollection(), "mp_more");
+
+ buildGUI(inter);
+ connect(this, SIGNAL(settingsChanged()),
+ inter, SLOT(settingsChangedSlot()));
+}
+
+void MainWindow::addKeys(KKeyDialog &d)
+{
+ static_cast<Interface *>(_inter)->addKeys(d);
+}
+
+void MainWindow::saveKeys()
+{
+ static_cast<Interface *>(_inter)->saveKeys();
+}
+
+void MainWindow::focusInEvent(QFocusEvent *e)
+{
+ static_cast<Interface *>(_inter)->setFocus();
+ BaseMainWindow::focusInEvent(e);
+}
diff --git a/libksirtet/common/main.h b/libksirtet/common/main.h
new file mode 100644
index 00000000..d22b7273
--- /dev/null
+++ b/libksirtet/common/main.h
@@ -0,0 +1,22 @@
+#ifndef COMMON_MAIN_H
+#define COMMON_MAIN_H
+
+#include "base/main.h"
+
+#include "lib/libksirtet_export.h"
+
+class LIBKSIRTET_EXPORT MainWindow : public BaseMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow() {}
+
+protected:
+ void init();
+ void addConfig(KConfigDialog *);
+ void addKeys(KKeyDialog &);
+ void saveKeys();
+ virtual void focusInEvent(QFocusEvent *e);
+};
+
+#endif
diff --git a/libksirtet/common/misc_ui.cpp b/libksirtet/common/misc_ui.cpp
new file mode 100644
index 00000000..45cfb440
--- /dev/null
+++ b/libksirtet/common/misc_ui.cpp
@@ -0,0 +1,194 @@
+#include "misc_ui.h"
+#include "misc_ui.moc"
+
+#include <qpainter.h>
+
+#include "base/piece.h"
+#include "base/board.h"
+#include "base/baseprefs.h"
+#include "base/kzoommainwindow.h"
+#include "factory.h"
+
+const uint GIFT_SHOWER_TIMEOUT = 800;
+const uint GIFT_POOL_TIMEOUT = 2000;
+
+const uint SHADOW_HEIGHT = 10;
+
+const uint GI_WIDTH = 15;
+const uint GI_HEIGHT = 11;
+const uint ARROW_HEIGHT = 3;
+const uint ARROW_WIDTH = 7;
+
+const uint LED_WIDTH = 15;
+const uint LED_HEIGHT = 15;
+const uint LED_SPACING = 5;
+
+/*****************************************************************************/
+ShowNextPiece::ShowNextPiece(BaseBoard *board, QWidget *parent)
+ : FixedCanvasView(parent, "show_next_piece")
+{
+ setCanvas(board->next());
+ setFrameStyle(QFrame::Panel | QFrame::Sunken);
+ KZoomMainWindow::addWidget(this);
+}
+
+/*****************************************************************************/
+Shadow::Shadow(BaseBoard *board, QWidget *parent)
+ : QWidget(parent, "shadow"), _xOffset(board->frameWidth()),
+ _board(board), _show(false)
+{
+ KZoomMainWindow::addWidget(this);
+ connect(board, SIGNAL(updatePieceConfigSignal()), SLOT(update()));
+}
+
+QSize Shadow::sizeHint() const
+{
+ return QSize(_xOffset + _board->matrix().width() * BasePrefs::blockSize(),
+ SHADOW_HEIGHT);
+}
+
+QSizePolicy Shadow::sizePolicy() const
+{
+ return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+}
+
+void Shadow::setDisplay(bool show)
+{
+ _show = show;
+ update();
+}
+
+void Shadow::paintEvent(QPaintEvent *)
+{
+ if ( !_show ) return;
+
+ const Piece *piece = _board->currentPiece();
+ uint pf = piece->min().first + _board->currentPos().first;
+ uint pl = pf + piece->size().first - 1;
+
+ QPainter p(this);
+ p.setBrush(black);
+ p.setPen(black);
+ for (uint i=pf; i<=pl; i++) {
+ QRect r(_xOffset + i * BasePrefs::blockSize() + 1 , 0,
+ BasePrefs::blockSize() - 2, SHADOW_HEIGHT);
+ p.drawRect(r);
+ }
+}
+
+
+/*****************************************************************************/
+class Led : public QWidget
+{
+ public:
+ Led(const QColor &c, QWidget *parent)
+ : QWidget(parent), col(c), _on(FALSE) {}
+
+ QSizePolicy sizePolicy() const
+ { return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); }
+ QSize sizeHint() const { return QSize(LED_WIDTH, LED_HEIGHT); }
+
+ void on() { if (!_on) { _on = TRUE; repaint(); } }
+ void off() { if (_on) {_on = FALSE; repaint(); } }
+ void setColor(const QColor &c) { if (c!=col) { col = c; repaint(); } }
+
+ protected:
+ void paintEvent(QPaintEvent *) {
+ QPainter p(this);
+ p.setBrush((_on ? col.light() : col.dark()));
+ p.setPen(black);
+ p.drawEllipse(0, 0, width(), height());
+ }
+
+ private:
+ QColor col;
+ bool _on;
+};
+
+GiftPool::GiftPool(QWidget *parent)
+ : QHBox(parent, "gift_pool"), nb(0), ready(false)
+{
+ setSpacing(LED_SPACING);
+ leds.resize(cfactory->cbi.nbGiftLeds);
+ for (uint i=0; i<leds.size(); i++)
+ leds.insert(i, new Led(yellow, this));
+}
+
+QSize GiftPool::sizeHint() const
+{
+ QSize s = (leds.size() ? leds[0]->sizeHint() : QSize());
+ return QSize((s.width()+LED_SPACING)*leds.size()-LED_SPACING, s.height());
+}
+
+QSizePolicy GiftPool::sizePolicy() const
+{
+ return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+}
+
+void GiftPool::put(uint n)
+{
+ if ( n==0 ) return;
+ if ( nb==0 && !ready )
+ QTimer::singleShot(cfactory->cbi.giftPoolTimeout,
+ this, SLOT(timeout()));
+ uint e = QMIN(nb+n, leds.size());
+ for (uint i=nb; i<e; i++) leds[i]->on();
+ uint f = QMIN(nb+n-e, leds.size());
+ for (uint i=0; i<f; i++) leds[i]->setColor(red);
+ nb += n;
+}
+
+uint GiftPool::take()
+{
+ Q_ASSERT(ready);
+ for (uint i=0; i<leds.size(); i++) {
+ leds[i]->setColor(yellow);
+ leds[i]->off();
+ }
+ uint max = cfactory->cbi.maxGiftsToSend;
+ if ( nb>max ) {
+ uint p = nb - max;
+ nb = 0;
+ put(p);
+ return max;
+ } else {
+ ready = false;
+ uint t = nb;
+ nb = 0;
+ return t;
+ }
+}
+
+void GiftPool::reset()
+{
+ killTimers();
+ ready = false;
+ nb = 0;
+ for (uint i=0; i<leds.size(); i++) {
+ leds[i]->setColor(yellow);
+ leds[i]->off();
+ }
+}
+
+//-----------------------------------------------------------------------------
+PlayerProgress::PlayerProgress(BaseBoard *board, QWidget *parent,
+ const char *name)
+ : KGameProgress(0, board->matrix().height(), 0, KGameProgress::Vertical,
+ parent, name), _board(board)
+{
+ setBackgroundColor(lightGray);
+ setTextEnabled(false);
+ setBarColor(blue);
+ KZoomMainWindow::addWidget(this);
+}
+
+QSize PlayerProgress::sizeHint() const
+{
+ return QSize(10, _board->matrix().height() * BasePrefs::blockSize())
+ + 2 * QSize(frameWidth(), frameWidth());
+}
+
+QSizePolicy PlayerProgress::sizePolicy() const
+{
+ return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+}
diff --git a/libksirtet/common/misc_ui.h b/libksirtet/common/misc_ui.h
new file mode 100644
index 00000000..3a89acaa
--- /dev/null
+++ b/libksirtet/common/misc_ui.h
@@ -0,0 +1,81 @@
+#ifndef COMMON_MISC_UI_H
+#define COMMON_MISC_UI_H
+
+#include <qcanvas.h>
+#include <qptrvector.h>
+#include <qhbox.h>
+
+#include <kgameprogress.h>
+#include "lib/libksirtet_export.h"
+
+#include "base/board.h"
+
+/*****************************************************************************/
+class LIBKSIRTET_EXPORT ShowNextPiece : public FixedCanvasView
+{
+ Q_OBJECT
+ public:
+ ShowNextPiece(BaseBoard *, QWidget *parent);
+};
+
+/*****************************************************************************/
+class LIBKSIRTET_EXPORT Shadow : public QWidget
+{
+ Q_OBJECT
+ public:
+ Shadow(BaseBoard *, QWidget *parent);
+
+ virtual QSize sizeHint() const;
+ virtual QSizePolicy sizePolicy() const;
+ void setDisplay(bool show);
+
+ private:
+ int _xOffset;
+ const BaseBoard *_board;
+ bool _show;
+
+ void paintEvent(QPaintEvent *);
+};
+
+/*****************************************************************************/
+class Led;
+
+class LIBKSIRTET_EXPORT GiftPool : public QHBox
+{
+ Q_OBJECT
+ public:
+ GiftPool(QWidget *parent);
+
+ virtual QSize sizeHint() const;
+ virtual QSizePolicy sizePolicy() const;
+
+ void reset();
+ void put(uint);
+ uint take();
+ bool pending() const { return ready; }
+
+ private slots:
+ void timeout() { ready = true; }
+
+ private:
+ QPtrVector<Led> leds;
+ uint _timeout, nb;
+ bool ready;
+};
+
+
+/*****************************************************************************/
+class LIBKSIRTET_EXPORT PlayerProgress : public KGameProgress
+{
+ Q_OBJECT
+public:
+ PlayerProgress(BaseBoard *board, QWidget *parent = 0, const char *name = 0);
+
+ virtual QSize sizeHint() const;
+ virtual QSizePolicy sizePolicy() const;
+
+private:
+ BaseBoard *_board;
+};
+
+#endif
diff --git a/libksirtet/common/settings.cpp b/libksirtet/common/settings.cpp
new file mode 100644
index 00000000..902d1e56
--- /dev/null
+++ b/libksirtet/common/settings.cpp
@@ -0,0 +1,54 @@
+#include "settings.h"
+#include "settings.moc"
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qwhatsthis.h>
+
+#include <klocale.h>
+#include <knuminput.h>
+#include <kdialog.h>
+#include <kglobal.h>
+
+
+//-----------------------------------------------------------------------------
+AppearanceConfig::AppearanceConfig()
+{
+ int row = _grid->numRows();
+ int col = _grid->numCols();
+
+ QCheckBox *cb = new QCheckBox(i18n("Show piece's shadow"), _main, "kcfg_ShowPieceShadow");
+ _grid->addMultiCellWidget(cb, row, row, 0, col-1);
+
+ cb = new QCheckBox(i18n("Show next piece"), _main, "kcfg_ShowNextPiece");
+ _grid->addMultiCellWidget(cb, row+1, row+1, 0, col-1);
+
+ cb = new QCheckBox(i18n("Show detailed \"removed lines\" field"), _main, "kcfg_ShowDetailedRemoved");
+ _grid->addMultiCellWidget(cb, row+2, row+2, 0, col-1);
+}
+
+//-----------------------------------------------------------------------------
+GameConfig::GameConfig()
+ : QWidget(0, "game config")
+{
+ QVBoxLayout *top = new QVBoxLayout(this, KDialog::marginHint(), KDialog::spacingHint());
+
+ _grid = new QGridLayout(top, 3, 2);
+ _grid->setColStretch(1, 1);
+
+ QLabel *label = new QLabel(i18n("Initial level:"), this);
+ _grid->addWidget(label, 0, 0);
+ KIntNumInput *in = new KIntNumInput(this, "kcfg_InitialGameLevel");
+ in->setRange(1, 20, 1, true);
+ _grid->addWidget(in, 0, 1);
+
+ _grid->addRowSpacing(1, KDialog::spacingHint());
+
+ QCheckBox *cb = new QCheckBox(i18n("Direct drop down"), this, "kcfg_DirectDropDownEnabled");
+ QWhatsThis::add(cb, i18n("Drop down is not stopped when drop down key is released."));
+ _grid->addMultiCellWidget(cb, 2, 2, 0, 1);
+
+ top->addStretch(1);
+}
+
diff --git a/libksirtet/common/settings.h b/libksirtet/common/settings.h
new file mode 100644
index 00000000..ceda13a1
--- /dev/null
+++ b/libksirtet/common/settings.h
@@ -0,0 +1,28 @@
+#ifndef COMMON_SETTINGS_H
+#define COMMON_SETTINGS_H
+
+#include "base/settings.h"
+
+#include "lib/libksirtet_export.h"
+
+
+//-----------------------------------------------------------------------------
+class LIBKSIRTET_EXPORT AppearanceConfig : public BaseAppearanceConfig
+{
+ Q_OBJECT
+public:
+ AppearanceConfig();
+};
+
+//-----------------------------------------------------------------------------
+class LIBKSIRTET_EXPORT GameConfig : public QWidget
+{
+ Q_OBJECT
+public:
+ GameConfig();
+
+protected:
+ QGridLayout *_grid;
+};
+
+#endif
diff --git a/libksirtet/common/types.cpp b/libksirtet/common/types.cpp
new file mode 100644
index 00000000..05d91db3
--- /dev/null
+++ b/libksirtet/common/types.cpp
@@ -0,0 +1,16 @@
+#include "types.h"
+
+LIBKSIRTET_EXPORT QDataStream &operator <<(QDataStream &s, const ClientPlayData &d)
+ { s << d.height << d.gift << d.end; return s; }
+LIBKSIRTET_EXPORT QDataStream &operator >>(QDataStream &s, ClientPlayData &d)
+ { s >> d.height >> d.gift >> d.end; return s; }
+
+LIBKSIRTET_EXPORT QDataStream &operator <<(QDataStream &s, const ServerPlayData &d)
+ { s << d.prevHeight << d.nextHeight << d.gift; return s; }
+LIBKSIRTET_EXPORT QDataStream &operator >>(QDataStream &s, ServerPlayData &d)
+ { s >> d.prevHeight >> d.nextHeight >> d.gift; return s; }
+
+LIBKSIRTET_EXPORT QDataStream &operator <<(QDataStream &s, const ServerInitData &d)
+{ s << d.initLevel << d.seed << d.nextName << d.prevName << d.name; return s; }
+LIBKSIRTET_EXPORT QDataStream &operator >>(QDataStream &s, ServerInitData &d)
+{ s >> d.initLevel >> d.seed >> d.nextName >> d.prevName >> d.name; return s; }
diff --git a/libksirtet/common/types.h b/libksirtet/common/types.h
new file mode 100644
index 00000000..8a30d276
--- /dev/null
+++ b/libksirtet/common/types.h
@@ -0,0 +1,26 @@
+#ifndef COMMON_TYPES_H
+#define COMMON_TYPES_H
+
+#include <qdatastream.h>
+
+#include "lib/libksirtet_export.h"
+
+
+struct ClientPlayData { Q_UINT8 height, gift, end; };
+LIBKSIRTET_EXPORT QDataStream &operator <<(QDataStream &s, const ClientPlayData &d);
+LIBKSIRTET_EXPORT QDataStream &operator >>(QDataStream &s, ClientPlayData &d);
+
+struct ServerPlayData { Q_UINT8 prevHeight, nextHeight, gift; };
+LIBKSIRTET_EXPORT QDataStream &operator <<(QDataStream &s, const ServerPlayData &d);
+LIBKSIRTET_EXPORT QDataStream &operator >>(QDataStream &s, ServerPlayData &d);
+
+class ServerInitData
+{
+ public:
+ QString prevName, nextName, name;
+ Q_UINT32 initLevel, seed;
+};
+LIBKSIRTET_EXPORT QDataStream &operator <<(QDataStream &s, const ServerInitData &d);
+LIBKSIRTET_EXPORT QDataStream &operator >>(QDataStream &s, ServerInitData &d);
+
+#endif