|
|
|
/***************************************************************************
|
|
|
|
twin4doc.cpp - Boardgame for TDE
|
|
|
|
-------------------
|
|
|
|
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 "twin4doc.h"
|
|
|
|
|
|
|
|
// include files for TQt
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
|
|
|
|
// include files for TDE
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tdeconfig.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <krandomsequence.h>
|
|
|
|
#include <tdeapplication.h>
|
|
|
|
|
|
|
|
// application specific includes
|
|
|
|
#include "kspritecache.h"
|
|
|
|
#include "twin4view.h"
|
|
|
|
#include "scorewidget.h"
|
|
|
|
#include "prefs.h"
|
|
|
|
#include "statuswidget.h"
|
|
|
|
|
|
|
|
Kwin4Doc::Kwin4Doc(TQWidget *parent, const char *) : KGame(1234,TQT_TQOBJECT(parent)), pView(0), mHintProcess(0)
|
|
|
|
{
|
|
|
|
connect(this,TQT_SIGNAL(signalPropertyChanged(KGamePropertyBase *,KGame *)),
|
|
|
|
this,TQT_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,TQString("mField"));
|
|
|
|
|
|
|
|
mFieldFilled.resize(7);
|
|
|
|
mHistory.resize(43);
|
|
|
|
mHistory.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mHistory"));
|
|
|
|
|
|
|
|
mAmzug.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mAmzug"));
|
|
|
|
mCurrentMove.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mCurrentMove"));
|
|
|
|
mMaxMove.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mMaxMove"));
|
|
|
|
mFieldFilled.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mFieldFilled"));
|
|
|
|
mHistoryCnt.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mHistoryCnt"));
|
|
|
|
mLastColumn.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mLastColumn"));
|
|
|
|
mLastHint.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mLastHint"));
|
|
|
|
mLastColour.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mLastColour"));
|
|
|
|
mScore.registerData(dataHandler(),KGamePropertyBase::PolicyLocal,TQString("mScore"));
|
|
|
|
|
|
|
|
// game startup parameter
|
|
|
|
mStartPlayer=Gelb;
|
|
|
|
mStartPlayer.registerData(dataHandler(),KGamePropertyBase::PolicyDirty,TQString("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,TQT_SIGNAL(signalMessageUpdate(int,TQ_UINT32,TQ_UINT32)),
|
|
|
|
this,TQT_SLOT(slotMessageUpdate(int, TQ_UINT32,TQ_UINT32)));
|
|
|
|
connect(this,TQT_SIGNAL(signalClientJoinedGame(TQ_UINT32,KGame *)),
|
|
|
|
this,TQT_SLOT(slotClientConnected(TQ_UINT32, KGame *)));
|
|
|
|
|
|
|
|
// Debug only
|
|
|
|
connect(this,TQT_SIGNAL(signalGameOver(int, KPlayer *,KGame *)),
|
|
|
|
this,TQT_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(TQCanvasItem *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 TQString &n){
|
|
|
|
getPlayer(i)->setName(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Query the name of i
|
|
|
|
*/
|
|
|
|
TQString 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(TDEConfig *config)
|
|
|
|
{
|
|
|
|
loadSettings();
|
|
|
|
|
|
|
|
config->setGroup("YellowPlayer");
|
|
|
|
getPlayer(Gelb)->readConfig(config);
|
|
|
|
|
|
|
|
config->setGroup("RedPlayer");
|
|
|
|
getPlayer(Rot)->readConfig(config);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* write config file
|
|
|
|
*/
|
|
|
|
void Kwin4Doc::WriteConfig(TDEConfig *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
|
|
|
|
*/
|
|
|
|
TQString Kwin4Doc::QueryProcessName()
|
|
|
|
{
|
|
|
|
// First try a local dir override
|
|
|
|
TQDir dir;
|
|
|
|
TQString filename=dir.path()+TQString("/twin4/twin4proc");
|
|
|
|
TQFile flocal(filename);
|
|
|
|
if (flocal.exists())
|
|
|
|
{
|
|
|
|
if (global_debug>1) kdDebug(12010) << " Found local process " << filename << endl;
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
TQString path=kapp->dirs()->findExe("twin4proc");
|
|
|
|
if (!path.isNull())
|
|
|
|
{
|
|
|
|
if (global_debug>1) kdDebug(12010) << " Found system process " << path << endl;
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
TQString empty;
|
|
|
|
kdError() << "Could not locate the computer player" << endl;
|
|
|
|
return empty;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Kwin4Doc::slotMessageUpdate(int /*id*/,TQ_UINT32 /*sender*/,TQ_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,TQT_SIGNAL(signalPropertyChanged(KGamePropertyBase *, KPlayer *)),
|
|
|
|
this,TQT_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(TQDataStream &msg, KPlayer * /*player*/)
|
|
|
|
{
|
|
|
|
int move, pl;
|
|
|
|
msg >> pl >> move;
|
|
|
|
if (!Move(move,pl))
|
|
|
|
TQTimer::singleShot(0, this,TQT_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) <<"twin4doc::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,TQT_SIGNAL(signalMouseEvent(KGameIO *,TQDataStream &,TQMouseEvent *,bool *)),
|
|
|
|
pView,TQT_SLOT(slotMouseInput(KGameIO *,TQDataStream &,TQMouseEvent *,bool *)));
|
|
|
|
player->addGameIO(input);
|
|
|
|
}
|
|
|
|
else if (io&KGameIO::ProcessIO)
|
|
|
|
{
|
|
|
|
TQString 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,TQT_SIGNAL(signalPrepareTurn(TQDataStream &,bool,KGameIO *,bool *)),
|
|
|
|
this,TQT_SLOT(slotPrepareTurn(TQDataStream &,bool,KGameIO *,bool *)));
|
|
|
|
|
|
|
|
connect(input,TQT_SIGNAL(signalProcessQuery(TQDataStream &,KGameProcessIO *)),
|
|
|
|
this,TQT_SLOT(slotProcessQuery(TQDataStream &,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,TQT_SIGNAL(signalKeyEvent(KGameIO *,TQDataStream &,TQKeyEvent *,bool *)),
|
|
|
|
pView,TQT_SLOT(slotKeyInput(KGameIO *,TQDataStream &,TQKeyEvent *,bool *)));
|
|
|
|
player->addGameIO(input);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This slot is called when a computer move should be generated
|
|
|
|
*/
|
|
|
|
void Kwin4Doc::slotPrepareTurn(TQDataStream &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)
|
|
|
|
|
|
|
|
TQ_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(TQDataStream &stream, TQ_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 << (TQ_INT32)QueryCurrentMove();
|
|
|
|
stream << (TQ_INT32)QueryCurrentPlayer();
|
|
|
|
stream << (TQ_INT32)QueryPlayerColour(0);
|
|
|
|
stream << (TQ_INT32)QueryPlayerColour(1);
|
|
|
|
stream << (TQ_INT32)Prefs::level();
|
|
|
|
|
|
|
|
int i,j;
|
|
|
|
for (i=0;i<FIELD_SIZE_Y;i++)
|
|
|
|
{
|
|
|
|
for (j=0;j<FIELD_SIZE_X;j++)
|
|
|
|
{
|
|
|
|
TQ_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 << (TQ_INT32)421256;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Kwin4Doc::slotProcessQuery(TQDataStream &in,KGameProcessIO * /*me*/)
|
|
|
|
{
|
|
|
|
TQ_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(TQ_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)
|
|
|
|
{
|
|
|
|
TQString file=QueryProcessName();
|
|
|
|
if (global_debug>1) kdDebug(12010) << "Creating HINT PROCESS IO " << endl;
|
|
|
|
|
|
|
|
// We want a computer player
|
|
|
|
mHintProcess=new KGameProcessIO(file);
|
|
|
|
|
|
|
|
connect(mHintProcess,TQT_SIGNAL(signalProcessQuery(TQDataStream &,KGameProcessIO *)),
|
|
|
|
this,TQT_SLOT(slotProcessHint(TQDataStream &,KGameProcessIO *)));
|
|
|
|
}
|
|
|
|
TQ_INT32 pl;
|
|
|
|
TQByteArray buffer;
|
|
|
|
TQDataStream 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(TQDataStream &in,KGameProcessIO * /*me*/)
|
|
|
|
{
|
|
|
|
TQ_INT8 cid;
|
|
|
|
in >> cid;
|
|
|
|
switch(cid)
|
|
|
|
{
|
|
|
|
case 2: // Hint
|
|
|
|
{
|
|
|
|
TQ_INT32 pl;
|
|
|
|
TQ_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(TQDataStream &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,TQValueList<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 "twin4doc.moc"
|