summaryrefslogtreecommitdiffstats
path: root/kwin4/kwin4/kwin4doc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kwin4/kwin4/kwin4doc.cpp')
-rw-r--r--kwin4/kwin4/kwin4doc.cpp1322
1 files changed, 1322 insertions, 0 deletions
diff --git a/kwin4/kwin4/kwin4doc.cpp b/kwin4/kwin4/kwin4doc.cpp
new file mode 100644
index 00000000..4c85f70e
--- /dev/null
+++ b/kwin4/kwin4/kwin4doc.cpp
@@ -0,0 +1,1322 @@
+/***************************************************************************
+ kwin4doc.cpp - Boardgame for KDE
+ -------------------
+ begin : Sun Mar 26 12:50:12 CEST 2000
+ copyright : (C) |1995-2000 by Martin Heni
+ email : martin@heni-online.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kwin4doc.h"
+
+// include files for Qt
+#include <qdir.h>
+#include <qtimer.h>
+
+// include files for KDE
+#include <klocale.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <krandomsequence.h>
+#include <kapplication.h>
+
+// application specific includes
+#include "kspritecache.h"
+#include "kwin4view.h"
+#include "scorewidget.h"
+#include "prefs.h"
+#include "statuswidget.h"
+
+Kwin4Doc::Kwin4Doc(QWidget *parent, const char *) : KGame(1234,parent), pView(0), mHintProcess(0)
+{
+ connect(this,SIGNAL(signalPropertyChanged(KGamePropertyBase *,KGame *)),
+ this,SLOT(slotPropertyChanged(KGamePropertyBase *,KGame *)));
+
+ dataHandler()->Debug();
+ //kdDebug(12010) << "Property 7 policy=" << dataHandler()->find(7)->policy() << endl;
+ setPolicy(KGame::PolicyDirty,true);
+
+ //kdDebug(12010) << "Property 7 policy=" << dataHandler()->find(7)->policy() << endl;
+
+ // Game design
+ setMaxPlayers(2);
+ setMinPlayers(2);
+
+ // Game initialization
+ mField.resize(42);
+
+ // ****************************************
+ // NOTE: Do not i18n the strings here. They
+ // are for debugging only
+ // ****************************************
+
+ // The field array needs not be updated as any move will change it
+ // Careful only in new ResetGame! Maybe unlocal it there!
+ // mField.setPolicy(KGamePropertyBase::PolicyLocal);
+ mField.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mField"));
+
+ mFieldFilled.resize(7);
+ mHistory.resize(43);
+ mHistory.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mHistory"));
+
+ mAmzug.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mAmzug"));
+ mCurrentMove.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mCurrentMove"));
+ mMaxMove.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mMaxMove"));
+ mFieldFilled.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mFieldFilled"));
+ mHistoryCnt.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mHistoryCnt"));
+ mLastColumn.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mLastColumn"));
+ mLastHint.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mLastHint"));
+ mLastColour.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mLastColour"));
+ mScore.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,QString("mScore"));
+
+ // game startup parameter
+ mStartPlayer=Gelb;
+ mStartPlayer.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,QString("mStartPlayer"));
+ SetCurrentPlayer((FARBE)mStartPlayer.value());
+ if (global_debug>1) kdDebug(12010) << "amZug policy=" << mAmzug.policy() << endl;
+
+ mPlayedBy[Gelb]=KGameIO::MouseIO;
+ mPlayedBy[Rot]=KGameIO::MouseIO;
+
+ // last in init
+ ResetGame(false);
+
+ setGameStatus(Intro);
+
+ // Listen to network
+ connect(this,SIGNAL(signalMessageUpdate(int,Q_UINT32,Q_UINT32)),
+ this,SLOT(slotMessageUpdate(int, Q_UINT32,Q_UINT32)));
+ connect(this,SIGNAL(signalClientJoinedGame(Q_UINT32,KGame *)),
+ this,SLOT(slotClientConnected(Q_UINT32, KGame *)));
+
+ // Debug only
+ connect(this,SIGNAL(signalGameOver(int, KPlayer *,KGame *)),
+ this,SLOT(slotGameOver(int, KPlayer *,KGame *)));
+
+ // Change global KGame policy
+ //dataHandler()->setPolicy(KGamePropertyBase::PolicyDirty,false);
+ dataHandler()->Debug();
+}
+
+/**
+ * Player initialization
+ */
+void Kwin4Doc::initPlayers()
+{
+ // Create yellow
+ Kwin4Player *yellow = (Kwin4Player *)createPlayer(1, mPlayedBy[Gelb], false);
+ yellow->setUserId(Gelb);
+ yellow->setName(Prefs::name1());
+ addPlayer(yellow);
+ setPlayedBy(Gelb,mPlayedBy[Gelb]);
+
+ // Create Red
+ Kwin4Player *red = (Kwin4Player *)createPlayer(1, mPlayedBy[Rot], false);
+ red->setUserId(Rot);
+ red->setName(Prefs::name1());
+ addPlayer(red);
+ setPlayedBy(Rot,mPlayedBy[Rot]);
+}
+
+Kwin4Doc::~Kwin4Doc()
+{
+ WriteConfig(kapp->config());
+ if (mHintProcess)
+ delete mHintProcess;
+}
+
+void Kwin4Doc::setView(Kwin4View *view)
+{
+ pView=view;
+}
+
+/**
+ * Returns colour
+ */
+FARBE Kwin4Doc::QueryColour(int x,int y){
+ return (FARBE)mField.at(x+y*FIELD_SIZE_X);
+}
+
+/**
+ * Set the colour
+ */
+void Kwin4Doc::SetColour(int x,int y,FARBE c){
+ if (x<0 || x>=FIELD_SIZE_X || y<0 || y>=FIELD_SIZE_Y)
+ {
+ kdDebug(12010) << "ERROR: SetColour auf falsche Poition " << x << " " << y << endl;
+ return ;
+ }
+ //kdDebug(12010) << "SetColor::mField["<<x+y*FIELD_SIZE_X<<"="<<c<<endl;
+ mField.setAt(x+y*FIELD_SIZE_X,c);
+}
+
+/**
+ * Reset the whole game
+ */
+void Kwin4Doc::ResetGame(bool initview){
+ // Reset field
+ for (int x=0;x<FIELD_SIZE_X;x++)
+ {
+ for (int y=FIELD_SIZE_Y-1;y>=0;y--)
+ SetColour(x,y,Niemand);
+ }
+ mFieldFilled.fill(0);
+
+ // Reset game vars
+ mHistoryCnt=0;
+ mCurrentMove=0;
+ mMaxMove=0;
+ mLastColumn=-1;
+ mLastColour=Niemand;
+ SetScore(0);
+ mLastHint=-1;
+
+ // Reset the view
+ if (initview)
+ pView->initView(false);
+
+ // Who starts this game
+ SetCurrentPlayer((FARBE)mStartPlayer.value());
+}
+
+/**
+ * Set current player to setTurn true
+ */
+void Kwin4Doc::preparePlayerTurn()
+{
+ if (global_debug>1)
+ kdDebug(12010) << "Setting the current player to turn"<<endl;
+ getPlayer(QueryCurrentPlayer())->setTurn(true,true);
+}
+
+/**
+ * End a game
+ */
+void Kwin4Doc::EndGame(TABLE mode)
+{
+ setGameStatus(End);
+ pView->clearError();
+ pView->EndGame();
+ Kwin4Player *yellow=getPlayer(Gelb);
+ Kwin4Player *red=getPlayer(Rot);
+
+ switch(mode)
+ {
+ case TWin: yellow->incWin();
+ red->incLost();
+ break;
+ case TLost: yellow->incLost();
+ red->incWin();
+ break;
+ case TRemis: yellow->incRemis();
+ red->incRemis();
+ break;
+ default:
+ // Only break if moves have been made
+ if (mMaxMove>0)
+ {
+ yellow->incBrk();
+ red->incBrk();
+ }
+ break;
+ }
+ // switch start player
+}
+
+void Kwin4Doc::moveDone(QCanvasItem *item,int )
+{
+ //kdDebug(12010) << "########################## SPRITE MOVE DONE ################# " << endl;
+ //Debug();
+ //for (KPlayer* p=playerList()->first(); p!= 0; p=playerList()->next() )
+ //{
+ // p->Debug();
+ //}
+
+ if (playerCount()>1)
+ playerInputFinished(getPlayer(QueryCurrentPlayer()));
+
+ pView->clearError();
+
+ KSprite *sprite=(KSprite *)item;
+ sprite->deleteNotify();
+}
+
+/**
+ * Calcualte the next players turn
+ */
+KPlayer * Kwin4Doc::nextPlayer(KPlayer *last,bool /*exclusive*/)
+{
+ if (global_debug>1)
+ kdDebug(12010) << k_funcinfo << "nextPlayer last="<<last->id() << " admin=" << isAdmin() <<endl;
+
+ // Should be enough if the admin sets the turn
+ if (last->userId()==Gelb)
+ SetCurrentPlayer(Rot);
+ else
+ SetCurrentPlayer(Gelb);
+ if (global_debug>1)
+ kdDebug(12010) <<" Current set to "<<QueryCurrentPlayer()<<endl;
+ if (isAdmin())
+ getPlayer(QueryCurrentPlayer())->setTurn(true,true);
+ emit signalMoveDone(0,0);
+ return getPlayer(QueryCurrentPlayer());
+}
+
+/**
+ * Make a game move
+ * mode=0 normal move, =1: redo move
+ */
+MOVESTATUS Kwin4Doc::MakeMove(int x,int mode){
+ if (x<0 || x>=FIELD_SIZE_X)
+ {
+ kdDebug(12010) << "ERROR: MakeMove auf falsche Position " << x << endl;
+ return GNotAllowed;
+ }
+
+ int y=mFieldFilled.at(x);
+
+ if (y>=FIELD_SIZE_Y)
+ {
+ return GIllMove; // no space left in column
+ }
+
+ if (mLastHint>=0)
+ {
+ int hy;
+ hy=mFieldFilled.at(mLastHint);
+ SetColour(mLastHint,hy,Niemand);
+ mLastHint=-1;
+ }
+ if (mode==Tip)
+ {
+ mLastHint=x;
+ SetColour(x,y,Tip);
+ return GTip ; // no real move
+ }
+
+ mFieldFilled.setAt(x,mFieldFilled.at(x)+1);
+ SetColour(x,y,QueryCurrentPlayer());
+
+ mHistory.setAt(QueryHistoryCnt(),x);
+ mHistoryCnt=mHistoryCnt.value()+1;
+
+ mLastColour=QueryCurrentPlayer();
+ //if (QueryCurrentPlayer()==Gelb) SetCurrentPlayer(Rot);
+ //else SetCurrentPlayer(Gelb);
+
+ mCurrentMove=mCurrentMove.value()+1;
+
+ // only if a real move isdone the maxmove is raised
+ if (mode==0) mMaxMove=mCurrentMove.value();
+ mLastColumn=x;
+
+ pView->setArrow(x,mLastColour);
+ // animation onyl if no redo
+ pView->setPiece(x,y,mLastColour,mCurrentMove-1,mode==1?false:true);
+ pView->setHint(0,0,false);
+
+ return GNormal;
+}
+
+
+/**
+ * Undo a move
+ */
+bool Kwin4Doc::UndoMove(){
+ //kdDebug(12010) <<" undo: current player="<<QueryCurrentPlayer() << endl;
+ //kdDebug(12010) <<" undo: history="<<QueryHistoryCnt() << endl;
+ if (QueryHistoryCnt()<1)
+ return false;
+
+ if (mLastHint>=0)
+ {
+ int hy;
+ hy=mFieldFilled.at(mLastHint);
+ SetColour(mLastHint,hy,Niemand);
+ mLastHint=-1;
+ }
+ // kdDebug(12010) << "Undo no="<<mHistoryCnt.value() << endl;
+ mHistoryCnt=mHistoryCnt.value()-1;
+ int x=mHistory.at(QueryHistoryCnt());
+ mFieldFilled.setAt(x,mFieldFilled.at(x)-1);
+ int y=mFieldFilled.at(x);
+ // kdDebug(12010) << "Undo x="<<x << " y=" <<y << endl;
+ SetColour(x,y,Niemand);
+ // We have to remove the piece as well...
+ pView->setPiece(x,y,Niemand,mCurrentMove-1,false);
+
+ mLastColour=QueryCurrentPlayer();
+ if (QueryCurrentPlayer()==Gelb) SetCurrentPlayer(Rot);
+ else SetCurrentPlayer(Gelb);
+ mCurrentMove=mCurrentMove.value()-1;
+
+ // sprite no, arrow pos, arrow color, enable
+ int oldx=-1;
+ if (QueryHistoryCnt()>0) oldx=mHistory.at(QueryHistoryCnt()-1);
+ pView->setSprite(mCurrentMove+1,oldx,QueryHistoryCnt()>0?mLastColour.value():0,false);
+ pView->setHint(0,0,false);
+
+ if (QueryHistoryCnt()>0)
+ mLastColumn=mHistory.at(QueryHistoryCnt()-1);
+ else
+ mLastColumn=-1;
+
+ SetScore(0);
+
+ return true;
+}
+
+/**
+ * Redo a move
+ */
+bool Kwin4Doc::RedoMove(){
+ //kdDebug(12010) << "mMaxMove=" << mMaxMove.value() << " historycnt=" << QueryHistoryCnt() << endl;
+ if (QueryHistoryCnt()>=mMaxMove)
+ return false;
+
+ int x=mHistory.at(QueryHistoryCnt());
+ //kdDebug(12010) << "Redo x=" << x << endl;
+ MakeMove(x,1);
+ if (QueryCurrentPlayer()==Gelb)
+ SetCurrentPlayer(Rot);
+ else
+ SetCurrentPlayer(Gelb);
+ SetScore(0);
+ pView->setHint(0,0,false);
+ return true;
+}
+
+/**
+ * Set the name of col
+ */
+void Kwin4Doc::SetName(FARBE i, const QString &n){
+ getPlayer(i)->setName(n);
+}
+
+/**
+ * Query the name of i
+ */
+QString Kwin4Doc::QueryName(FARBE i){
+ return getPlayer(i)->name();
+}
+
+/**
+ * Returns the all time statistics for player i
+ */
+int Kwin4Doc::QueryStat(FARBE i,TABLE mode){
+ Kwin4Player *player=getPlayer(i);
+ switch(mode)
+ {
+ case TWin: return player->win();
+ break;
+ case TRemis: return player->remis();
+ break;
+ case TLost: return player->lost();
+ break;
+ case TBrk: return player->brk();
+ break;
+ case TSum: return (player->win()+player->remis()+player->lost());
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * Query the colour of player i
+ */
+FARBE Kwin4Doc::QueryPlayerColour(int player){
+ if (player==0)
+ return (FARBE)mStartPlayer.value();
+
+ if (mStartPlayer.value()==Gelb)
+ return Rot;
+ else
+ return Gelb;
+}
+
+/** */
+int Kwin4Doc::CheckGameOver(int x, FARBE col){
+ int y,i;
+ FARBE c;
+ int star=1;
+ FARBE winc=Niemand;
+
+ // Check vertical up
+ int flag=0;
+ for (i=0;i<4;i++)
+ {
+ y=mFieldFilled.at(x)-1-i;
+ if (y>=0)
+ {
+ c=QueryColour(x,y);
+ if (c==col) flag++;
+ }
+ }
+ if (flag>=4 /*&& doBlink*/)
+ {
+ // Store win fields
+ for (i=0;i<4;i++)
+ {
+ y=mFieldFilled.at(x)-1-i;
+ pView->drawStar(x,y,star++);
+ winc=QueryColour(x,y);
+ }
+ return 1;
+ }
+ else if (flag>=4) return 1;
+
+ int xx;
+ // Check horizontal to the right
+ y=mFieldFilled.at(x)-1;
+ flag=0;
+ for (i=-3;i<=3 && flag<4;i++)
+ {
+ xx=x+i;
+ if (xx>=0 && xx<FIELD_SIZE_X)
+ {
+ c=QueryColour(xx,y);
+ if (c==col) flag++;
+ else flag=0;
+ }
+ }
+ if (flag>=4 /*&& doBlink*/)
+ {
+ // Store win fields
+ y=mFieldFilled.at(x)-1;
+ winc=QueryColour(x,y);
+ int cnt=0;
+ for (i=0;i<4;i++)
+ {
+ xx=x+i;
+ if (xx>=0 && xx<FIELD_SIZE_X)
+ {
+ if (QueryColour(xx,y)!=winc) break;
+ pView->drawStar(xx,y,star++);
+ cnt++;
+ }
+ else break;
+ }
+ for (i=-1;i>-4 && cnt<4;i--)
+ {
+ xx=x+i;
+ if (xx>=0 && xx<FIELD_SIZE_X)
+ {
+ if (QueryColour(xx,y)!=winc) break;
+ pView->drawStar(xx,y,star++);
+ cnt++;
+ }
+ else break;
+ }
+ return 1;
+ }
+ else if (flag>=4) return 1;
+
+
+ // Check dy+
+ flag=0;
+ for (i=-3;i<=3 && flag<4;i++)
+ {
+ xx=x+i;
+ if (xx>=0 && xx<FIELD_SIZE_X)
+ {
+ y=mFieldFilled.at(x)-1-i;
+ if (y>=0 && y<FIELD_SIZE_Y)
+ {
+ c=QueryColour(xx,y);
+ if (c==col) flag++;
+ else flag=0;
+ }
+ }
+ }
+ if (flag>=4 /*&& doBlink*/)
+ {
+ // Store win fields
+ y=mFieldFilled.at(x)-1;
+ winc=QueryColour(x,y);
+ int cnt=0;
+ for (i=0;i<4;i++)
+ {
+ xx=x+i;
+ if (xx>=0 && xx<FIELD_SIZE_X)
+ {
+ y=mFieldFilled.at(x)-1-i;
+ if (y<0) break;
+ if (QueryColour(xx,y)!=winc) break;
+ pView->drawStar(xx,y,star++);
+ cnt++;
+ }
+ else break;
+ }
+ for (i=-1;i>-4 && cnt<4;i--)
+ {
+ xx=x+i;
+ if (xx>=0 && xx<FIELD_SIZE_X)
+ {
+ y=mFieldFilled.at(x)-1-i;
+ if (y>=FIELD_SIZE_Y) break;
+ if (QueryColour(xx,y)!=winc) break;
+ pView->drawStar(xx,y,star++);
+ cnt++;
+ }
+ else break;
+ }
+ return 1;
+ }
+ else if (flag>=4) return 1;
+
+
+ // Check dy-
+ flag=0;
+ for (i=-3;i<=3 && flag<4;i++)
+ {
+ xx=x+i;
+ if (xx>=0 && xx<FIELD_SIZE_X)
+ {
+ y=mFieldFilled.at(x)-1+i;
+ if (y>=0 && y<FIELD_SIZE_Y)
+ {
+ c=QueryColour(xx,y);
+ if (c==col) flag++;
+ else flag=0;
+ }
+ }
+ }
+ if (flag>=4 /*&& doBlink*/)
+ {
+ // Store win fields
+ y=mFieldFilled.at(x)-1;
+ winc=QueryColour(x,y);
+ int cnt=0;
+ for (i=0;i<4;i++)
+ {
+ xx=x+i;
+ if (xx>=0 && xx<FIELD_SIZE_X)
+ {
+ y=mFieldFilled.at(x)-1+i;
+ if (y>=FIELD_SIZE_Y) break;
+ if (QueryColour(xx,y)!=winc) break;
+ pView->drawStar(xx,y,star++);
+ cnt++;
+ }
+ else break;
+ }
+ //kdDebug(12010) << "Found + cnt=" << cnt <<endl;
+ for (i=-1;i>-4 && cnt<4;i--)
+ {
+ xx=x+i;
+ if (xx>=0 && xx<FIELD_SIZE_X)
+ {
+ y=mFieldFilled.at(x)-1+i;
+ if (y<0) break;
+ if (QueryColour(xx,y)!=winc) break;
+ pView->drawStar(xx,y,star++);
+ cnt++;
+ }
+ else break;
+ }
+ //kdDebug(12010) << "all cnt=" << cnt<<endl;
+ return 1;
+ }
+ else if (flag>=4) return 1;
+
+ if (mCurrentMove>=42) return -1;
+
+ return 0;
+}
+
+/**
+ * Reset the stats
+ */
+void Kwin4Doc::ResetStat(){
+ getPlayer(Gelb)->resetStats();
+ getPlayer(Rot)->resetStats();
+}
+
+/**
+ * Set computer score
+ */
+void Kwin4Doc::SetScore(long i){
+ mScore.setValue(i);
+}
+
+/**
+ * Height of a column
+ */
+int Kwin4Doc::QueryHeight(int x){
+ if (x<0 || x>=FIELD_SIZE_X)
+ {
+ kdError() << "ERROR: Query Height for wrong x " << x << endl;
+ return 0;
+ }
+ return mFieldFilled.at(x);
+}
+
+int Kwin4Doc::QueryLastHint(){
+ return mLastHint;
+}
+
+void Kwin4Doc::loadSettings(){
+ // TODO find out what to do with this...
+ // mLevel.setValue(Prefs::level());
+
+ SetName(Gelb, Prefs::name1());
+ SetName(Rot, Prefs::name2());
+
+ KGameIO::IOMode mode = KGameIO::MouseIO;
+
+ int m = Prefs::input1();
+ if(m == 0) mode = KGameIO::MouseIO;
+ if(m == 1) mode = KGameIO::ProcessIO;
+ if(m == 2) mode = KGameIO::KeyIO;
+ setPlayedBy(Gelb, mode);
+
+ m = Prefs::input2();
+ if(m == 0) mode = KGameIO::MouseIO;
+ if(m == 1) mode = KGameIO::ProcessIO;
+ if(m == 2) mode = KGameIO::KeyIO;
+ setPlayedBy(Rot, mode);
+
+ FARBE col = (FARBE)Prefs::colour1();
+ if (QueryPlayerColour(0)!=col)
+ SwitchStartPlayer();
+}
+
+/**
+ * read config file
+ */
+void Kwin4Doc::ReadConfig(KConfig *config)
+{
+ loadSettings();
+
+ config->setGroup("YellowPlayer");
+ getPlayer(Gelb)->readConfig(config);
+
+ config->setGroup("RedPlayer");
+ getPlayer(Rot)->readConfig(config);
+}
+
+/**
+ * write config file
+ */
+void Kwin4Doc::WriteConfig(KConfig *config)
+{
+ config->setGroup("YellowPlayer");
+ getPlayer(Gelb)->writeConfig(config);
+
+ config->setGroup("RedPlayer");
+ getPlayer(Rot)->writeConfig(config);
+
+ config->sync();
+}
+
+/**
+ * Returns the current player, resp amzug
+ */
+FARBE Kwin4Doc::QueryCurrentPlayer(){
+ return (FARBE)mAmzug.value();
+}
+
+void Kwin4Doc::SetCurrentPlayer(FARBE i)
+{
+ mAmzug.setValue(i);
+}
+
+/**
+ * Swtich the starting player and return the new started
+ */
+FARBE Kwin4Doc::SwitchStartPlayer()
+{
+ if (mStartPlayer.value()==Gelb)
+ mStartPlayer.setValue(Rot);
+ else
+ mStartPlayer.setValue(Gelb);
+
+ return (FARBE)mStartPlayer.value();
+}
+
+int Kwin4Doc::QueryLastcolumn()
+{
+ return mLastColumn;
+}
+
+FARBE Kwin4Doc::QueryLastcolour()
+{
+ return (FARBE)(mLastColour.value());
+}
+
+int Kwin4Doc::QueryCurrentMove()
+{
+ return mCurrentMove;
+}
+
+void Kwin4Doc::SetCurrentMove(int i)
+{
+ mCurrentMove=i;
+}
+
+int Kwin4Doc::QueryMaxMove()
+{
+ return mMaxMove;
+}
+
+int Kwin4Doc::QueryHistoryCnt()
+{
+ return mHistoryCnt;
+}
+
+/**
+ * Return the name of the computer player process
+ */
+QString Kwin4Doc::QueryProcessName()
+{
+ // First try a local dir override
+ QDir dir;
+ QString filename=dir.path()+QString("/kwin4/kwin4proc");
+ QFile flocal(filename);
+ if (flocal.exists())
+ {
+ if (global_debug>1) kdDebug(12010) << " Found local process " << filename << endl;
+ return filename;
+ }
+ QString path=kapp->dirs()->findExe("kwin4proc");
+ if (!path.isNull())
+ {
+ if (global_debug>1) kdDebug(12010) << " Found system process " << path << endl;
+ return path;
+ }
+ QString empty;
+ kdError() << "Could not locate the computer player" << endl;
+ return empty;
+}
+
+void Kwin4Doc::slotMessageUpdate(int /*id*/,Q_UINT32 /*sender*/,Q_UINT32 /*recv*/)
+{
+// kdDebug(12010) << "MSG: id=" << id << " sender=" << sender << " receiver="<<recv<< endl;
+}
+
+/**
+ * Create a KPlayer
+ */
+KPlayer *Kwin4Doc::createPlayer(int /*rtti*/,int io,bool isvirtual)
+{
+ KPlayer *player = new Kwin4Player;
+ if (!isvirtual)
+ createIO(player,(KGameIO::IOMode)io);
+
+ connect(player,SIGNAL(signalPropertyChanged(KGamePropertyBase *, KPlayer *)),
+ this,SLOT(slotPlayerPropertyChanged(KGamePropertyBase *, KPlayer *)));
+ ((Kwin4Player *)player)->setWidget(pView->statusWidget());
+ return player;
+}
+
+/**
+ * Called when a player input is received from the KGame object
+ * this is e-.g. a mouse event
+ */
+bool Kwin4Doc::playerInput(QDataStream &msg, KPlayer * /*player*/)
+{
+ int move, pl;
+ msg >> pl >> move;
+ if (!Move(move,pl))
+ QTimer::singleShot(0, this,SLOT(slotRepeatMove()));
+
+ return false;
+}
+
+/**
+ * Reactivate player in case of a move which could not pe performed
+ */
+void Kwin4Doc::slotRepeatMove()
+{
+ getPlayer(QueryCurrentPlayer())->setTurn(true);
+}
+
+/**
+ * Performs a game move
+ */
+bool Kwin4Doc::Move(int x,int id)
+{
+ if (global_debug>1)
+ kdDebug(12010) <<" Kwin4Doc::Move("<<x<<","<<id<<")"<<endl;
+
+ return (MakeMove(x,0) == GNormal);
+}
+
+/**
+ * return -1: remis, 1:won, 0: continue
+ */
+int Kwin4Doc::checkGameOver(KPlayer *p)
+{
+ if (global_debug>1)
+ kdDebug(12010) <<"kwin4doc::checkGameOver::"<<p->userId()<<endl;
+ return CheckGameOver(QueryLastcolumn(),QueryLastcolour());
+}
+
+KGameIO::IOMode Kwin4Doc::playedBy(int col)
+{
+ return mPlayedBy[col];
+}
+
+void Kwin4Doc::setPlayedBy(int col, KGameIO::IOMode io)
+{
+ if (global_debug>1)
+ kdDebug(12010) << " Kwin4Doc::setPlayedBy(int "<<col<<",KGameIO::IOMode "<<io<<")" << endl;
+
+ Kwin4Player *player=getPlayer((FARBE)col);
+
+ if (mPlayedBy[col]!=io && !player->isVirtual())
+ {
+ mPlayedBy[col]=io;
+ player->removeGameIO(0); // remove all IO's
+ createIO(player,io);
+ }
+}
+
+/* Get the io values right after a load game as the io the playedby
+ * is not set there
+ */
+void Kwin4Doc::recalcIO()
+{
+ mPlayedBy[Gelb]=(KGameIO::IOMode)getPlayer(Gelb)->calcIOValue();
+ mPlayedBy[Rot]=(KGameIO::IOMode)getPlayer(Rot)->calcIOValue();
+}
+
+void Kwin4Doc::createIO(KPlayer *player,KGameIO::IOMode io)
+{
+ if (!player)
+ return;
+
+ if (global_debug>1)
+ kdDebug(12010) << " Kwin4Doc::createIO(KPlayer *player("<<player->userId()<<"),KGameIO::IOMode "<<io<<") " << endl;
+
+ if (io&KGameIO::MouseIO)
+ {
+ KGameMouseIO *input;
+ if (global_debug>1) kdDebug(12010) << "Creating MOUSE IO to "<<pView<< endl;
+ // We want the player to work over mouse
+ input=new KGameMouseIO(pView);
+ if (global_debug>1) kdDebug(12010) << "MOUSE IO added " << endl;
+ // Connect mouse input to a function to process the actual input
+ connect(input,SIGNAL(signalMouseEvent(KGameIO *,QDataStream &,QMouseEvent *,bool *)),
+ pView,SLOT(slotMouseInput(KGameIO *,QDataStream &,QMouseEvent *,bool *)));
+ player->addGameIO(input);
+ }
+ else if (io&KGameIO::ProcessIO)
+ {
+ QString file=QueryProcessName();
+ if (global_debug>1) kdDebug(12010) << "Creating PROCESS IO " << file << endl;
+
+ KGameProcessIO *input;
+ // We want a computer player
+ input=new KGameProcessIO(file);
+ // Connect computer player to the setTurn
+ connect(input,SIGNAL(signalPrepareTurn(QDataStream &,bool,KGameIO *,bool *)),
+ this,SLOT(slotPrepareTurn(QDataStream &,bool,KGameIO *,bool *)));
+
+ connect(input,SIGNAL(signalProcessQuery(QDataStream &,KGameProcessIO *)),
+ this,SLOT(slotProcessQuery(QDataStream &,KGameProcessIO *)));
+ player->addGameIO(input);
+ }
+ else if (io&KGameIO::KeyIO)
+ {
+ if (global_debug>1) kdDebug(12010) << "Creating KEYBOARD IO " << endl;
+ // We want the player to work over keyboard
+ KGameKeyIO *input;
+ input=new KGameKeyIO(pView->parentWidget());
+ // Connect keys input to a function to process the actual input
+ connect((KGameKeyIO *)input,SIGNAL(signalKeyEvent(KGameIO *,QDataStream &,QKeyEvent *,bool *)),
+ pView,SLOT(slotKeyInput(KGameIO *,QDataStream &,QKeyEvent *,bool *)));
+ player->addGameIO(input);
+ }
+}
+
+/**
+ * This slot is called when a computer move should be generated
+ */
+void Kwin4Doc::slotPrepareTurn(QDataStream &stream,bool b,KGameIO *input,bool *sendit)
+{
+ if (global_debug>1)
+ kdDebug(12010) << " Kwin4Doc::slotPrepareTurn b="<<b << endl;
+
+ *sendit=false;
+ // Our player
+ KPlayer *player=input->player();
+ if (!player->myTurn()) return ;
+ if (!b) return ; // only on setTurn(true)
+
+ Q_INT32 pl;
+ if (global_debug>1) kdDebug(12010) << "slotPrepareComputerTurn for player id= " << player->id() << endl;
+ pl=player->userId();
+
+ prepareGameMessage(stream,pl);
+
+ *sendit=true;
+}
+
+/**
+ * Sends the current game status to the computer player
+ * Careful: The data needs to be the same than the computer
+ * player reading on the other side
+ **/
+void Kwin4Doc::prepareGameMessage(QDataStream &stream, Q_INT32 pl)
+{
+ if (global_debug>1) kdDebug(12010) << " sending col=" << pl << endl;
+ stream << pl ;
+ // This needs to be the same than the computer player reads!
+ stream << (Q_INT32)QueryCurrentMove();
+ stream << (Q_INT32)QueryCurrentPlayer();
+ stream << (Q_INT32)QueryPlayerColour(0);
+ stream << (Q_INT32)QueryPlayerColour(1);
+ stream << (Q_INT32)Prefs::level();
+
+ int i,j;
+ for (i=0;i<FIELD_SIZE_Y;i++)
+ {
+ for (j=0;j<FIELD_SIZE_X;j++)
+ {
+ Q_INT8 col;
+ col=QueryColour(j,i);
+ stream << col;
+ }
+ if (global_debug>1) kdDebug(12010)
+ << QueryColour(0,i) << " "
+ << QueryColour(1,i) << " "
+ << QueryColour(2,i) << " "
+ << QueryColour(3,i) << " "
+ << QueryColour(4,i) << " "
+ << QueryColour(5,i) << " "
+ << QueryColour(6,i) << endl;
+ }
+ stream << (Q_INT32)421256;
+}
+
+void Kwin4Doc::slotProcessQuery(QDataStream &in,KGameProcessIO * /*me*/)
+{
+ Q_INT8 cid;
+ in >> cid;
+ switch(cid)
+ {
+ case 1: // value
+ long value;
+ in >> value;
+ if (global_debug>1) kdDebug(12010) << "#### Computer thinks value is " << value << endl;
+ SetScore(value);
+ break;
+ default:
+ kdError() << "Kwin4Doc::slotProcessQuery: Unknown id " << cid << endl;
+ break;
+ }
+}
+
+/**
+ * This slot is called by the signal of KGame to indicated
+ * that the network connection is done and a new client is
+ * connected
+ * cid is the id of the client connected. if this is equal
+ * gameId() WE are the client
+ */
+void Kwin4Doc::slotClientConnected(Q_UINT32 cid,KGame *)
+{
+ if (global_debug>1) kdDebug(12010) << " void Kwin4Doc::slotClientConnected id="<<cid << " we=" <<
+ gameId() << " we admin=" << isAdmin() << "master)" << isMaster() << endl;
+
+ if (playerList()->count()!=2)
+ {
+ kdError() << "SERIOUS ERROR: We do not have two players...Trying to disconnect!"<<endl;
+ disconnect();
+ return ;
+ }
+
+ // Get the two players - more are not possible
+ Kwin4Player *p1=(Kwin4Player *)playerList()->at(0);
+ Kwin4Player *p2=(Kwin4Player *)playerList()->at(1);
+ if (!p1->isVirtual())
+ {
+ emit signalChatChanged(p1);
+ if (global_debug>1) kdDebug(12010) << "CHAT to player 0 " << endl;
+ }
+ else
+ {
+ emit signalChatChanged(p2);
+ if (global_debug>1) kdDebug(12010) << "CHAT to player 1 " << endl;
+ }
+
+ // Now check whose turn it is. The Admin will rule this
+ if (isAdmin())
+ {
+ if (global_debug>1) kdDebug(12010) << "WE are ADMIN == COOL ! " << endl;
+ // p1 is local
+ if (!p1->isVirtual())
+ {
+ if (global_debug>1) kdDebug(12010) << "p1 id=" << p1->userId() << " is local turn="<<p1->myTurn()<< endl;
+ // Exclusive setting of the turn
+ p1->setTurn(p1->myTurn(),true);
+ p2->setTurn(!p1->myTurn(),true);
+ }
+ else if (!p2->isVirtual())
+ {
+ if (global_debug>1) kdDebug(12010) << "p2 id=" << p2->userId() << " is local turn="<<p2->myTurn()<< endl;
+ // Exclusive setting of the turn
+ p2->setTurn(p2->myTurn(),true);
+ p1->setTurn(!p2->myTurn(),true);
+ }
+ }
+}
+
+/**
+ * Get the KPlayer from the color by searching all players
+ * users id's
+ **/
+Kwin4Player *Kwin4Doc::getPlayer(FARBE col)
+{
+ Kwin4Player *p;
+ for ( p=(Kwin4Player *)playerList()->first(); p!= 0; p=(Kwin4Player *)playerList()->next() )
+ {
+ if (p->userId()==col)
+ return p;
+ }
+ kdError() << "SERIOUS ERROR: Cannot find player with colour " << col << ". CRASH imminent" << endl;
+ return 0;
+}
+
+/**
+ * We create a process which calulcates a computer move
+ * which is shown as hint
+ **/
+void Kwin4Doc::calcHint()
+{
+ // We allocate the hint process only if it is needed
+ if (!mHintProcess)
+ {
+ QString file=QueryProcessName();
+ if (global_debug>1) kdDebug(12010) << "Creating HINT PROCESS IO " << endl;
+
+ // We want a computer player
+ mHintProcess=new KGameProcessIO(file);
+
+ connect(mHintProcess,SIGNAL(signalProcessQuery(QDataStream &,KGameProcessIO *)),
+ this,SLOT(slotProcessHint(QDataStream &,KGameProcessIO *)));
+ }
+ Q_INT32 pl;
+ QByteArray buffer;
+ QDataStream stream(buffer,IO_WriteOnly);
+ pl=QueryCurrentPlayer();
+ prepareGameMessage(stream,pl);
+ mHintProcess->sendMessage(stream,2,0,gameId());
+}
+
+/**
+ * The compute rprocess sent a hint which we show in the
+ * game board
+ **/
+void Kwin4Doc::slotProcessHint(QDataStream &in,KGameProcessIO * /*me*/)
+{
+ Q_INT8 cid;
+ in >> cid;
+ switch(cid)
+ {
+ case 2: // Hint
+ {
+ Q_INT32 pl;
+ Q_INT32 move;
+ long value;
+ in >> pl >> move >> value;
+ if (global_debug>1) kdDebug(12010) << "#### Computer thinks pl=" << pl << " move =" << move << endl;
+ if (global_debug>1) kdDebug(12010) << "#### Computer thinks hint is " << move << " and value is " << value << endl;
+ int x=move;
+ int y=mFieldFilled.at(x);
+ pView->setHint(x,y,true);
+ }
+ break;
+ default:
+ kdError() << "Kwin4Doc::slotProcessHint: Unknown id " << cid << endl;
+ break;
+ }
+}
+
+/**
+ * Called when a player property has changed. We check whether the name
+ * changed and then update the score widget
+ * We should maybe do this for the other properties too to update
+ * the status widget...I am not sure here...we'll see
+ **/
+void Kwin4Doc::slotPlayerPropertyChanged(KGamePropertyBase *prop,KPlayer *player)
+{
+ if (!pView) return ;
+ if (prop->id()==KGamePropertyBase::IdName)
+ {
+ if (global_debug>1) kdDebug(12010) << "Player name id=" << player->userId() << " changed to " << player->name()<<endl;
+ pView->scoreWidget()->setPlayer(player->name(),player->userId());
+ }
+}
+
+void Kwin4Doc::slotPropertyChanged(KGamePropertyBase *prop,KGame *)
+{
+ if (!pView)
+ return ;
+
+ if (prop->id()==mCurrentMove.id())
+ {
+ pView->scoreWidget()->setMove(mCurrentMove);
+ }
+ else if (prop->id()==mScore.id())
+ {
+ int sc=mScore/10000;
+ if (sc==0 && mScore.value()>0) sc=1;
+ else if (sc==0 && mScore.value()<0) sc=-1;
+ pView->scoreWidget()->setChance(sc);
+ }
+ else if (prop->id()==mAmzug.id())
+ {
+ if (global_debug>1) kdDebug(12010) << "Amzug changed to " << mAmzug.value()<<endl;
+ pView->scoreWidget()->setTurn(mAmzug);
+ }
+ else if (prop->id()==KGamePropertyBase::IdGameStatus)
+ {
+ if (gameStatus()==Abort)
+ {
+ if (global_debug>1) kdDebug(12010) << "PropertyChanged::status signal game abort +++" << endl;
+ emit signalGameOver(2,getPlayer(QueryCurrentPlayer()),0); // 2 indicates Abort
+ }
+ else if (gameStatus()==Run)
+ {
+ if (global_debug>1) kdDebug(12010) << "PropertyChanged::status signal game run +++" << endl;
+ preparePlayerTurn(); // Set the current player to play
+ emit signalGameRun();
+ }
+ else if (gameStatus()==Init)
+ {
+ if (global_debug>1) kdDebug(12010) << "PropertyChanged::status signal game INIT +++" << endl;
+ ResetGame(true);
+ }
+ else
+ {
+ if (global_debug>1) kdDebug(12010) << "PropertyChanged::other status signal +++" << endl;
+ }
+
+ }
+}
+
+/**
+ * Called by KGame if the game has ended.
+ * DEBUG only as we do not need any extension to
+ * the KGame behavior
+ */
+void Kwin4Doc::slotGameOver(int status, KPlayer * p, KGame * /*me*/)
+{
+ if (global_debug>1) kdDebug(12010) << "SlotGameOver: status="<<status<<" lastplayer uid="<<p->userId()<<endl;
+
+}
+
+/**
+ * This is an overwritten function of KGame which is called
+ * when a game is loaded. This can either be via a networ
+ * connect or via a real load from file
+ **/
+bool Kwin4Doc::loadgame(QDataStream &stream,bool network,bool reset)
+{
+ if (global_debug>1)
+ kdDebug () << "loadgame() network=" << network << " reset="<< reset << endl;
+ if (!network) setGameStatus(End);
+
+ // Clear out the old game
+ if (global_debug>1) kdDebug(12010)<<"loadgame wants to reset the game"<<endl;
+ ResetGame(true);
+
+ // load the new game
+ bool res=KGame::loadgame(stream,network,reset);
+ if (global_debug>1) kdDebug(12010) << "amzug loaded to ="<<mAmzug.value() << endl;
+
+ // Replay the game be undoing and redoing
+ if (global_debug>1) kdDebug(12010) << "REDRAW GAME using undo/redo" << endl;
+ if (global_debug>1) kdDebug(12010) << "history cnt="<<mHistoryCnt.value() << endl;
+ if (global_debug>1) kdDebug(12010) << "amzug ="<<mAmzug.value() << endl;
+ int cnt=0;
+ while(UndoMove())
+ {
+ cnt++;
+ if (global_debug>1) kdDebug(12010) << "Undoing move "<<cnt<<endl;
+ }
+ if (global_debug>1) kdDebug(12010) << "amzug ="<<mAmzug.value() << endl;
+ while(cnt>0)
+ {
+ RedoMove();
+ cnt--;
+ if (global_debug>1) kdDebug(12010) << "Redoing move "<<cnt<<endl;
+ }
+ if (global_debug>1) kdDebug(12010) << "amzug ="<<mAmzug.value() << endl;
+
+ // Set the input devices
+ recalcIO();
+ // And set the right player to turn
+ preparePlayerTurn();
+
+ if (global_debug>1)
+ kdDebug(12010) << "loadgame done +++" << endl;
+ return res;
+}
+
+/**
+ * This is also an overwritten function of KGame. It is
+ * Called in the game negotiation upon connect. Here
+ * the games have to determine what player is remote and
+ * what is local
+ * This function is only called in the Admin.
+ */
+void Kwin4Doc::newPlayersJoin(KGamePlayerList * /*oldList*/,KGamePlayerList *newList,QValueList<int> &inactivate)
+{
+ if (global_debug>1)
+ kdDebug(12010) << "newPlayersJoin: START"<<endl;
+
+ Kwin4Player *yellow=getPlayer(Gelb);
+ Kwin4Player *red=getPlayer(Rot);
+ KPlayer *player;
+ // Take the master player with the higher priority. Prioirty is set
+ // be the network dialog
+ if (yellow->networkPriority()>red->networkPriority())
+ {
+ // Deactivate the lower one
+ inactivate.append(red->id());
+ if (global_debug>1) kdDebug(12010) << "ADMIN keeps yellow and kicks red= " << red->id()<<" userId/col="<<red->userId()<<endl;
+ // loop all client players and deactivate the one which have the color
+ // yellow
+ for ( player=newList->first(); player != 0; player=newList->next() )
+ {
+ if (player->userId()==yellow->userId())
+ {
+ inactivate.append(player->id());
+ if (global_debug>1) kdDebug(12010) << "Deactivate C1 " << player->id()<<" col="<<player->userId()<<endl;
+ }
+ }
+ }
+ else
+ {
+ // Deactivate the lower one
+ inactivate.append(yellow->id());
+ if (global_debug>1) kdDebug(12010) << "ADMIN keeps red and kicks yellow= " << yellow->id()<<" userId/col="<<yellow->userId()<<endl;
+ // loop all client players and deactivate the one which have the color
+ // red
+ for ( player=newList->first(); player != 0; player=newList->next() )
+ {
+ if (player->userId()==red->userId())
+ {
+ inactivate.append(player->id());
+ if (global_debug>1) kdDebug(12010) << "Deactivate C2 " << player->id()<<" col="<<player->userId()<<endl;
+ }
+ }
+ }
+ if (global_debug>1)
+ kdDebug(12010) << "newPlayersJoin: DONE"<<endl;
+}
+
+#include "kwin4doc.moc"