summaryrefslogtreecommitdiffstats
path: root/libkdegames/kgame/kgame.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitc90c389a8a8d9d8661e9772ec4144c5cf2039f23 (patch)
tree6d8391395bce9eaea4ad78958617edb20c6a7573 /libkdegames/kgame/kgame.cpp
downloadtdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.tar.gz
tdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegames@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'libkdegames/kgame/kgame.cpp')
-rw-r--r--libkdegames/kgame/kgame.cpp1475
1 files changed, 1475 insertions, 0 deletions
diff --git a/libkdegames/kgame/kgame.cpp b/libkdegames/kgame/kgame.cpp
new file mode 100644
index 00000000..101dbfcc
--- /dev/null
+++ b/libkdegames/kgame/kgame.cpp
@@ -0,0 +1,1475 @@
+/*
+ This file is part of the KDE games library
+ Copyright (C) 2001 Martin Heni (martin@heni-online.de)
+ Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/*
+ $Id$
+*/
+
+#include "kgame.h"
+#include "kgame.moc"
+#include "kgamepropertyhandler.h"
+#include "kgameproperty.h"
+#include "kplayer.h"
+#include "kgameio.h"
+#include "kgameerror.h"
+#include "kgamesequence.h"
+
+#include "kgamemessage.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <qbuffer.h>
+#include <qtimer.h>
+#include <qptrqueue.h>
+#include <qfile.h>
+
+#include <klocale.h>
+#include <krandomsequence.h>
+#include <kdebug.h>
+
+#define KGAME_LOAD_COOKIE 4210
+
+// try to place as much as possible here
+// many things are *not* possible here as KGame has to use some inline function
+class KGamePrivate
+{
+public:
+ KGamePrivate()
+ {
+ mUniquePlayerNumber = 0;
+ mPolicy=KGame::PolicyLocal;
+ mGameSequence = 0;
+ }
+
+ int mUniquePlayerNumber;
+ QPtrQueue<KPlayer> mAddPlayerList;// this is a list of to-be-added players. See addPlayer() docu
+ KRandomSequence* mRandom;
+ KGame::GamePolicy mPolicy;
+ KGameSequence* mGameSequence;
+
+
+ KGamePropertyHandler* mProperties;
+
+ // player lists
+ KGame::KGamePlayerList mPlayerList;
+ KGame::KGamePlayerList mInactivePlayerList;
+
+ //KGamePropertys
+ KGamePropertyInt mMaxPlayer;
+ KGamePropertyUInt mMinPlayer;
+ KGamePropertyInt mGameStatus; // Game running?
+ QValueList<int> mInactiveIdList;
+
+};
+
+// ------------------- GAME CLASS --------------------------
+KGame::KGame(int cookie,QObject* parent) : KGameNetwork(cookie,parent)
+{
+ kdDebug(11001) << k_funcinfo << " - " << this << ", sizeof(KGame)=" << sizeof(KGame) << endl;
+ d = new KGamePrivate;
+
+ d->mProperties = new KGamePropertyHandler(this);
+
+ d->mProperties->registerHandler(KGameMessage::IdGameProperty,
+ this,SLOT(sendProperty(int, QDataStream&, bool* )),
+ SLOT(emitSignal(KGamePropertyBase *)));
+ d->mMaxPlayer.registerData(KGamePropertyBase::IdMaxPlayer, this, i18n("MaxPlayers"));
+ d->mMaxPlayer.setLocal(-1); // Infinite
+ d->mMinPlayer.registerData(KGamePropertyBase::IdMinPlayer, this, i18n("MinPlayers"));
+ d->mMinPlayer.setLocal(0); // Always ok
+ d->mGameStatus.registerData(KGamePropertyBase::IdGameStatus, this, i18n("GameStatus"));
+ d->mGameStatus.setLocal(Init);
+ // d->mUniquePlayerNumber = 0;
+ d->mRandom = new KRandomSequence;
+ d->mRandom->setSeed(0);
+
+ connect(this, SIGNAL(signalClientConnected(Q_UINT32)),
+ this, SLOT(slotClientConnected(Q_UINT32)));
+ connect(this, SIGNAL(signalClientDisconnected(Q_UINT32,bool)),
+ this, SLOT(slotClientDisconnected(Q_UINT32,bool)));
+ connect(this, SIGNAL(signalConnectionBroken()),
+ this, SLOT(slotServerDisconnected()));
+
+ setGameSequence(new KGameSequence());
+
+ // BL: FIXME This signal does no longer exist. When we are merging
+ // MH: super....and how do I find out about the lost conenction now?
+ // KGame and KGameNetwork, this could be improved!
+// connect(this,SIGNAL(signalConnectionLost(KGameClient *)),
+// this,SLOT(slotConnectionLost(KGameClient *)));
+}
+
+KGame::~KGame()
+{
+ kdDebug(11001) << k_funcinfo << endl;
+// Debug();
+ reset();
+ delete d->mGameSequence;
+ delete d->mRandom;
+ delete d;
+ kdDebug(11001) << k_funcinfo << " done" << endl;
+}
+
+bool KGame::reset()
+{
+ deletePlayers();
+ deleteInactivePlayers();
+ return true;
+}
+
+void KGame::deletePlayers()
+{
+// kdDebug(11001) << k_funcinfo << endl;
+ KGamePlayerList tmp = d->mPlayerList; // in case of PolicyClean player=d->mPlayerList.first() is infinite
+ KPlayer *player;
+ while((player=tmp.first()))
+ {
+ delete player; // delete and removes the player
+ tmp.removeFirst();
+ }
+// kdDebug(11001) << k_funcinfo << " done" << endl;
+}
+
+void KGame::deleteInactivePlayers()
+{
+ KPlayer *player;
+ while((player=d->mInactivePlayerList.first()))
+ {
+ //player->setGame(0); // prevent call backs
+ d->mInactivePlayerList.remove(player);
+ delete player;
+ }
+}
+
+bool KGame::load(QString filename,bool reset)
+{
+ if (filename.isNull())
+ {
+ return false;
+ }
+ QFile f(filename);
+ if (!f.open(IO_ReadOnly))
+ {
+ return false;
+ }
+ QDataStream s( &f );
+ load(s,reset);
+ f.close();
+ return true;
+}
+
+bool KGame::load(QDataStream &stream,bool reset)
+{ return loadgame(stream, false,reset); }
+
+bool KGame::loadgame(QDataStream &stream, bool network,bool resetgame)
+{
+ // Load Game Data
+
+ // internal data
+ Q_INT32 c;
+ stream >> c; // cookie
+
+ if (c!=cookie())
+ {
+ kdWarning(11001) << "Trying to load different game version we="<<cookie() << " saved=" << c << endl;
+ bool result=false;
+ emit signalLoadError(stream,network,(int)c,result);
+ return result;
+ }
+ if (resetgame) reset();
+
+ uint i;
+ stream >> i;
+// setPolicy((GamePolicy)i);
+
+ stream >> d->mUniquePlayerNumber;
+
+ if (gameSequence())
+ {
+ gameSequence()->setCurrentPlayer(0); // TODO !!!
+ }
+ int newseed;
+ stream >> newseed;
+ d->mRandom->setSeed(newseed);
+
+ // Switch off the direct emitting of signals while
+ // loading properties. This can cause inconsistencies
+ // otherwise if a property emits and this emit accesses
+ // a property not yet loaded
+ // Note we habe to have this external locking to prevent the games unlocking
+ // to access the players
+ dataHandler()->lockDirectEmit();
+ KPlayer *player;
+ for ( player=playerList()->first(); player != 0; player=playerList()->next() )
+ {
+ player->dataHandler()->lockDirectEmit();
+ // kdDebug(11001) << "Player "<<player->id() << " to indirect emit" <<endl;
+ }
+
+ // Properties
+ dataHandler()->load(stream);
+
+ // If there is additional data to be loaded before players are loaded then do
+ // this here.
+ emit signalLoadPrePlayers(stream);
+
+ // Load Playerobjects
+ uint playercount;
+ stream >> playercount;
+ kdDebug(11001) << "Loading KGame " << playercount << " KPlayer objects " << endl;
+ for (i=0;i<playercount;i++)
+ {
+ KPlayer *newplayer=loadPlayer(stream,network);
+ systemAddPlayer(newplayer);
+ }
+
+ Q_INT16 cookie;
+ stream >> cookie;
+ if (cookie==KGAME_LOAD_COOKIE) {
+ kdDebug(11001) << " Game loaded propertly"<<endl;
+ } else {
+ kdError(11001) << " Game loading error. probably format error"<<endl;
+ }
+
+ // Switch back on the direct emitting of signals and emit the
+ // queued signals.
+ // Note we habe to have this external locking to prevent the games unlocking
+ // to access the players
+ dataHandler()->unlockDirectEmit();
+ for ( player=playerList()->first(); player != 0; player=playerList()->next() )
+ {
+ player->dataHandler()->unlockDirectEmit();
+ // kdDebug(11001) << "Player "<<player->id() << " to direct emit" <<endl;
+ }
+
+ emit signalLoad(stream);
+ return true;
+}
+
+bool KGame::save(QString filename,bool saveplayers)
+{
+ if (filename.isNull())
+ {
+ return false;
+ }
+ QFile f(filename);
+ if (!f.open(IO_WriteOnly))
+ {
+ return false;
+ }
+ QDataStream s( &f );
+ save(s,saveplayers);
+ f.close();
+ return true;
+}
+
+bool KGame::save(QDataStream &stream,bool saveplayers)
+{ return savegame(stream, false,saveplayers); }
+
+bool KGame::savegame(QDataStream &stream,bool /*network*/,bool saveplayers)
+{
+ // Save Game Data
+
+ // internal variables
+ Q_INT32 c=cookie();
+ stream << c;
+
+ uint p=(uint)policy();
+ stream << p;
+ stream << d->mUniquePlayerNumber;
+ int newseed=(int)d->mRandom->getLong(65535);
+ stream << newseed;
+ d->mRandom->setSeed(newseed);
+
+ // Properties
+ dataHandler()->save(stream);
+
+ // Save all data that need to be saved *before* the players are saved
+ emit signalSavePrePlayers(stream);
+
+ if (saveplayers)
+ {
+ savePlayers(stream,playerList());
+ }
+ else
+ {
+ stream << (uint)0; // no players saved
+ }
+
+ stream << (Q_INT16)KGAME_LOAD_COOKIE;
+
+ emit signalSave(stream);
+ return true;
+}
+
+void KGame::savePlayer(QDataStream &stream,KPlayer* p)
+{
+// this could be in KGameMessage as well
+ stream << (Q_INT32)p->rtti();
+ stream << (Q_INT32)p->id();
+ stream << (Q_INT32)p->calcIOValue();
+ p->save(stream);
+}
+
+void KGame::savePlayers(QDataStream &stream, KGamePlayerList *list)
+{
+ if (!list)
+ {
+ list=playerList();
+ }
+
+ Q_INT32 cnt=list->count();
+ kdDebug(11001) << "Saving KGame " << cnt << " KPlayer objects " << endl;
+ stream << cnt;
+ KPlayer *player;
+ for ( player=list->first(); player != 0; player=list->next() )
+ {
+ savePlayer(stream,player);
+ }
+}
+
+KPlayer *KGame::createPlayer(int /*rtti*/,int /*io*/,bool /*isvirtual*/)
+{
+ kdWarning(11001) << " No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! " << endl;
+ return new KPlayer;
+}
+KPlayer *KGame::loadPlayer(QDataStream& stream,bool isvirtual)
+{
+ Q_INT32 rtti,id,iovalue;
+ stream >> rtti >> id >> iovalue;
+ KPlayer *newplayer=findPlayer(id);
+ if (!newplayer)
+ {
+ kdDebug(11001) << k_funcinfo << "Player "<< id << " not found...asking user to create one " << endl;
+ newplayer=createPlayer(rtti,iovalue,isvirtual);
+ //emit signalCreatePlayer(newplayer,rtti,iovalue,isvirtual,this);
+ }
+ /*
+ if (!newplayer)
+ {
+ kdWarning(11001) << " No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! " << endl;
+ newplayer=new KPlayer;
+ }
+ else
+ {
+ kdDebug(11001) << " USER Player " << newplayer << " done player->rtti=" << newplayer->rtti() << " rtti=" << rtti << endl;
+ }
+ */
+ newplayer->load(stream);
+ if (isvirtual)
+ {
+ newplayer->setVirtual(true);
+ }
+ return newplayer;
+}
+
+// ----------------- Player handling -----------------------
+
+KPlayer * KGame::findPlayer(Q_UINT32 id) const
+{
+ for (QPtrListIterator<KPlayer> it(d->mPlayerList); it.current(); ++it)
+ {
+ if (it.current()->id() == id)
+ {
+ return it.current();
+ }
+ }
+ for (QPtrListIterator<KPlayer> it(d->mInactivePlayerList); it.current(); ++it)
+ {
+ if (it.current()->id() == id)
+ {
+ return it.current();
+ }
+ }
+ return 0;
+}
+
+// it is necessary that addPlayer and systemAddPlayer are called in the same
+// order. Ie if addPlayer(foo) followed by addPlayer(bar) is called, you must
+// not call systemAddPlayer(bar) followed by systemAddPlayer(foo), as the
+// mAddPlayerList would get confused. Should be no problem as long as comServer
+// and the clients are working correctly.
+// BUT: if addPlayer(foo) does not arrive by any reason while addPlayer(bar)
+// does, we would be in trouble...
+void KGame::addPlayer(KPlayer* newplayer)
+{
+ kdDebug(11001) << k_funcinfo << ": " << "; maxPlayers=" << maxPlayers() << " playerCount=" << playerCount() << endl;
+ if (!newplayer)
+ {
+ kdFatal(11001) << "trying to add NULL player in KGame::addPlayer()" << endl;
+ return ;
+ }
+
+ if (maxPlayers() >= 0 && (int)playerCount() >= maxPlayers())
+ {
+ kdWarning(11001) << "cannot add more than " << maxPlayers() << " players - deleting..." << endl;
+ delete newplayer;
+ return;
+ }
+
+ if (newplayer->id() == 0)
+ {
+ d->mUniquePlayerNumber++;
+ newplayer->setId(KGameMessage::createPlayerId(d->mUniquePlayerNumber, gameId()));
+ kdDebug(11001) << k_funcinfo << "NEW!!! player " << newplayer << " now has id " << newplayer->id() << endl;
+ }
+ else
+ {
+ // this could happen in games which use their own ID management by certain
+ // reasons. that is NOT recommended
+ kdDebug(11001) << k_funcinfo << "player " << newplayer << " already has an id: " << newplayer->id() << endl;
+ }
+
+ QByteArray buffer;
+ QDataStream stream(buffer,IO_WriteOnly);
+ // We distinguis here what policy we have
+ if (policy()==PolicyLocal || policy()==PolicyDirty)
+ {
+ systemAddPlayer(newplayer);
+ }
+ if (policy()==PolicyClean || policy()==PolicyDirty)
+ {
+ savePlayer(stream,newplayer);
+ // Store the player for delayed clean adding
+ if (policy()==PolicyClean)
+ {
+ d->mAddPlayerList.enqueue(newplayer);
+ }
+ sendSystemMessage(stream,(int)KGameMessage::IdAddPlayer, 0);
+ }
+}
+
+void KGame::systemAddPlayer(KPlayer* newplayer)
+{
+ if (!newplayer)
+ {
+ kdFatal(11001) << "trying to add NULL player in KGame::systemAddPlayer()" << endl;
+ return ;
+ }
+ if (newplayer->id() == 0)
+ {
+ kdWarning(11001) << k_funcinfo << "player " << newplayer << " has no ID" << endl;
+ }
+
+ if (findPlayer(newplayer->id()))
+ {
+ kdError(11001) << "ERROR: Double adding player !!!!! NOT GOOD !!!!!! " << newplayer->id() << "...I delete it again" << endl;
+ delete newplayer;
+ }
+ else
+ {
+ kdDebug(11001) << "Trying to add player " << newplayer <<" maxPlayers="<<maxPlayers()<<" playerCount="<<playerCount() << endl;
+ // Add the player to the game
+ d->mPlayerList.append(newplayer);
+ newplayer->setGame(this);
+ kdDebug(11001) << "Player: isVirtual=" << newplayer->isVirtual() << endl;
+ kdDebug(11001) << " id=" << newplayer->id() << " #Players="
+ << d->mPlayerList.count() << " added " << newplayer
+ << " (virtual=" << newplayer->isVirtual() << ")" << endl;
+ emit signalPlayerJoinedGame(newplayer);
+ }
+}
+
+// Called by the KPlayer destructor
+void KGame::playerDeleted(KPlayer *player)
+{
+ kdDebug(11001) << k_funcinfo << ": id (" << player->id() << ") to be removed " << player << endl;
+
+ if (policy()==PolicyLocal || policy()==PolicyDirty)
+ {
+ systemRemovePlayer(player,false);
+ }
+ if (policy()==PolicyClean || policy()==PolicyDirty)
+ {
+ if (!player->isVirtual())
+ {
+ kdDebug(11001) << k_funcinfo << ": sending IdRemovePlayer "<<player->id() << endl;
+ sendSystemMessage(player->id(), KGameMessage::IdRemovePlayer, 0);
+ }
+ }
+}
+
+bool KGame::removePlayer(KPlayer * player, Q_UINT32 receiver)
+{//transmit to all clients, or to receiver only
+ if (!player)
+ {
+ kdFatal(11001) << "trying to remove NULL player in KGame::removePlayer()" << endl;
+ return false;
+ }
+ kdDebug(11001) << k_funcinfo << ": id (" << player->id() << ") to be removed " << player << endl;
+
+ if (policy()==PolicyLocal || policy()==PolicyDirty)
+ {
+ systemRemovePlayer(player,true);
+ }
+ if (policy()==PolicyClean || policy()==PolicyDirty)
+ {
+ kdDebug(11001) << k_funcinfo << ": sending IdRemovePlayer "<<player->id() << endl;
+ sendSystemMessage(player->id(),KGameMessage::IdRemovePlayer, receiver);
+ }
+ return true;
+ // we will receive the message in networkTransmission()
+}
+
+void KGame::systemRemovePlayer(KPlayer* player,bool deleteit)
+{
+ kdDebug(11001) << k_funcinfo << endl;
+ if (!player)
+ {
+ kdWarning(11001) << "cannot remove NULL player" << endl;
+ return;
+ }
+ if (!systemRemove(player,deleteit))
+ {
+ kdWarning(11001) << "player " << player << "(" << player->id() << ") Could not be found!" << endl;
+ }
+
+ if (gameStatus()==(int)Run && playerCount()<minPlayers())
+ {
+ kdWarning(11001) << k_funcinfo ": not enough players, PAUSING game\n" << endl;
+ setGameStatus(Pause);
+ }
+}
+
+bool KGame::systemRemove(KPlayer* p,bool deleteit)
+{
+ if (!p)
+ {
+ kdWarning(11001) << "cannot remove NULL player" << endl;
+ return false;
+ }
+ bool result;
+ kdDebug(11001) << k_funcinfo << ": Player (" << p->id() << ") to be removed " << p << endl;
+
+ if (d->mPlayerList.count() == 0)
+ {
+ result = false;
+ }
+ else
+ {
+ result = d->mPlayerList.remove(p);
+ }
+
+ emit signalPlayerLeftGame(p);
+
+ p->setGame(0);
+ if (deleteit)
+ {
+ delete p;
+ }
+
+ return result;
+}
+
+bool KGame::inactivatePlayer(KPlayer* player)
+{
+ if (!player)
+ {
+ return false;
+ }
+ kdDebug(11001) << "Inactivate player " << player->id() << endl;
+
+ if (policy()==PolicyLocal || policy()==PolicyDirty)
+ {
+ systemInactivatePlayer(player);
+ }
+ if (policy()==PolicyClean || policy()==PolicyDirty)
+ {
+ sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer);
+ }
+
+ return true;
+}
+
+bool KGame::systemInactivatePlayer(KPlayer* player)
+{
+ if (!player || !player->isActive())
+ {
+ return false;
+ }
+ kdDebug(11001) << " Inactivate player " << player->id() << endl;
+
+ int pid=player->id();
+ // Virtual players cannot be deactivated. They will be removed
+ if (player->isVirtual())
+ {
+ systemRemovePlayer(player,true);
+ }
+ else
+ {
+ d->mPlayerList.remove(player);
+ d->mInactivePlayerList.prepend(player);
+ player->setActive(false);
+ }
+ emit signalPlayerLeftGame(player);
+ if (isAdmin())
+ {
+ d->mInactiveIdList.prepend(pid);
+ }
+ return true;
+}
+
+bool KGame::activatePlayer(KPlayer * player)
+{
+ if (!player)
+ {
+ return false;
+ }
+ kdDebug(11001) << k_funcinfo << ": activate " << player->id() << endl;
+ if (policy()==PolicyLocal || policy()==PolicyDirty)
+ {
+ systemActivatePlayer(player);
+ }
+ if (policy()==PolicyClean || policy()==PolicyDirty)
+ {
+ sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer);
+ }
+ return true;
+}
+
+bool KGame::systemActivatePlayer(KPlayer* player)
+{
+ if (!player || player->isActive())
+ {
+ return false;
+ }
+ kdDebug(11001) << k_funcinfo << ": activate " << player->id() << endl;
+
+ d->mInactivePlayerList.remove(player);
+ player->setActive(true);
+ addPlayer(player);
+ if (isAdmin())
+ {
+ d->mInactiveIdList.remove(player->id());
+ }
+ return true;
+}
+
+// -------------------- Properties ---------------------------
+
+void KGame::setMaxPlayers(uint maxnumber)
+{ if (isAdmin()) { d->mMaxPlayer.changeValue(maxnumber); } }
+
+void KGame::setMinPlayers(uint minnumber)
+{ if (isAdmin()) { d->mMinPlayer.changeValue(minnumber); } }
+
+uint KGame::minPlayers() const
+{ return d->mMinPlayer.value(); }
+
+int KGame::maxPlayers() const
+{ return d->mMaxPlayer.value(); }
+
+uint KGame::playerCount() const
+{ return d->mPlayerList.count(); }
+
+int KGame::gameStatus() const
+{ return d->mGameStatus.value(); }
+
+bool KGame::isRunning() const
+{ return d->mGameStatus.value() == Run; }
+
+KGamePropertyHandler* KGame::dataHandler() const
+{ return d->mProperties; }
+
+
+KGame::KGamePlayerList* KGame::inactivePlayerList()
+{ return &d->mInactivePlayerList; }
+
+const KGame::KGamePlayerList* KGame::inactivePlayerList() const
+{ return &d->mInactivePlayerList; }
+
+KGame::KGamePlayerList* KGame::playerList()
+{ return &d->mPlayerList; }
+
+const KGame::KGamePlayerList* KGame::playerList() const
+{ return &d->mPlayerList; }
+
+KRandomSequence* KGame::random() const
+{ return d->mRandom; }
+
+
+bool KGame::sendPlayerInput(QDataStream &msg, KPlayer *player, Q_UINT32 sender)
+{
+ if (!player)
+ {
+ kdError(11001) << k_funcinfo << ": NULL player" << endl;
+ return false;
+ }
+ if (!isRunning())
+ {
+ kdError(11001) << k_funcinfo << ": game not running" << endl;
+ return false;
+ }
+
+ kdDebug(11001) << k_funcinfo << ": transmitting playerInput over network" << endl;
+ sendSystemMessage(msg, (int)KGameMessage::IdPlayerInput, player->id(), sender);
+ return true;
+}
+
+bool KGame::systemPlayerInput(QDataStream &msg, KPlayer *player, Q_UINT32 sender)
+{
+ if (!player)
+ {
+ kdError(11001) << k_funcinfo << ": NULL player" << endl;
+ return false;
+ }
+ if (!isRunning())
+ {
+ kdError(11001) << k_funcinfo << ": game not running" << endl;
+ return false;
+ }
+ kdDebug(11001) << "KGame: Got playerInput from messageServer... sender: " << sender << endl;
+ if (playerInput(msg,player))
+ {
+ playerInputFinished(player);
+ }
+ else
+ {
+ kdDebug(11001) << k_funcinfo<<": switching off player input"<<endl;
+ // TODO: (MH 03-2003): We need an return option from playerInput so that
+ // the player's is not automatically disabled here
+ if (!player->asyncInput())
+ {
+ player->setTurn(false); // in turn based games we have to switch off input now
+ }
+ }
+ return true;
+}
+
+
+KPlayer * KGame::playerInputFinished(KPlayer *player)
+{
+ kdDebug(11001) << k_funcinfo<<"player input finished for "<<player->id()<<endl;
+ // Check for game over and if not allow the next player to move
+ int gameOver = 0;
+ if (gameSequence())
+ {
+ gameSequence()->setCurrentPlayer(player);
+ }
+ // do not call gameSequence()->checkGameOver() to keep backward compatibility!
+ gameOver = checkGameOver(player);
+ if (gameOver!=0)
+ {
+ if (player)
+ {
+ player->setTurn(false);
+ }
+ setGameStatus(End);
+ emit signalGameOver(gameOver,player,this);
+ }
+ else if (!player->asyncInput())
+ {
+ player->setTurn(false); // in turn based games we have to switch off input now
+ if (gameSequence())
+ {
+ QTimer::singleShot(0,this,SLOT(prepareNext()));
+ }
+ }
+ return player;
+}
+
+// Per default we do not do anything
+int KGame::checkGameOver(KPlayer *player)
+{
+ if (gameSequence())
+ {
+ return gameSequence()->checkGameOver(player);
+ }
+ return 0;
+}
+
+void KGame::setGameSequence(KGameSequence* sequence)
+{
+ delete d->mGameSequence;
+ d->mGameSequence = sequence;
+ if (d->mGameSequence)
+ {
+ d->mGameSequence->setGame(this);
+ }
+}
+
+KGameSequence* KGame::gameSequence() const
+{
+ return d->mGameSequence;
+}
+
+void KGame::prepareNext()
+{
+ if (gameSequence())
+ {
+ // we don't call gameSequence->nextPlayer() to keep old code working
+ nextPlayer(gameSequence()->currentPlayer());
+ }
+}
+
+KPlayer *KGame::nextPlayer(KPlayer *last,bool exclusive)
+{
+ if (gameSequence())
+ {
+ return gameSequence()->nextPlayer(last, exclusive);
+ }
+ return 0;
+}
+
+void KGame::setGameStatus(int status)
+{
+ kdDebug(11001) << k_funcinfo << ": GAMESTATUS CHANGED to" << status << endl;
+ if (status==(int)Run && playerCount()<minPlayers())
+ {
+ kdDebug(11001) << k_funcinfo << ": not enough players, pausing game\n" << endl;
+ status=Pause;
+ }
+ d->mGameStatus = status;
+}
+
+void KGame::networkTransmission(QDataStream &stream, int msgid, Q_UINT32 receiver, Q_UINT32 sender, Q_UINT32 /*clientID*/)
+{//clientID is unused
+ // message targets a playerobject. If we find it we forward the message to the
+ // player. Otherwise we proceed here and hope the best that the user processes
+ // the message
+
+// kdDebug(11001) << k_funcinfo << ": we="<<(int)gameId()<<" id="<<msgid<<" recv=" << receiver << " sender=" << sender << endl;
+
+
+ // *first* notice the game that something has changed - so no return prevents
+ // this
+ emit signalMessageUpdate(msgid, receiver, sender);
+ if (KGameMessage::isPlayer(receiver))
+ {
+ //kdDebug(11001) << "message id " << msgid << " seems to be for a player ("<<active=p->isActive()<<" recv="<< receiver << endl;
+ KPlayer *p=findPlayer(receiver);
+ if (p && p->isActive())
+ {
+ p->networkTransmission(stream,msgid,sender);
+ return;
+ }
+ if (p)
+ {
+ kdDebug(11001) << "player is here but not active" << endl;
+ }
+ else
+ {
+ kdDebug(11001) << "no player found" << endl;
+ }
+ }
+ // If it is not for a player it is meant for us!!!! Otherwise the
+ // gamenetwork would not have passed the message to us!
+
+ // GameProperties processed
+ if (d->mProperties->processMessage(stream, msgid, sender == gameId()))
+ {
+// kdDebug(11001 ) << "KGame: message taken by property - returning" << endl;
+ return ;
+ }
+
+ switch(msgid)
+ {
+ case KGameMessage::IdSetupGame: // Client: First step in setup game
+ {
+ Q_INT16 v;
+ Q_INT32 c;
+ stream >> v >> c;
+ kdDebug(11001) << " ===================> (Client) " << k_funcinfo << ": Got IdSetupGame ================== " << endl;
+ kdDebug(11001) << "our game id is " << gameId() << " Lib version=" << v << " App Cookie=" << c << endl;
+ // Verify identity of the network partners
+ if (c!=cookie())
+ {
+ kdError(11001) << "IdGameSetup: Negotiate Game: cookie mismatch I'am="<<cookie()<<" master="<<c<<endl;
+ sendError(KGameError::Cookie, KGameError::errCookie(cookie(), c));
+ disconnect(); // disconnect from master
+ }
+ else if (v!=KGameMessage::version())
+ {
+ sendError(KGameError::Version, KGameError::errVersion(v));
+ disconnect(); // disconnect from master
+ }
+ else
+ {
+ setupGame(sender);
+ }
+ kdDebug(11001) << "========== (Client) Setup game done\n";
+ }
+ break;
+ case KGameMessage::IdSetupGameContinue: // Master: second step in game setup
+ {
+ kdDebug(11001) << "=====>(Master) " << k_funcinfo << " - IdSetupGameContinue" << endl;
+ setupGameContinue(stream, sender);
+ }
+ break;
+ case KGameMessage::IdActivatePlayer: // Activate Player
+ {
+ int id;
+ stream >> id;
+ kdDebug(11001) << "Got IdActivatePlayer id=" << id << endl;
+ if (sender!=gameId() || policy()!=PolicyDirty)
+ {
+ systemActivatePlayer(findPlayer(id));
+ }
+ }
+ break;
+ case KGameMessage::IdInactivatePlayer: // Inactivate Player
+ {
+ int id;
+ stream >> id;
+ kdDebug(11001) << "Got IdInactivatePlayer id=" << id << endl;
+ if (sender!=gameId() || policy()!=PolicyDirty)
+ {
+ systemInactivatePlayer(findPlayer(id));
+ }
+ }
+ break;
+ case KGameMessage::IdAddPlayer:
+ {
+ kdDebug(11001) << k_funcinfo << ": Got IdAddPlayer" << endl;
+ if (sender!=gameId() || policy()!=PolicyDirty)
+ {
+ KPlayer *newplayer=0;
+ // We sent the message so the player is already available
+ if (sender==gameId())
+ {
+ kdDebug(11001) << "dequeue previously added player" << endl;
+ newplayer = d->mAddPlayerList.dequeue();
+ }
+ else
+ {
+ newplayer=loadPlayer(stream,true);
+ }
+ systemAddPlayer(newplayer);// the final, local, adding
+ //systemAddPlayer(stream);
+ }
+ }
+ break;
+ case KGameMessage::IdRemovePlayer: // Client should delete player id
+ {
+ int id;
+ stream >> id;
+ kdDebug(11001) << k_funcinfo << ": Got IdRemovePlayer " << id << endl;
+ KPlayer *p=findPlayer(id);
+ if (p)
+ {
+ // Otherwise the player is already removed
+ if (sender!=gameId() || policy()!=PolicyDirty)
+ {
+ systemRemovePlayer(p,true);
+ }
+ }
+ else
+ {
+ kdWarning(11001) << k_funcinfo << "Cannot find player " << id << endl;
+ }
+ }
+ break;
+ case KGameMessage::IdGameLoad:
+ {
+ kdDebug(11001) << "====> (Client) " << k_funcinfo << ": Got IdGameLoad" << endl;
+ loadgame(stream,true,false);
+ }
+ break;
+ case KGameMessage::IdGameSetupDone:
+ {
+ int cid;
+ stream >> cid;
+ kdDebug(11001) << "====> (CLIENT) " << k_funcinfo << ": Got IdGameSetupDone for client "
+ << cid << " we are =" << gameId() << endl;
+ sendSystemMessage(gameId(), KGameMessage::IdGameConnected, 0);
+ }
+ break;
+ case KGameMessage::IdGameConnected:
+ {
+ int cid;
+ stream >> cid;
+ kdDebug(11001) << "====> (ALL) " << k_funcinfo << ": Got IdGameConnected for client "<< cid << " we are =" << gameId() << endl;
+ emit signalClientJoinedGame(cid,this);
+ }
+ break;
+
+ case KGameMessage::IdSyncRandom: // Master forces a new random seed on us
+ {
+ int newseed;
+ stream >> newseed;
+ kdDebug(11001) << "CLIENT: setting random seed to " << newseed << endl;
+ d->mRandom->setSeed(newseed);
+ }
+ break;
+ case KGameMessage::IdDisconnect:
+ {
+ // if we disconnect we *always* start a local game.
+ // this could lead into problems if we just change the message server
+ if (sender != gameId())
+ {
+ kdDebug(11001) << "client " << sender << " leaves game" << endl;
+ return;
+ }
+ kdDebug(11001) << "leaving the game" << endl;
+ // start a new local game
+ // no other client is by default connected to this so this call should be
+ // enough
+ setMaster();
+ }
+ break;
+ default:
+ {
+ if (msgid < KGameMessage::IdUser)
+ {
+ kdError(11001) << "incorrect message id " << msgid << " - emit anyway"
+ << endl;
+ }
+ kdDebug(11001) << k_funcinfo << ": User data msgid " << msgid << endl;
+ emit signalNetworkData(msgid - KGameMessage::IdUser,((QBuffer*)stream.device())->readAll(),receiver,sender);
+ }
+ break;
+ }
+
+}
+
+// called by the IdSetupGameContinue Message - MASTER SIDE
+// Here the master needs to decide which players can take part at the game
+// and which will be deactivated
+void KGame::setupGameContinue(QDataStream& stream, Q_UINT32 sender)
+{
+ KPlayer *player;
+ Q_INT32 cnt;
+ int i;
+ stream >> cnt;
+
+ QValueList<int> inactivateIds;
+
+ KGamePlayerList newPlayerList;
+ newPlayerList.setAutoDelete(true);
+ for (i=0;i<cnt;i++)
+ {
+ player=loadPlayer(stream,true);
+ kdDebug(11001) << " Master got player " << player->id() <<" rawgame=" << KGameMessage::rawGameId(player->id()) << " from sender " << sender << endl;
+ if (KGameMessage::rawGameId(player->id()) != sender)
+ {
+ kdError(11001) << "Client tries to add player with wrong game id - cheat possible" << endl;
+ }
+ else
+ {
+ newPlayerList.append(player);
+ kdDebug(11001) << " newplayerlist appended " << player->id() << endl;
+ }
+ }
+
+ newPlayersJoin(playerList(),&newPlayerList,inactivateIds);
+
+
+ kdDebug(11001) << " Master calculates how many players to activate client has cnt=" << cnt << endl;
+ kdDebug(11001) << " The game has " << playerCount() << " active players" << endl;
+ kdDebug(11001) << " The user deactivated "<< inactivateIds.count() << " player already " << endl;
+ kdDebug(11001) << " MaxPlayers for this game is " << maxPlayers() << endl;
+
+ // Do we have too many players? (After the programmer disabled some?)
+ // MH: We cannot use have player here as it CHANGES in the loop
+ // int havePlayers = cnt+playerCount()-inactivateIds.count();
+ kdDebug(11001) << " havePlayers " << cnt+playerCount()-inactivateIds.count() << endl;
+ while (maxPlayers() > 0 && maxPlayers() < (int)(cnt+playerCount() - inactivateIds.count()))
+ {
+ kdDebug(11001) << " Still to deacticvate "
+ << (int)(cnt+playerCount()-inactivateIds.count())-(int)maxPlayers()
+ << endl;
+ KPlayer *currentPlayer=0;
+ int currentPriority=0x7fff; // MAX_UINT (16bit?) to get the maximum of the list
+ // find lowest network priority which is not yet in the newPlayerList
+ // do this for the new players
+ for ( player=newPlayerList.first(); player != 0; player=newPlayerList.next() )
+ {
+ // Already in the list
+ if (inactivateIds.find(player->id())!=inactivateIds.end())
+ {
+ continue;
+ }
+ if (player->networkPriority()<currentPriority)
+ {
+ currentPriority=player->networkPriority();
+ currentPlayer=player;
+ }
+ }
+
+ // find lowest network priority which is not yet in the newPlayerList
+ // Do this for the network players
+ for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() )
+ {
+ // Already in the list
+ if (inactivateIds.find(player->id())!=inactivateIds.end())
+ {
+ continue;
+ }
+ if (player->networkPriority()<currentPriority)
+ {
+ currentPriority=player->networkPriority();
+ currentPlayer=player;
+ }
+ }
+
+ // add it to inactivateIds
+ if (currentPlayer)
+ {
+ kdDebug(11001) << "Marking player " << currentPlayer->id() << " for inactivation" << endl;
+ inactivateIds.append(currentPlayer->id());
+ }
+ else
+ {
+ kdError(11001) << "Couldn't find a player to dectivate..That is not so good..." << endl;
+ break;
+ }
+ }
+
+ kdDebug(11001) << "Alltogether deactivated " << inactivateIds.count() << " players" << endl;
+
+ QValueList<int>::Iterator it;
+ for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it )
+ {
+ int pid=*it;
+ kdDebug(11001) << " pid=" << pid << endl;
+ }
+
+ // Now deactivate the network players from the inactivateId list
+ //QValueList<int>::Iterator it;
+ for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it )
+ {
+ int pid=*it;
+ if (KGameMessage::rawGameId(pid) == sender)
+ {
+ continue; // client's player
+ }
+ kdDebug(11001) << " -> the network needs to deactivate " << pid <<endl;
+ player=findPlayer(pid);
+ if (player)
+ {
+ // We have to make REALLY sure that the player is gone. With any policy
+ systemInactivatePlayer(player);
+ if (policy()!=PolicyLocal)
+ {
+ sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer);
+ }
+ }
+ else
+ {
+ kdError(11001) << " We should deactivate a player, but cannot find it...not good." << endl;
+ }
+ }
+
+ // Now send out the player list which the client can activate
+ for ( player=newPlayerList.first(); player != 0; player=newPlayerList.next() )
+ {
+ kdDebug(11001) << " newplayerlist contains " << player->id() << endl;
+ // Only activate what is not in the list
+ if (inactivateIds.find(player->id())!=inactivateIds.end())
+ {
+ continue;
+ }
+ kdDebug(11001) << " -> the client can ******** reactivate ******** " << player->id() << endl;
+ sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer, sender);
+ }
+
+ // Save the game over the network
+ QByteArray bufferS;
+ QDataStream streamS(bufferS,IO_WriteOnly);
+ // Save game over netowrk and save players
+ savegame(streamS,true,true);
+ sendSystemMessage(streamS,KGameMessage::IdGameLoad,sender);
+
+
+ // Only to the client first , as the client will add players
+ sendSystemMessage(sender, KGameMessage::IdGameSetupDone, sender);
+}
+
+// called by the IdSetupGame Message - CLIENT SIDE
+// Client needs to prepare for network transfer
+void KGame::setupGame(Q_UINT32 sender)
+{
+ QByteArray bufferS;
+ QDataStream streamS(bufferS,IO_WriteOnly);
+
+ // Deactivate all players
+ KGamePlayerList mTmpList(d->mPlayerList); // we need copy otherwise the removal crashes
+ Q_INT32 cnt=mTmpList.count();
+ kdDebug(11001) << "Client: playerlistcount=" << d->mPlayerList.count() << " tmplistcout=" << cnt << endl;
+
+ streamS << cnt;
+
+ QPtrListIterator<KPlayer> it(mTmpList);
+ KPlayer *player;
+ while (it.current())
+ {
+ player=it.current();
+ systemInactivatePlayer(player);
+ // Give the new game id to all players (which are inactivated now)
+ player->setId(KGameMessage::createPlayerId(player->id(),gameId()));
+
+ // Save it for the master to decide what to do
+ savePlayer(streamS,player);
+
+ ++it;
+ --cnt;
+ }
+ if (d->mPlayerList.count() > 0 || cnt!=0)
+ {
+ kdFatal(11001) << "KGame::setupGame(): Player list is not empty! or cnt!=0=" <<cnt << endl;
+ }
+
+ sendSystemMessage(streamS,KGameMessage::IdSetupGameContinue,sender);
+}
+
+// unused by KGame
+void KGame::syncRandom()
+{
+ int newseed=(int)d->mRandom->getLong(65535);
+ sendSystemMessage(newseed,KGameMessage::IdSyncRandom); // Broadcast
+ d->mRandom->setSeed(newseed);
+}
+
+void KGame::Debug()
+{
+ KGameNetwork::Debug();
+ kdDebug(11001) << "------------------- KGAME -------------------------" << endl;
+ kdDebug(11001) << "this: " << this << endl;
+ kdDebug(11001) << "uniquePlayer " << d->mUniquePlayerNumber << endl;
+ kdDebug(11001) << "gameStatus " << gameStatus() << endl;
+ kdDebug(11001) << "MaxPlayers : " << maxPlayers() << endl;
+ kdDebug(11001) << "NoOfPlayers : " << playerCount() << endl;
+ kdDebug(11001) << "NoOfInactive: " << d->mInactivePlayerList.count() << endl;
+ kdDebug(11001) << "---------------------------------------------------" << endl;
+}
+
+void KGame::slotClientConnected(Q_UINT32 clientID)
+{
+ if (isAdmin())
+ {
+ negotiateNetworkGame(clientID);
+ }
+}
+
+void KGame::slotServerDisconnected() // Client side
+{
+ kdDebug(11001) << "======= SERVER DISCONNECT ======="<<endl;
+ kdDebug(11001) << "+++ (CLIENT)++++++++" << k_funcinfo << ": our GameID="<<gameId() << endl;
+
+ int oldgamestatus=gameStatus();
+
+ KPlayer *player;
+ KGamePlayerList removeList;
+ kdDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << " count" << endl;
+ kdDebug(11001) << "Inactive Playerlist of client=" << d->mInactivePlayerList.count() << " count" << endl;
+ for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() )
+ {
+ // TODO: CHECK: id=0, could not connect to server in the first place??
+ if (KGameMessage::rawGameId(player->id()) != gameId() && gameId()!=0)
+ {
+ kdDebug(11001) << "Player " << player->id() << " belongs to a removed game" << endl;
+ removeList.append(player);
+ }
+ }
+
+ for ( player=removeList.first(); player != 0; player=removeList.next() )
+ {
+ bool remove = true;
+ emit signalReplacePlayerIO(player, &remove);
+ if (remove)
+ {
+ kdDebug(11001) << " ---> Removing player " << player->id() << endl;
+ systemRemovePlayer(player,true); // no network necessary
+ }
+ }
+
+ setMaster();
+ kdDebug(11001) << " our game id is after setMaster " << gameId() << endl;
+
+ KGamePlayerList mReList(d->mInactivePlayerList);
+ for ( player=mReList.first(); player != 0; player=mReList.next() )
+ {
+ // TODO ?check for priority? Sequence should be ok
+ if ((int)playerCount()<maxPlayers() || maxPlayers()<0)
+ {
+ systemActivatePlayer(player);
+ }
+ }
+ kdDebug(11001) << " Players activated player-cnt=" << playerCount() << endl;
+
+ for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() )
+ {
+ int oldid=player->id();
+ d->mUniquePlayerNumber++;
+ player->setId(KGameMessage::createPlayerId(d->mUniquePlayerNumber,gameId()));
+ kdDebug(11001) << "Player id " << oldid <<" changed to " << player->id() << " as we are now local" << endl;
+ }
+ // TODO clear inactive lists ?
+ Debug();
+ for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() )
+ {
+ player->Debug();
+ }
+ kdDebug(11001) << "+++++++++++" << k_funcinfo << " DONE=" << endl;
+ emit signalClientLeftGame(0,oldgamestatus,this);
+}
+
+void KGame::slotClientDisconnected(Q_UINT32 clientID,bool /*broken*/) // server side
+{
+ kdDebug(11001) << "++++(SERVER)+++++++" << k_funcinfo << " clientId=" << clientID << endl;
+
+ int oldgamestatus=gameStatus();
+
+ KPlayer *player;
+ KGamePlayerList removeList;
+ kdDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << " count" << endl;
+ for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() )
+ {
+ if (KGameMessage::rawGameId(player->id())==clientID)
+ {
+ kdDebug(11001) << "Player " << player->id() << " belongs to the removed game" << endl;
+ removeList.append(player);
+ }
+ }
+
+ for ( player=removeList.first(); player != 0; player=removeList.next() )
+ {
+ // try to replace the KGameIO first
+ bool remove = true;
+ emit signalReplacePlayerIO(player, &remove);
+ if (remove) {
+ // otherwise (no new KGameIO) remove the player
+ kdDebug(11001) << " ---> Removing player " << player->id() << endl;
+ removePlayer(player,0);
+ }
+ }
+
+ // Now add inactive players - sequence should be ok
+ // TODO remove players from removed game
+ for (unsigned int idx=0;idx<d->mInactiveIdList.count();idx++)
+ {
+ QValueList<int>::Iterator it1 = d->mInactiveIdList.at(idx);
+ player = findPlayer(*it1);
+ if (((int)playerCount() < maxPlayers() || maxPlayers() < 0) && player && KGameMessage::rawGameId(*it1) != clientID)
+ {
+ activatePlayer(player);
+ }
+ }
+ emit signalClientLeftGame(clientID,oldgamestatus,this);
+}
+
+
+// -------------------- Synchronisation -----------------------
+
+// this initializes a newly connected client.
+// we send the number of players (including type) as well as game status and
+// properties to the client. After the initialization has been completed both
+// clients should have the same status (ie players, properties, etc)
+void KGame::negotiateNetworkGame(Q_UINT32 clientID)
+{
+ kdDebug(11001) << "===========================" << k_funcinfo << ": clientID=" << clientID << " =========================== "<< endl;
+ if (!isAdmin())
+ {
+ kdError(11001) << k_funcinfo << ": Serious WARNING..only gameAdmin should call this" << endl;
+ return ;
+ }
+
+ QByteArray buffer;
+ QDataStream streamGS(buffer,IO_WriteOnly);
+
+ // write Game setup specific data
+ //streamGS << (Q_INT32)maxPlayers();
+ //streamGS << (Q_INT32)minPlayers();
+
+ // send to the newly connected client *only*
+ Q_INT16 v=KGameMessage::version();
+ Q_INT32 c=cookie();
+ streamGS << v << c;
+ sendSystemMessage(streamGS, KGameMessage::IdSetupGame, clientID);
+}
+
+bool KGame::sendGroupMessage(const QByteArray &msg, int msgid, Q_UINT32 sender, const QString& group)
+{
+// AB: group must not be i18n'ed!! we should better use an id for group and use
+// a groupName() for the name // FIXME
+ KPlayer *player;
+ for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() )
+ {
+ if (player && player->group()==group)
+ {
+ sendMessage(msg,msgid,player->id(), sender);
+ }
+ }
+ return true;
+}
+
+bool KGame::sendGroupMessage(const QDataStream &msg, int msgid, Q_UINT32 sender, const QString& group)
+{ return sendGroupMessage(((QBuffer*)msg.device())->buffer(), msgid, sender, group); }
+
+bool KGame::sendGroupMessage(const QString& msg, int msgid, Q_UINT32 sender, const QString& group)
+{
+ QByteArray buffer;
+ QDataStream stream(buffer, IO_WriteOnly);
+ stream << msg;
+ return sendGroupMessage(stream, msgid, sender, group);
+}
+
+bool KGame::addProperty(KGamePropertyBase* data)
+{ return dataHandler()->addProperty(data); }
+
+bool KGame::sendPlayerProperty(int msgid, QDataStream& s, Q_UINT32 playerId)
+{ return sendSystemMessage(s, msgid, playerId); }
+
+void KGame::sendProperty(int msgid, QDataStream& stream, bool* sent)
+{
+ bool s = sendSystemMessage(stream, msgid);
+ if (s)
+ {
+ *sent = true;
+ }
+}
+
+void KGame::emitSignal(KGamePropertyBase *me)
+{
+ emit signalPropertyChanged(me,this);
+}
+
+KGamePropertyBase* KGame::findProperty(int id) const
+{ return d->mProperties->find(id); }
+
+KGame::GamePolicy KGame::policy() const
+{
+ return d->mPolicy;
+}
+void KGame::setPolicy(GamePolicy p,bool recursive)
+{
+ // Set KGame policy
+ d->mPolicy=p;
+ if (recursive)
+ {
+ // Set all KGame property policy
+ dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false);
+
+ // Set all KPLayer (active or inactive) property policy
+ for (QPtrListIterator<KPlayer> it(d->mPlayerList); it.current(); ++it)
+ {
+ it.current()->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false);
+ }
+ for (QPtrListIterator<KPlayer> it(d->mInactivePlayerList); it.current(); ++it)
+ {
+ it.current()->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false);
+ }
+ }
+}
+
+/*
+ * vim: et sw=2
+ */