kgame.cpp

00001 /*
00002     This file is part of the KDE games library
00003     Copyright (C) 2001 Martin Heni (martin@heni-online.de)
00004     Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License version 2 as published by the Free Software Foundation.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 /*
00021     $Id: kgame.cpp 465369 2005-09-29 14:33:08Z mueller $
00022 */
00023 
00024 #include "kgame.h"
00025 #include "kgame.moc"
00026 #include "kgamepropertyhandler.h"
00027 #include "kgameproperty.h"
00028 #include "kplayer.h"
00029 #include "kgameio.h"
00030 #include "kgameerror.h"
00031 #include "kgamesequence.h"
00032 
00033 #include "kgamemessage.h"
00034 
00035 #include <unistd.h>
00036 #include <stdio.h>
00037 #include <assert.h>
00038 
00039 #include <qbuffer.h>
00040 #include <qtimer.h>
00041 #include <qptrqueue.h>
00042 #include <qfile.h>
00043 
00044 #include <klocale.h>
00045 #include <krandomsequence.h>
00046 #include <kdebug.h>
00047 
00048 #define KGAME_LOAD_COOKIE 4210
00049 
00050 // try to place as much as possible here
00051 // many things are *not* possible here as KGame has to use some inline function
00052 class KGamePrivate
00053 {
00054 public:
00055     KGamePrivate()
00056     {
00057         mUniquePlayerNumber = 0;
00058         mPolicy=KGame::PolicyLocal;
00059         mGameSequence = 0;
00060     }
00061 
00062     int mUniquePlayerNumber;
00063     QPtrQueue<KPlayer> mAddPlayerList;// this is a list of to-be-added players. See addPlayer() docu
00064     KRandomSequence* mRandom;
00065     KGame::GamePolicy mPolicy;
00066     KGameSequence* mGameSequence;
00067 
00068 
00069     KGamePropertyHandler* mProperties;
00070 
00071     // player lists
00072     KGame::KGamePlayerList mPlayerList;
00073     KGame::KGamePlayerList mInactivePlayerList;
00074 
00075     //KGamePropertys
00076     KGamePropertyInt mMaxPlayer;
00077     KGamePropertyUInt mMinPlayer;
00078     KGamePropertyInt mGameStatus; // Game running?
00079     QValueList<int> mInactiveIdList;
00080 
00081 };
00082 
00083 // ------------------- GAME CLASS --------------------------
00084 KGame::KGame(int cookie,QObject* parent) : KGameNetwork(cookie,parent)
00085 {
00086  kdDebug(11001) << k_funcinfo << " - " << this << ", sizeof(KGame)=" << sizeof(KGame) << endl;
00087  d = new KGamePrivate;
00088 
00089  d->mProperties = new KGamePropertyHandler(this);
00090 
00091  d->mProperties->registerHandler(KGameMessage::IdGameProperty,
00092                                 this,SLOT(sendProperty(int, QDataStream&, bool* )),
00093                                      SLOT(emitSignal(KGamePropertyBase *)));
00094  d->mMaxPlayer.registerData(KGamePropertyBase::IdMaxPlayer, this, i18n("MaxPlayers"));
00095  d->mMaxPlayer.setLocal(-1);  // Infinite
00096  d->mMinPlayer.registerData(KGamePropertyBase::IdMinPlayer, this, i18n("MinPlayers"));
00097  d->mMinPlayer.setLocal(0);   // Always ok
00098  d->mGameStatus.registerData(KGamePropertyBase::IdGameStatus, this, i18n("GameStatus"));
00099  d->mGameStatus.setLocal(Init);
00100  // d->mUniquePlayerNumber = 0;
00101  d->mRandom = new KRandomSequence;
00102  d->mRandom->setSeed(0);
00103 
00104  connect(this, SIGNAL(signalClientConnected(Q_UINT32)),
00105                 this, SLOT(slotClientConnected(Q_UINT32)));
00106  connect(this, SIGNAL(signalClientDisconnected(Q_UINT32,bool)),
00107                 this, SLOT(slotClientDisconnected(Q_UINT32,bool)));
00108  connect(this, SIGNAL(signalConnectionBroken()),
00109                 this, SLOT(slotServerDisconnected()));
00110 
00111  setGameSequence(new KGameSequence());
00112 
00113  // BL: FIXME This signal does no longer exist. When we are merging
00114  // MH: super....and how do I find out about the lost conenction now?
00115  // KGame and KGameNetwork, this could be improved!
00116 //  connect(this,SIGNAL(signalConnectionLost(KGameClient *)),
00117 //          this,SLOT(slotConnectionLost(KGameClient *)));
00118 }
00119 
00120 KGame::~KGame()
00121 {
00122  kdDebug(11001) << k_funcinfo << endl;
00123 // Debug();
00124  reset();
00125  delete d->mGameSequence;
00126  delete d->mRandom;
00127  delete d;
00128  kdDebug(11001) << k_funcinfo << " done" << endl;
00129 }
00130 
00131 bool KGame::reset()
00132 {
00133  deletePlayers();
00134  deleteInactivePlayers();
00135  return true;
00136 }
00137 
00138 void KGame::deletePlayers()
00139 {
00140 // kdDebug(11001) << k_funcinfo << endl;
00141  KGamePlayerList tmp = d->mPlayerList; // in case of PolicyClean player=d->mPlayerList.first() is infinite
00142  KPlayer *player;
00143  while((player=tmp.first()))
00144  {
00145    delete player; // delete and removes the player
00146    tmp.removeFirst();
00147  }
00148 // kdDebug(11001) << k_funcinfo << " done" << endl;
00149 }
00150 
00151 void KGame::deleteInactivePlayers()
00152 {
00153  KPlayer *player;
00154  while((player=d->mInactivePlayerList.first()))
00155  {
00156    //player->setGame(0); // prevent call backs
00157    d->mInactivePlayerList.remove(player);
00158    delete player;
00159  }
00160 }
00161 
00162 bool KGame::load(QString filename,bool reset)
00163 {
00164   if (filename.isNull())
00165   {
00166     return false;
00167   }
00168   QFile f(filename);
00169   if (!f.open(IO_ReadOnly))
00170   {
00171     return false;
00172   }
00173   QDataStream s( &f );
00174   load(s,reset);
00175   f.close();
00176   return true;
00177 }
00178 
00179 bool KGame::load(QDataStream &stream,bool reset)
00180 { return loadgame(stream, false,reset); }
00181 
00182 bool KGame::loadgame(QDataStream &stream, bool network,bool resetgame)
00183 {
00184  // Load Game Data
00185 
00186  // internal data
00187  Q_INT32 c;
00188  stream >> c; // cookie
00189 
00190  if (c!=cookie())
00191  {
00192    kdWarning(11001) << "Trying to load different game version we="<<cookie() << " saved=" << c << endl;
00193    bool result=false;
00194    emit signalLoadError(stream,network,(int)c,result);
00195    return result;
00196  }
00197  if (resetgame) reset();
00198 
00199  uint i;
00200  stream >> i;
00201 // setPolicy((GamePolicy)i);
00202 
00203  stream >> d->mUniquePlayerNumber;
00204 
00205  if (gameSequence())
00206  {
00207    gameSequence()->setCurrentPlayer(0);  // TODO !!!
00208  }
00209  int newseed;
00210  stream >> newseed;
00211  d->mRandom->setSeed(newseed);
00212 
00213  // Switch off the direct emitting of signals while
00214  // loading properties. This can cause inconsistencies
00215  // otherwise if a property emits and this emit accesses
00216  // a property not yet loaded
00217  // Note we habe to have this external locking to prevent the games unlocking
00218  // to access the players
00219  dataHandler()->lockDirectEmit();
00220  KPlayer *player;
00221  for ( player=playerList()->first(); player != 0; player=playerList()->next() )
00222  {
00223    player->dataHandler()->lockDirectEmit();
00224    // kdDebug(11001) << "Player "<<player->id() << " to indirect emit" <<endl;
00225  }
00226 
00227  // Properties
00228  dataHandler()->load(stream);
00229 
00230  // If there is additional data to be loaded before players are loaded then do
00231  // this here.
00232  emit signalLoadPrePlayers(stream);
00233 
00234  // Load Playerobjects
00235  uint playercount;
00236  stream >> playercount;
00237  kdDebug(11001) << "Loading KGame " << playercount << " KPlayer objects " << endl;
00238  for (i=0;i<playercount;i++)
00239  {
00240    KPlayer *newplayer=loadPlayer(stream,network);
00241    systemAddPlayer(newplayer);
00242  }
00243 
00244  Q_INT16 cookie;
00245  stream >> cookie;
00246  if (cookie==KGAME_LOAD_COOKIE) {
00247    kdDebug(11001) << "   Game loaded propertly"<<endl;
00248  } else {
00249    kdError(11001) << "   Game loading error. probably format error"<<endl;
00250  }
00251 
00252  // Switch back on the direct emitting of signals and emit the
00253  // queued signals.
00254  // Note we habe to have this external locking to prevent the games unlocking
00255  // to access the players
00256  dataHandler()->unlockDirectEmit();
00257  for ( player=playerList()->first(); player != 0; player=playerList()->next() )
00258  {
00259    player->dataHandler()->unlockDirectEmit();
00260    // kdDebug(11001) << "Player "<<player->id() << " to direct emit" <<endl;
00261  }
00262 
00263  emit signalLoad(stream);
00264  return true;
00265 }
00266 
00267 bool KGame::save(QString filename,bool saveplayers)
00268 {
00269  if (filename.isNull())
00270  {
00271    return false;
00272  }
00273  QFile f(filename);
00274  if (!f.open(IO_WriteOnly))
00275  {
00276    return false;
00277  }
00278  QDataStream s( &f );
00279  save(s,saveplayers);
00280  f.close();
00281  return true;
00282 }
00283 
00284 bool KGame::save(QDataStream &stream,bool saveplayers)
00285 { return savegame(stream, false,saveplayers); }
00286 
00287 bool KGame::savegame(QDataStream &stream,bool /*network*/,bool saveplayers)
00288 {
00289   // Save Game Data
00290 
00291   // internal variables
00292   Q_INT32 c=cookie();
00293   stream << c;
00294 
00295   uint p=(uint)policy();
00296   stream << p;
00297   stream << d->mUniquePlayerNumber;
00298   int newseed=(int)d->mRandom->getLong(65535);
00299   stream << newseed;
00300   d->mRandom->setSeed(newseed);
00301 
00302  // Properties
00303  dataHandler()->save(stream);
00304 
00305  // Save all data that need to be saved *before* the players are saved
00306  emit signalSavePrePlayers(stream);
00307 
00308  if (saveplayers)
00309  {
00310    savePlayers(stream,playerList());
00311  }
00312  else
00313  {
00314    stream << (uint)0; // no players saved
00315  }
00316 
00317  stream << (Q_INT16)KGAME_LOAD_COOKIE;
00318 
00319  emit signalSave(stream);
00320  return true;
00321 }
00322 
00323 void KGame::savePlayer(QDataStream &stream,KPlayer* p)
00324 {
00325 // this could be in KGameMessage as well
00326  stream << (Q_INT32)p->rtti();
00327  stream << (Q_INT32)p->id();
00328  stream << (Q_INT32)p->calcIOValue();
00329  p->save(stream);
00330 }
00331 
00332 void KGame::savePlayers(QDataStream &stream, KGamePlayerList *list)
00333 {
00334  if (!list)
00335  {
00336    list=playerList();
00337  }
00338 
00339  Q_INT32 cnt=list->count();
00340  kdDebug(11001) << "Saving KGame " << cnt << " KPlayer objects " << endl;
00341  stream << cnt;
00342  KPlayer *player;
00343  for ( player=list->first(); player != 0; player=list->next() )
00344  {
00345    savePlayer(stream,player);
00346  }
00347 }
00348 
00349 KPlayer *KGame::createPlayer(int /*rtti*/,int /*io*/,bool /*isvirtual*/)
00350 {
00351   kdWarning(11001) << "   No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! " << endl;
00352   return new KPlayer;
00353 }
00354 KPlayer *KGame::loadPlayer(QDataStream& stream,bool isvirtual)
00355 {
00356   Q_INT32 rtti,id,iovalue;
00357   stream >> rtti >> id >> iovalue;
00358   KPlayer *newplayer=findPlayer(id);
00359   if (!newplayer)
00360   {
00361     kdDebug(11001) << k_funcinfo << "Player "<< id << " not found...asking user to create one " << endl;
00362     newplayer=createPlayer(rtti,iovalue,isvirtual);
00363     //emit signalCreatePlayer(newplayer,rtti,iovalue,isvirtual,this);
00364   }
00365   /*
00366   if (!newplayer)
00367   {
00368     kdWarning(11001) << "   No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! " << endl;
00369     newplayer=new KPlayer;
00370   }
00371   else
00372   {
00373     kdDebug(11001) << "   USER Player " << newplayer << " done player->rtti=" << newplayer->rtti() << " rtti=" << rtti << endl;
00374   }
00375   */
00376   newplayer->load(stream);
00377   if (isvirtual)
00378   {
00379     newplayer->setVirtual(true);
00380   }
00381   return newplayer;
00382 }
00383 
00384 // ----------------- Player handling -----------------------
00385 
00386 KPlayer * KGame::findPlayer(Q_UINT32 id) const
00387 {
00388  for (QPtrListIterator<KPlayer> it(d->mPlayerList); it.current(); ++it)
00389  {
00390    if (it.current()->id() == id)
00391    {
00392      return it.current();
00393    }
00394  }
00395  for (QPtrListIterator<KPlayer> it(d->mInactivePlayerList); it.current(); ++it)
00396  {
00397    if (it.current()->id() == id)
00398    {
00399      return it.current();
00400    }
00401  }
00402  return 0;
00403 }
00404 
00405 // it is necessary that addPlayer and systemAddPlayer are called in the same
00406 // order. Ie if addPlayer(foo) followed by addPlayer(bar) is called, you must
00407 // not call systemAddPlayer(bar) followed by systemAddPlayer(foo), as the
00408 // mAddPlayerList would get confused. Should be no problem as long as comServer
00409 // and the clients are working correctly.
00410 // BUT: if addPlayer(foo) does not arrive by any reason while addPlayer(bar)
00411 // does, we would be in trouble...
00412 void KGame::addPlayer(KPlayer* newplayer)
00413 {
00414  kdDebug(11001) << k_funcinfo << ":  " << "; maxPlayers=" << maxPlayers() << " playerCount=" << playerCount() << endl;
00415  if (!newplayer)
00416  {
00417   kdFatal(11001) << "trying to add NULL player in KGame::addPlayer()" << endl;
00418   return ;
00419  }
00420 
00421  if (maxPlayers() >= 0 && (int)playerCount() >= maxPlayers())
00422  {
00423    kdWarning(11001) << "cannot add more than " << maxPlayers() << " players - deleting..." << endl;
00424    delete newplayer;
00425    return;
00426  }
00427 
00428  if (newplayer->id() == 0)
00429  {
00430    d->mUniquePlayerNumber++;
00431    newplayer->setId(KGameMessage::createPlayerId(d->mUniquePlayerNumber, gameId()));
00432    kdDebug(11001) << k_funcinfo << "NEW!!! player " << newplayer << " now has id " << newplayer->id() << endl;
00433  }
00434  else
00435  {
00436    // this could happen in games which use their own ID management by certain
00437    // reasons. that is NOT recommended
00438    kdDebug(11001) << k_funcinfo << "player " << newplayer << " already has an id: " << newplayer->id() << endl;
00439  }
00440 
00441  QByteArray buffer;
00442  QDataStream stream(buffer,IO_WriteOnly);
00443  // We distinguis here what policy we have
00444  if (policy()==PolicyLocal || policy()==PolicyDirty)
00445  {
00446    systemAddPlayer(newplayer);
00447  }
00448  if (policy()==PolicyClean || policy()==PolicyDirty)
00449  {
00450    savePlayer(stream,newplayer);
00451    // Store the player for delayed clean adding
00452    if (policy()==PolicyClean)
00453    {
00454      d->mAddPlayerList.enqueue(newplayer);
00455    }
00456    sendSystemMessage(stream,(int)KGameMessage::IdAddPlayer, 0);
00457  }
00458 }
00459 
00460 void KGame::systemAddPlayer(KPlayer* newplayer)
00461 {
00462  if (!newplayer)
00463  {
00464    kdFatal(11001) << "trying to add NULL player in KGame::systemAddPlayer()" << endl;
00465    return ;
00466  }
00467  if (newplayer->id() == 0)
00468  {
00469    kdWarning(11001) << k_funcinfo << "player " << newplayer << " has no ID" << endl;
00470  }
00471 
00472  if (findPlayer(newplayer->id()))
00473  {
00474    kdError(11001) << "ERROR: Double adding player !!!!! NOT GOOD !!!!!! " << newplayer->id() << "...I delete it again" << endl;
00475    delete newplayer;
00476  }
00477  else
00478  {
00479    kdDebug(11001) << "Trying to add player " << newplayer <<" maxPlayers="<<maxPlayers()<<" playerCount="<<playerCount() << endl;
00480    // Add the player to the game
00481    d->mPlayerList.append(newplayer);
00482    newplayer->setGame(this);
00483    kdDebug(11001) << "Player: isVirtual=" << newplayer->isVirtual() << endl;
00484    kdDebug(11001) << "        id=" << newplayer->id() << "  #Players="
00485                   << d->mPlayerList.count() << " added " << newplayer
00486                   << "  (virtual=" << newplayer->isVirtual() << ")" << endl;
00487    emit signalPlayerJoinedGame(newplayer);
00488  }
00489 }
00490 
00491 // Called by the KPlayer destructor
00492 void KGame::playerDeleted(KPlayer *player)
00493 {
00494  kdDebug(11001) << k_funcinfo << ": id (" << player->id() << ") to be removed " << player << endl;
00495 
00496  if (policy()==PolicyLocal || policy()==PolicyDirty)
00497  {
00498    systemRemovePlayer(player,false);
00499  }
00500  if (policy()==PolicyClean || policy()==PolicyDirty)
00501  {
00502    if (!player->isVirtual())
00503    {
00504      kdDebug(11001) << k_funcinfo << ": sending IdRemovePlayer "<<player->id() << endl;
00505      sendSystemMessage(player->id(), KGameMessage::IdRemovePlayer, 0);
00506    }
00507  }
00508 }
00509 
00510 bool KGame::removePlayer(KPlayer * player, Q_UINT32 receiver)
00511 {//transmit to all clients, or to receiver only
00512  if (!player)
00513  {
00514    kdFatal(11001) << "trying to remove NULL player in KGame::removePlayer()" << endl;
00515    return false;
00516  }
00517  kdDebug(11001) << k_funcinfo << ": id (" << player->id() << ") to be removed " << player << endl;
00518 
00519  if (policy()==PolicyLocal || policy()==PolicyDirty)
00520  {
00521    systemRemovePlayer(player,true);
00522  }
00523  if (policy()==PolicyClean || policy()==PolicyDirty)
00524  {
00525    kdDebug(11001) << k_funcinfo << ": sending IdRemovePlayer "<<player->id() << endl;
00526    sendSystemMessage(player->id(),KGameMessage::IdRemovePlayer, receiver);
00527  }
00528  return true;
00529  // we will receive the message in networkTransmission()
00530 }
00531 
00532 void KGame::systemRemovePlayer(KPlayer* player,bool deleteit)
00533 {
00534  kdDebug(11001) << k_funcinfo << endl;
00535  if (!player)
00536  {
00537    kdWarning(11001) << "cannot remove NULL player" << endl;
00538    return;
00539  }
00540  if (!systemRemove(player,deleteit))
00541  {
00542    kdWarning(11001) << "player " << player << "(" << player->id() << ") Could not be found!" << endl;
00543  }
00544 
00545  if (gameStatus()==(int)Run && playerCount()<minPlayers())
00546  {
00547    kdWarning(11001) << k_funcinfo ": not enough players, PAUSING game\n" << endl;
00548    setGameStatus(Pause);
00549  }
00550 }
00551 
00552 bool KGame::systemRemove(KPlayer* p,bool deleteit)
00553 {
00554  if (!p)
00555  {
00556    kdWarning(11001) << "cannot remove NULL player" << endl;
00557    return false;
00558  }
00559  bool result;
00560  kdDebug(11001) << k_funcinfo << ": Player (" << p->id() << ") to be removed " << p << endl;
00561 
00562  if (d->mPlayerList.count() == 0)
00563  {
00564    result = false;
00565  }
00566  else
00567  {
00568    result = d->mPlayerList.remove(p);
00569  }
00570 
00571  emit signalPlayerLeftGame(p);
00572 
00573  p->setGame(0);
00574  if (deleteit)
00575  {
00576    delete p;
00577  }
00578 
00579  return result;
00580 }
00581 
00582 bool KGame::inactivatePlayer(KPlayer* player)
00583 {
00584  if (!player)
00585  {
00586    return false;
00587  }
00588  kdDebug(11001) << "Inactivate player " << player->id() << endl;
00589 
00590  if (policy()==PolicyLocal || policy()==PolicyDirty)
00591  {
00592    systemInactivatePlayer(player);
00593  }
00594  if (policy()==PolicyClean || policy()==PolicyDirty)
00595  {
00596    sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer);
00597  }
00598 
00599  return true;
00600 }
00601 
00602 bool KGame::systemInactivatePlayer(KPlayer* player)
00603 {
00604  if (!player || !player->isActive())
00605  {
00606    return false;
00607  }
00608  kdDebug(11001) << " Inactivate player " << player->id() << endl;
00609 
00610  int pid=player->id();
00611  // Virtual players cannot be deactivated. They will be removed
00612  if (player->isVirtual())
00613  {
00614    systemRemovePlayer(player,true);
00615  }
00616  else
00617  {
00618    d->mPlayerList.remove(player);
00619    d->mInactivePlayerList.prepend(player);
00620    player->setActive(false);
00621  }
00622  emit signalPlayerLeftGame(player);
00623  if (isAdmin())
00624  {
00625    d->mInactiveIdList.prepend(pid);
00626  }
00627  return true;
00628 }
00629 
00630 bool KGame::activatePlayer(KPlayer * player)
00631 {
00632   if (!player)
00633   {
00634     return false;
00635   }
00636   kdDebug(11001) << k_funcinfo << ": activate " << player->id() << endl;
00637   if (policy()==PolicyLocal || policy()==PolicyDirty)
00638   {
00639     systemActivatePlayer(player);
00640   }
00641   if (policy()==PolicyClean || policy()==PolicyDirty)
00642   {
00643     sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer);
00644   }
00645  return true;
00646 }
00647 
00648 bool KGame::systemActivatePlayer(KPlayer* player)
00649 {
00650  if (!player || player->isActive())
00651  {
00652    return false;
00653  }
00654  kdDebug(11001) << k_funcinfo << ": activate " << player->id() << endl;
00655 
00656  d->mInactivePlayerList.remove(player);
00657  player->setActive(true);
00658  addPlayer(player);
00659  if (isAdmin())
00660  {
00661    d->mInactiveIdList.remove(player->id());
00662  }
00663  return true;
00664 }
00665 
00666 // -------------------- Properties ---------------------------
00667 
00668 void KGame::setMaxPlayers(uint maxnumber)
00669 { if (isAdmin()) { d->mMaxPlayer.changeValue(maxnumber); } }
00670 
00671 void KGame::setMinPlayers(uint minnumber)
00672 { if (isAdmin()) { d->mMinPlayer.changeValue(minnumber); } }
00673 
00674 uint KGame::minPlayers() const
00675 { return d->mMinPlayer.value(); }
00676 
00677 int KGame::maxPlayers() const
00678 { return d->mMaxPlayer.value(); }
00679 
00680 uint KGame::playerCount() const
00681 { return d->mPlayerList.count(); }
00682 
00683 int KGame::gameStatus() const
00684 { return d->mGameStatus.value(); }
00685 
00686 bool KGame::isRunning() const
00687 { return d->mGameStatus.value() == Run; }
00688 
00689 KGamePropertyHandler* KGame::dataHandler() const
00690 { return d->mProperties; }
00691 
00692 
00693 KGame::KGamePlayerList* KGame::inactivePlayerList()
00694 { return &d->mInactivePlayerList; }
00695 
00696 const KGame::KGamePlayerList* KGame::inactivePlayerList() const
00697 { return &d->mInactivePlayerList; }
00698 
00699 KGame::KGamePlayerList* KGame::playerList()
00700 { return &d->mPlayerList; }
00701 
00702 const KGame::KGamePlayerList* KGame::playerList() const
00703 { return &d->mPlayerList; }
00704 
00705 KRandomSequence* KGame::random() const
00706 { return d->mRandom; }
00707 
00708 
00709 bool KGame::sendPlayerInput(QDataStream &msg, KPlayer *player, Q_UINT32 sender)
00710 {
00711  if (!player)
00712  {
00713    kdError(11001) << k_funcinfo << ": NULL player" << endl;
00714    return false;
00715  }
00716  if (!isRunning())
00717  {
00718    kdError(11001) << k_funcinfo << ": game not running" << endl;
00719    return false;
00720  }
00721 
00722  kdDebug(11001) << k_funcinfo << ": transmitting playerInput over network" << endl;
00723  sendSystemMessage(msg, (int)KGameMessage::IdPlayerInput, player->id(), sender);
00724  return true;
00725 }
00726 
00727 bool KGame::systemPlayerInput(QDataStream &msg, KPlayer *player, Q_UINT32 sender)
00728 {
00729  if (!player)
00730  {
00731    kdError(11001) << k_funcinfo << ": NULL player" << endl;
00732    return false;
00733  }
00734  if (!isRunning())
00735  {
00736    kdError(11001) << k_funcinfo << ": game not running" << endl;
00737    return false;
00738  }
00739  kdDebug(11001) << "KGame: Got playerInput from messageServer... sender: " << sender << endl;
00740  if (playerInput(msg,player))
00741  {
00742    playerInputFinished(player);
00743  }
00744  else
00745  {
00746    kdDebug(11001) << k_funcinfo<<": switching off player input"<<endl;
00747    // TODO: (MH 03-2003): We need an return option from playerInput so that
00748    // the player's is not automatically disabled here 
00749    if (!player->asyncInput())
00750    {
00751      player->setTurn(false); // in turn based games we have to switch off input now
00752    }
00753  }
00754  return true;
00755 }
00756 
00757 
00758 KPlayer * KGame::playerInputFinished(KPlayer *player)
00759 {
00760  kdDebug(11001) << k_funcinfo<<"player input finished for "<<player->id()<<endl;
00761  // Check for game over and if not allow the next player to move
00762  int gameOver = 0;
00763  if (gameSequence())
00764  {
00765    gameSequence()->setCurrentPlayer(player);
00766  }
00767  // do not call gameSequence()->checkGameOver() to keep backward compatibility!
00768  gameOver = checkGameOver(player);
00769  if (gameOver!=0)
00770  {
00771    if (player)
00772    {
00773      player->setTurn(false);
00774    }
00775    setGameStatus(End);
00776    emit signalGameOver(gameOver,player,this);
00777  }
00778  else if (!player->asyncInput())
00779  {
00780    player->setTurn(false); // in turn based games we have to switch off input now
00781    if (gameSequence())
00782    {
00783      QTimer::singleShot(0,this,SLOT(prepareNext()));
00784    }
00785  }
00786  return player;
00787 }
00788 
00789 // Per default we do not do anything
00790 int KGame::checkGameOver(KPlayer *player)
00791 {
00792  if (gameSequence())
00793  {
00794    return gameSequence()->checkGameOver(player);
00795  }
00796  return 0;
00797 }
00798 
00799 void KGame::setGameSequence(KGameSequence* sequence)
00800 {
00801  delete d->mGameSequence;
00802  d->mGameSequence = sequence;
00803  if (d->mGameSequence)
00804  {
00805    d->mGameSequence->setGame(this);
00806  }
00807 }
00808 
00809 KGameSequence* KGame::gameSequence() const
00810 {
00811   return d->mGameSequence;
00812 }
00813 
00814 void KGame::prepareNext()
00815 {
00816  if (gameSequence())
00817  {
00818    // we don't call gameSequence->nextPlayer() to keep old code working
00819    nextPlayer(gameSequence()->currentPlayer());
00820  }
00821 }
00822 
00823 KPlayer *KGame::nextPlayer(KPlayer *last,bool exclusive)
00824 {
00825  if (gameSequence())
00826  {
00827    return gameSequence()->nextPlayer(last, exclusive);
00828  }
00829  return 0;
00830 }
00831 
00832 void KGame::setGameStatus(int status)
00833 {
00834  kdDebug(11001) << k_funcinfo << ": GAMESTATUS CHANGED  to" << status << endl;
00835  if (status==(int)Run && playerCount()<minPlayers()) 
00836  {
00837    kdDebug(11001) << k_funcinfo << ": not enough players, pausing game\n" << endl;
00838    status=Pause;
00839  }
00840  d->mGameStatus = status;
00841 }
00842 
00843 void KGame::networkTransmission(QDataStream &stream, int msgid, Q_UINT32 receiver, Q_UINT32 sender, Q_UINT32 /*clientID*/)
00844 {//clientID is unused
00845  // message targets a playerobject. If we find it we forward the message to the
00846  // player. Otherwise we proceed here and hope the best that the user processes
00847  // the message
00848 
00849 //  kdDebug(11001) << k_funcinfo << ": we="<<(int)gameId()<<" id="<<msgid<<" recv=" << receiver << " sender=" << sender << endl;
00850 
00851  
00852  // *first* notice the game that something has changed - so no return prevents
00853  // this
00854  emit signalMessageUpdate(msgid, receiver, sender);
00855  if (KGameMessage::isPlayer(receiver))
00856  {
00857    //kdDebug(11001) << "message id " << msgid << " seems to be for a player ("<<active=p->isActive()<<" recv="<< receiver << endl;
00858    KPlayer *p=findPlayer(receiver);
00859    if (p && p->isActive())
00860    {
00861      p->networkTransmission(stream,msgid,sender);
00862      return;
00863    }
00864    if (p)
00865    {
00866       kdDebug(11001) << "player is here but not active" << endl;
00867    }
00868    else
00869    {
00870       kdDebug(11001) << "no player found" << endl;
00871    }
00872  }
00873  // If it is not for a player it is meant for us!!!! Otherwise the
00874  // gamenetwork would not have passed the message to us!
00875 
00876  // GameProperties processed
00877  if (d->mProperties->processMessage(stream, msgid, sender == gameId())) 
00878  {
00879 //   kdDebug(11001 ) << "KGame: message taken by property - returning" << endl;
00880    return ;
00881  }
00882 
00883  switch(msgid)
00884  {
00885    case KGameMessage::IdSetupGame:  // Client: First step in setup game
00886    {
00887      Q_INT16 v;
00888      Q_INT32 c;
00889      stream >> v >> c;
00890      kdDebug(11001) << " ===================> (Client) " << k_funcinfo << ": Got IdSetupGame ================== " << endl;
00891      kdDebug(11001) << "our game id is " << gameId() << " Lib version=" << v << " App Cookie=" << c << endl; 
00892      // Verify identity of the network partners
00893      if (c!=cookie())
00894      {
00895        kdError(11001) << "IdGameSetup: Negotiate Game: cookie mismatch I'am="<<cookie()<<" master="<<c<<endl;
00896        sendError(KGameError::Cookie, KGameError::errCookie(cookie(), c));
00897        disconnect(); // disconnect from master
00898      }
00899      else if (v!=KGameMessage::version())
00900      {
00901        sendError(KGameError::Version, KGameError::errVersion(v));
00902        disconnect(); // disconnect from master
00903      }
00904      else
00905      {
00906        setupGame(sender);
00907      }
00908      kdDebug(11001) << "========== (Client) Setup game done\n";
00909    }
00910    break;
00911    case KGameMessage::IdSetupGameContinue:  // Master: second step in game setup
00912    {
00913      kdDebug(11001) << "=====>(Master) " << k_funcinfo << " - IdSetupGameContinue" << endl;
00914      setupGameContinue(stream, sender);
00915    }
00916    break;
00917    case KGameMessage::IdActivatePlayer:  // Activate Player
00918    {
00919      int id;
00920      stream >> id;
00921      kdDebug(11001) << "Got IdActivatePlayer id=" << id << endl;
00922      if (sender!=gameId()  || policy()!=PolicyDirty)
00923      {
00924        systemActivatePlayer(findPlayer(id));
00925      }
00926    }
00927    break;
00928    case KGameMessage::IdInactivatePlayer:  // Inactivate Player
00929    {
00930      int id;
00931      stream >> id;
00932      kdDebug(11001) << "Got IdInactivatePlayer id=" << id << endl;
00933      if (sender!=gameId()  || policy()!=PolicyDirty)
00934      {
00935        systemInactivatePlayer(findPlayer(id));
00936      }
00937    }
00938    break;
00939    case KGameMessage::IdAddPlayer:
00940    {
00941      kdDebug(11001) << k_funcinfo << ": Got IdAddPlayer" << endl;
00942      if (sender!=gameId()  || policy()!=PolicyDirty)
00943      {
00944        KPlayer *newplayer=0;
00945        // We sent the message so the player is already available
00946        if (sender==gameId())
00947        {
00948           kdDebug(11001) << "dequeue previously added player" << endl;
00949           newplayer = d->mAddPlayerList.dequeue();
00950        }
00951        else
00952        {
00953          newplayer=loadPlayer(stream,true);
00954        }
00955        systemAddPlayer(newplayer);// the final, local, adding
00956        //systemAddPlayer(stream);
00957      }
00958    }
00959    break;
00960    case KGameMessage::IdRemovePlayer: // Client should delete player id
00961    {
00962      int id;
00963      stream >> id;
00964      kdDebug(11001) << k_funcinfo << ": Got IdRemovePlayer " << id << endl;
00965      KPlayer *p=findPlayer(id);
00966      if (p)
00967      {
00968        // Otherwise the player is already removed
00969        if (sender!=gameId()  || policy()!=PolicyDirty)
00970        {
00971          systemRemovePlayer(p,true);
00972        }
00973      }
00974      else
00975      {
00976        kdWarning(11001) << k_funcinfo << "Cannot find player " << id << endl;
00977      }
00978    }
00979    break;
00980    case KGameMessage::IdGameLoad:
00981    {
00982      kdDebug(11001) << "====> (Client) " << k_funcinfo << ": Got IdGameLoad" << endl;
00983      loadgame(stream,true,false);
00984    }
00985    break;
00986    case KGameMessage::IdGameSetupDone:
00987    {
00988      int cid;
00989      stream >> cid;
00990      kdDebug(11001) << "====> (CLIENT) " << k_funcinfo << ": Got IdGameSetupDone for client "
00991              << cid << " we are =" << gameId() << endl;
00992      sendSystemMessage(gameId(), KGameMessage::IdGameConnected, 0);
00993    }
00994    break;
00995    case KGameMessage::IdGameConnected:
00996    {
00997      int cid;
00998      stream >> cid;
00999      kdDebug(11001) << "====> (ALL) " << k_funcinfo << ": Got IdGameConnected for client "<< cid << " we are =" << gameId() << endl;
01000      emit signalClientJoinedGame(cid,this);
01001    }
01002    break;
01003 
01004    case KGameMessage::IdSyncRandom:  // Master forces a new random seed on us
01005    {
01006      int newseed;
01007      stream >> newseed;
01008      kdDebug(11001) << "CLIENT: setting random seed to " << newseed << endl;
01009      d->mRandom->setSeed(newseed);
01010    }
01011    break;
01012    case KGameMessage::IdDisconnect:
01013    {
01014    // if we disconnect we *always* start a local game. 
01015    // this could lead into problems if we just change the message server
01016      if (sender != gameId())
01017      {
01018          kdDebug(11001) << "client " << sender << " leaves game" << endl;
01019          return;
01020      }
01021      kdDebug(11001) << "leaving the game" << endl;
01022      // start a new local game
01023      // no other client is by default connected to this so this call should be
01024      // enough
01025      setMaster();
01026    }
01027    break;
01028    default:
01029     {
01030      if (msgid < KGameMessage::IdUser)
01031      {
01032        kdError(11001) << "incorrect message id " << msgid << " - emit anyway"
01033                       << endl;
01034      }
01035      kdDebug(11001) << k_funcinfo << ": User data msgid " << msgid << endl;
01036      emit signalNetworkData(msgid - KGameMessage::IdUser,((QBuffer*)stream.device())->readAll(),receiver,sender);
01037    }
01038    break;
01039  }
01040 
01041 }
01042 
01043 // called by the IdSetupGameContinue Message - MASTER SIDE
01044 // Here the master needs to decide which players can take part at the game
01045 // and which will be deactivated
01046 void KGame::setupGameContinue(QDataStream& stream, Q_UINT32 sender)
01047 {
01048   KPlayer *player;
01049   Q_INT32 cnt;
01050   int i;
01051   stream >> cnt;
01052 
01053   QValueList<int> inactivateIds;
01054 
01055   KGamePlayerList newPlayerList;
01056   newPlayerList.setAutoDelete(true);
01057   for (i=0;i<cnt;i++)
01058   {
01059     player=loadPlayer(stream,true);
01060     kdDebug(11001) << " Master got player " << player->id() <<" rawgame=" << KGameMessage::rawGameId(player->id())  << " from sender " << sender << endl;
01061     if (KGameMessage::rawGameId(player->id()) != sender)
01062     {
01063       kdError(11001) << "Client tries to add player with wrong game id - cheat possible" << endl;
01064     }
01065     else
01066     {
01067       newPlayerList.append(player);
01068       kdDebug(11001) << " newplayerlist appended " << player->id() << endl;
01069     }
01070   }
01071 
01072   newPlayersJoin(playerList(),&newPlayerList,inactivateIds);
01073 
01074 
01075   kdDebug(11001) << " Master calculates how many players to activate client has cnt=" << cnt << endl;
01076   kdDebug(11001) << " The game has " << playerCount() << " active players" << endl;
01077   kdDebug(11001) << " The user deactivated "<< inactivateIds.count() << " player already " << endl;
01078   kdDebug(11001) << " MaxPlayers for this game is " << maxPlayers() << endl;
01079 
01080   // Do we have too many players? (After the programmer disabled some?)
01081   // MH: We cannot use have player here as it CHANGES in the loop
01082   // int havePlayers = cnt+playerCount()-inactivateIds.count();
01083   kdDebug(11001) << " havePlayers " << cnt+playerCount()-inactivateIds.count() << endl;
01084   while (maxPlayers() > 0 && maxPlayers() < (int)(cnt+playerCount() - inactivateIds.count()))
01085   {
01086     kdDebug(11001) << "  Still to deacticvate "
01087             << (int)(cnt+playerCount()-inactivateIds.count())-(int)maxPlayers() 
01088             << endl;
01089     KPlayer *currentPlayer=0;
01090     int currentPriority=0x7fff; // MAX_UINT (16bit?) to get the maximum of the list
01091     // find lowest network priority which is not yet in the newPlayerList
01092     // do this for the new players
01093     for ( player=newPlayerList.first(); player != 0; player=newPlayerList.next() ) 
01094     {
01095       // Already in the list
01096       if (inactivateIds.find(player->id())!=inactivateIds.end()) 
01097       {
01098         continue;
01099       }
01100       if (player->networkPriority()<currentPriority)
01101       {
01102         currentPriority=player->networkPriority();
01103         currentPlayer=player;
01104       }
01105     }
01106 
01107     // find lowest network priority which is not yet in the newPlayerList
01108     // Do this for the network players
01109     for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 
01110     {
01111       // Already in the list
01112       if (inactivateIds.find(player->id())!=inactivateIds.end()) 
01113       {
01114         continue;
01115       }
01116       if (player->networkPriority()<currentPriority)
01117       {
01118         currentPriority=player->networkPriority();
01119         currentPlayer=player;
01120       }
01121     }
01122 
01123     // add it to inactivateIds
01124     if (currentPlayer)
01125     {
01126       kdDebug(11001) << "Marking player " << currentPlayer->id() << " for inactivation" << endl;
01127       inactivateIds.append(currentPlayer->id());
01128     }
01129     else
01130     {
01131       kdError(11001) << "Couldn't find a player to dectivate..That is not so good..." << endl;
01132       break;
01133     }
01134   }
01135 
01136   kdDebug(11001) << "Alltogether deactivated " << inactivateIds.count() << " players" << endl;
01137 
01138   QValueList<int>::Iterator it;
01139   for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it )
01140   {
01141     int pid=*it;
01142     kdDebug(11001) << " pid=" << pid << endl;
01143   }
01144 
01145   // Now deactivate the network players from the inactivateId list
01146   //QValueList<int>::Iterator it;
01147   for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it )
01148   {
01149     int pid=*it;
01150     if (KGameMessage::rawGameId(pid) == sender)
01151     {
01152       continue; // client's player
01153     }
01154     kdDebug(11001) << " -> the network needs to deactivate " << pid <<endl;
01155     player=findPlayer(pid);
01156     if (player)
01157     {
01158       // We have to make REALLY sure that the player is gone. With any policy
01159       systemInactivatePlayer(player);
01160       if (policy()!=PolicyLocal)
01161       {
01162         sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer);
01163       }
01164     }
01165     else
01166     {
01167       kdError(11001) << " We should deactivate a player, but cannot find it...not good." << endl;
01168     }
01169   }
01170 
01171   // Now send out the player list which the client can activate
01172   for ( player=newPlayerList.first(); player != 0; player=newPlayerList.next() )
01173   {
01174     kdDebug(11001) << " newplayerlist contains " << player->id() << endl;
01175     // Only activate what is not in the list
01176     if (inactivateIds.find(player->id())!=inactivateIds.end())
01177     {
01178       continue;
01179     }
01180     kdDebug(11001) << " -> the client can ******** reactivate ********  " << player->id() << endl;
01181     sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer, sender);
01182   }
01183 
01184   // Save the game over the network
01185   QByteArray bufferS;
01186   QDataStream streamS(bufferS,IO_WriteOnly);
01187   // Save game over netowrk and save players
01188   savegame(streamS,true,true);
01189   sendSystemMessage(streamS,KGameMessage::IdGameLoad,sender);
01190 
01191 
01192   // Only to the client first , as the client will add players
01193   sendSystemMessage(sender, KGameMessage::IdGameSetupDone, sender);
01194 }
01195 
01196 // called by the IdSetupGame Message - CLIENT SIDE
01197 // Client needs to prepare for network transfer
01198 void KGame::setupGame(Q_UINT32 sender)
01199 {
01200   QByteArray bufferS;
01201   QDataStream streamS(bufferS,IO_WriteOnly);
01202 
01203   // Deactivate all players
01204   KGamePlayerList mTmpList(d->mPlayerList); // we need copy otherwise the removal crashes
01205   Q_INT32 cnt=mTmpList.count();
01206   kdDebug(11001) << "Client: playerlistcount=" << d->mPlayerList.count() << " tmplistcout=" << cnt << endl;
01207 
01208   streamS << cnt;
01209 
01210   QPtrListIterator<KPlayer> it(mTmpList);
01211   KPlayer *player;
01212   while (it.current())
01213   {
01214     player=it.current();
01215     systemInactivatePlayer(player);
01216     // Give the new game id to all players (which are inactivated now)
01217     player->setId(KGameMessage::createPlayerId(player->id(),gameId()));
01218 
01219     // Save it for the master to decide what to do
01220     savePlayer(streamS,player);
01221 
01222     ++it;
01223     --cnt;
01224   }
01225   if (d->mPlayerList.count() > 0 || cnt!=0)
01226   {
01227     kdFatal(11001) << "KGame::setupGame(): Player list is not empty! or cnt!=0=" <<cnt << endl;
01228   }
01229 
01230   sendSystemMessage(streamS,KGameMessage::IdSetupGameContinue,sender);
01231 }
01232 
01233 // unused by KGame
01234 void KGame::syncRandom()
01235 {
01236  int newseed=(int)d->mRandom->getLong(65535);
01237  sendSystemMessage(newseed,KGameMessage::IdSyncRandom); // Broadcast
01238  d->mRandom->setSeed(newseed);
01239 }
01240 
01241 void KGame::Debug()
01242 {
01243  KGameNetwork::Debug();
01244  kdDebug(11001) << "------------------- KGAME -------------------------" << endl;
01245  kdDebug(11001) << "this:          " << this << endl;
01246  kdDebug(11001) << "uniquePlayer   " << d->mUniquePlayerNumber << endl;
01247  kdDebug(11001) << "gameStatus     " << gameStatus() << endl;
01248  kdDebug(11001) << "MaxPlayers :   " << maxPlayers() << endl;
01249  kdDebug(11001) << "NoOfPlayers :  " << playerCount() << endl;
01250  kdDebug(11001) << "NoOfInactive:  " << d->mInactivePlayerList.count() << endl;
01251  kdDebug(11001) << "---------------------------------------------------" << endl;
01252 }
01253 
01254 void KGame::slotClientConnected(Q_UINT32 clientID)
01255 {
01256  if (isAdmin())
01257  {
01258    negotiateNetworkGame(clientID);
01259  }
01260 }
01261 
01262 void KGame::slotServerDisconnected() // Client side
01263 {
01264   kdDebug(11001) << "======= SERVER DISCONNECT ======="<<endl;
01265   kdDebug(11001) << "+++ (CLIENT)++++++++" << k_funcinfo << ": our GameID="<<gameId() << endl;
01266 
01267   int oldgamestatus=gameStatus();
01268 
01269   KPlayer *player;
01270   KGamePlayerList removeList;
01271   kdDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << " count" << endl;
01272   kdDebug(11001) << "Inactive Playerlist of client=" << d->mInactivePlayerList.count() << " count" << endl;
01273   for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 
01274   {
01275     // TODO: CHECK: id=0, could not connect to server in the first place??
01276     if (KGameMessage::rawGameId(player->id()) != gameId() && gameId()!=0)
01277     {
01278       kdDebug(11001) << "Player " << player->id() << " belongs to a removed game" << endl;
01279       removeList.append(player);
01280     }
01281   }
01282 
01283   for ( player=removeList.first(); player != 0; player=removeList.next() )
01284   {
01285     bool remove = true;
01286     emit signalReplacePlayerIO(player, &remove);
01287     if (remove)
01288     {
01289       kdDebug(11001) << " ---> Removing player " << player->id() <<  endl;
01290       systemRemovePlayer(player,true); // no network necessary
01291     }
01292   }
01293 
01294   setMaster();
01295   kdDebug(11001) << " our game id is after setMaster " << gameId() << endl;
01296 
01297   KGamePlayerList mReList(d->mInactivePlayerList);
01298   for ( player=mReList.first(); player != 0; player=mReList.next() )
01299   {
01300     // TODO ?check for priority? Sequence should be ok
01301     if ((int)playerCount()<maxPlayers() || maxPlayers()<0)
01302     {
01303       systemActivatePlayer(player);
01304     }
01305   }
01306   kdDebug(11001) << " Players activated player-cnt=" << playerCount() << endl;
01307 
01308   for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 
01309   {
01310     int oldid=player->id();
01311     d->mUniquePlayerNumber++;
01312     player->setId(KGameMessage::createPlayerId(d->mUniquePlayerNumber,gameId()));
01313     kdDebug(11001) << "Player id " << oldid <<" changed to " << player->id() << " as we are now local" << endl;
01314   }
01315   // TODO clear inactive lists ?
01316   Debug();
01317   for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 
01318   {
01319     player->Debug();
01320   }
01321   kdDebug(11001) << "+++++++++++" << k_funcinfo << " DONE=" << endl;
01322   emit signalClientLeftGame(0,oldgamestatus,this);
01323 }
01324 
01325 void KGame::slotClientDisconnected(Q_UINT32 clientID,bool /*broken*/) // server side
01326 {
01327  kdDebug(11001) << "++++(SERVER)+++++++" << k_funcinfo << " clientId=" << clientID << endl;
01328 
01329  int oldgamestatus=gameStatus();
01330 
01331  KPlayer *player;
01332  KGamePlayerList removeList;
01333  kdDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << " count" << endl;
01334  for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() )
01335  {
01336    if (KGameMessage::rawGameId(player->id())==clientID)
01337    {
01338      kdDebug(11001) << "Player " << player->id() << " belongs to the removed game" << endl;
01339      removeList.append(player);
01340    }
01341  }
01342 
01343  for ( player=removeList.first(); player != 0; player=removeList.next() )
01344  {
01345    // try to replace the KGameIO first
01346    bool remove = true;
01347    emit signalReplacePlayerIO(player, &remove);
01348    if (remove) {
01349      // otherwise (no new KGameIO) remove the player
01350      kdDebug(11001) << " ---> Removing player " << player->id() <<  endl;
01351      removePlayer(player,0);
01352    }
01353  }
01354 
01355  // Now add inactive players - sequence should be ok
01356  // TODO remove players from removed game
01357  for (unsigned int idx=0;idx<d->mInactiveIdList.count();idx++)
01358  {
01359    QValueList<int>::Iterator it1 = d->mInactiveIdList.at(idx);
01360    player = findPlayer(*it1);
01361    if (((int)playerCount() < maxPlayers() || maxPlayers() < 0) && player && KGameMessage::rawGameId(*it1) != clientID)
01362    {
01363      activatePlayer(player);
01364    }
01365  }
01366   emit signalClientLeftGame(clientID,oldgamestatus,this);
01367 }
01368 
01369 
01370 // -------------------- Synchronisation -----------------------
01371 
01372 // this initializes a newly connected client.
01373 // we send the number of players (including type) as well as game status and
01374 // properties to the client. After the initialization has been completed both
01375 // clients should have the same status (ie players, properties, etc)
01376 void KGame::negotiateNetworkGame(Q_UINT32 clientID)
01377 {
01378  kdDebug(11001) << "===========================" << k_funcinfo << ": clientID=" << clientID << " =========================== "<< endl;
01379  if (!isAdmin())
01380  {
01381    kdError(11001) << k_funcinfo << ": Serious WARNING..only gameAdmin should call this" << endl;
01382    return ;
01383  }
01384 
01385  QByteArray buffer;
01386  QDataStream streamGS(buffer,IO_WriteOnly);
01387 
01388  // write Game setup specific data
01389  //streamGS << (Q_INT32)maxPlayers();
01390  //streamGS << (Q_INT32)minPlayers();
01391 
01392  // send to the newly connected client *only*
01393  Q_INT16 v=KGameMessage::version();
01394  Q_INT32 c=cookie();
01395  streamGS << v << c;
01396  sendSystemMessage(streamGS, KGameMessage::IdSetupGame, clientID);
01397 }
01398 
01399 bool KGame::sendGroupMessage(const QByteArray &msg, int msgid, Q_UINT32 sender, const QString& group)
01400 {
01401 // AB: group must not be i18n'ed!! we should better use an id for group and use
01402 // a groupName() for the name // FIXME
01403  KPlayer *player;
01404  for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() )
01405  {
01406    if (player && player->group()==group)
01407    {
01408      sendMessage(msg,msgid,player->id(), sender);
01409    }
01410  }
01411  return true;
01412 }
01413 
01414 bool KGame::sendGroupMessage(const QDataStream &msg, int msgid, Q_UINT32 sender, const QString& group)
01415 { return sendGroupMessage(((QBuffer*)msg.device())->buffer(), msgid, sender, group); }
01416 
01417 bool KGame::sendGroupMessage(const QString& msg, int msgid, Q_UINT32 sender, const QString& group)
01418 {
01419  QByteArray buffer;
01420  QDataStream stream(buffer, IO_WriteOnly);
01421  stream << msg;
01422  return sendGroupMessage(stream, msgid, sender, group);
01423 }
01424 
01425 bool KGame::addProperty(KGamePropertyBase* data)
01426 { return dataHandler()->addProperty(data); }
01427 
01428 bool KGame::sendPlayerProperty(int msgid, QDataStream& s, Q_UINT32 playerId)
01429 { return sendSystemMessage(s, msgid, playerId); }
01430 
01431 void KGame::sendProperty(int msgid, QDataStream& stream, bool* sent)
01432 {
01433   bool s = sendSystemMessage(stream, msgid);
01434   if (s)
01435   {
01436     *sent = true;
01437   }
01438 }
01439 
01440 void KGame::emitSignal(KGamePropertyBase *me)
01441 {
01442  emit signalPropertyChanged(me,this);
01443 }
01444 
01445 KGamePropertyBase* KGame::findProperty(int id) const
01446 { return d->mProperties->find(id); }
01447 
01448 KGame::GamePolicy KGame::policy() const
01449 {
01450  return d->mPolicy;
01451 }
01452 void KGame::setPolicy(GamePolicy p,bool recursive)
01453 {
01454  // Set KGame policy
01455  d->mPolicy=p;
01456  if (recursive)
01457  {
01458    // Set all KGame property policy
01459    dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false);
01460 
01461    // Set all KPLayer (active or inactive) property policy
01462    for (QPtrListIterator<KPlayer> it(d->mPlayerList); it.current(); ++it)
01463    {
01464      it.current()->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false);
01465    }
01466    for (QPtrListIterator<KPlayer> it(d->mInactivePlayerList); it.current(); ++it)
01467    {
01468      it.current()->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false);
01469    }
01470  }
01471 }
01472 
01473 /*
01474  * vim: et sw=2
01475  */
KDE Home | KDE Accessibility Home | Description of Access Keys