• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • libtdegames
 

libtdegames

  • libtdegames
  • highscore
kexthighscore_internal.cpp
1 /*
2  This file is part of the TDE games library
3  Copyright (C) 2001-2004 Nicolas Hadacek (hadacek@kde.org)
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 #include "kexthighscore_internal.h"
21 
22 #include <pwd.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 
26 #include <tqfile.h>
27 #include <tqlayout.h>
28 #include <tqdom.h>
29 
30 #include <tdeglobal.h>
31 #include <tdeio/netaccess.h>
32 #include <tdeio/job.h>
33 #include <tdemessagebox.h>
34 #include <kmdcodec.h>
35 #include <kdebug.h>
36 
37 #include "config.h"
38 #include "kexthighscore.h"
39 #include "kexthighscore_gui.h"
40 #include "tdeemailsettings.h"
41 
42 
43 namespace KExtHighscore
44 {
45 
46 //-----------------------------------------------------------------------------
47 const char ItemContainer::ANONYMOUS[] = "_";
48 const char ItemContainer::ANONYMOUS_LABEL[] = I18N_NOOP("anonymous");
49 
50 ItemContainer::ItemContainer()
51  : _item(0)
52 {}
53 
54 ItemContainer::~ItemContainer()
55 {
56  delete _item;
57 }
58 
59 void ItemContainer::setItem(Item *item)
60 {
61  delete _item;
62  _item = item;
63 }
64 
65 TQString ItemContainer::entryName() const
66 {
67  if ( _subGroup.isEmpty() ) return _name;
68  return _name + "_" + _subGroup;
69 }
70 
71 TQVariant ItemContainer::read(uint i) const
72 {
73  Q_ASSERT(_item);
74 
75  TQVariant v = _item->defaultValue();
76  if ( isStored() ) {
77  internal->hsConfig().setHighscoreGroup(_group);
78  v = internal->hsConfig().readPropertyEntry(i+1, entryName(), v);
79  }
80  return _item->read(i, v);
81 }
82 
83 TQString ItemContainer::pretty(uint i) const
84 {
85  Q_ASSERT(_item);
86  return _item->pretty(i, read(i));
87 }
88 
89 void ItemContainer::write(uint i, const TQVariant &value) const
90 {
91  Q_ASSERT( isStored() );
92  Q_ASSERT( internal->hsConfig().isLocked() );
93  internal->hsConfig().setHighscoreGroup(_group);
94  internal->hsConfig().writeEntry(i+1, entryName(), value);
95 }
96 
97 uint ItemContainer::increment(uint i) const
98 {
99  uint v = read(i).toUInt() + 1;
100  write(i, v);
101  return v;
102 }
103 
104 //-----------------------------------------------------------------------------
105 ItemArray::ItemArray()
106  : _group(""), _subGroup("") // no null groups
107 {}
108 
109 ItemArray::~ItemArray()
110 {
111  for (uint i=0; i<size(); i++) delete at(i);
112 }
113 
114 int ItemArray::findIndex(const TQString &name) const
115 {
116  for (uint i=0; i<size(); i++)
117  if ( at(i)->name()==name ) return i;
118  return -1;
119 }
120 
121 const ItemContainer *ItemArray::item(const TQString &name) const
122 {
123  int i = findIndex(name);
124  if ( i==-1 ) kdError(11002) << k_funcinfo << "no item named \"" << name
125  << "\"" << endl;
126  return at(i);
127 }
128 
129 ItemContainer *ItemArray::item(const TQString &name)
130 {
131  int i = findIndex(name);
132  if ( i==-1 ) kdError(11002) << k_funcinfo << "no item named \"" << name
133  << "\"" << endl;
134  return at(i);
135 }
136 
137 void ItemArray::setItem(const TQString &name, Item *item)
138 {
139  int i = findIndex(name);
140  if ( i==-1 ) kdError(11002) << k_funcinfo << "no item named \"" << name
141  << "\"" << endl;
142  bool stored = at(i)->isStored();
143  bool canHaveSubGroup = at(i)->canHaveSubGroup();
144  _setItem(i, name, item, stored, canHaveSubGroup);
145 }
146 
147 void ItemArray::addItem(const TQString &name, Item *item,
148  bool stored, bool canHaveSubGroup)
149 {
150  if ( findIndex(name)!=-1 )
151  kdError(11002) << "item already exists \"" << name << "\"" << endl;
152  uint i = size();
153  resize(i+1);
154  at(i) = new ItemContainer;
155  _setItem(i, name, item, stored, canHaveSubGroup);
156 }
157 
158 void ItemArray::_setItem(uint i, const TQString &name, Item *item,
159  bool stored, bool canHaveSubGroup)
160 {
161  at(i)->setItem(item);
162  at(i)->setName(name);
163  at(i)->setGroup(stored ? _group : TQString());
164  at(i)->setSubGroup(canHaveSubGroup ? _subGroup : TQString());
165 }
166 
167 void ItemArray::setGroup(const TQString &group)
168 {
169  Q_ASSERT( !group.isNull() );
170  _group = group;
171  for (uint i=0; i<size(); i++)
172  if ( at(i)->isStored() ) at(i)->setGroup(group);
173 }
174 
175 void ItemArray::setSubGroup(const TQString &subGroup)
176 {
177  Q_ASSERT( !subGroup.isNull() );
178  _subGroup = subGroup;
179  for (uint i=0; i<size(); i++)
180  if ( at(i)->canHaveSubGroup() ) at(i)->setSubGroup(subGroup);
181 }
182 
183 void ItemArray::read(uint k, Score &data) const
184 {
185  for (uint i=0; i<size(); i++) {
186  if ( !at(i)->isStored() ) continue;
187  data.setData(at(i)->name(), at(i)->read(k));
188  }
189 }
190 
191 void ItemArray::write(uint k, const Score &data, uint nb) const
192 {
193  for (uint i=0; i<size(); i++) {
194  if ( !at(i)->isStored() ) continue;
195  for (uint j=nb-1; j>k; j--) at(i)->write(j, at(i)->read(j-1));
196  at(i)->write(k, data.data(at(i)->name()));
197  }
198 }
199 
200 void ItemArray::exportToText(TQTextStream &s) const
201 {
202  for (uint k=0; k<nbEntries()+1; k++) {
203  for (uint i=0; i<size(); i++) {
204  const Item *item = at(i)->item();
205  if ( item->isVisible() ) {
206  if ( i!=0 ) s << '\t';
207  if ( k==0 ) s << item->label();
208  else s << at(i)->pretty(k-1);
209  }
210  }
211  s << endl;
212  }
213 }
214 
215 //-----------------------------------------------------------------------------
216 class ScoreNameItem : public NameItem
217 {
218  public:
219  ScoreNameItem(const ScoreInfos &score, const PlayerInfos &infos)
220  : _score(score), _infos(infos) {}
221 
222  TQString pretty(uint i, const TQVariant &v) const {
223  uint id = _score.item("id")->read(i).toUInt();
224  if ( id==0 ) return NameItem::pretty(i, v);
225  return _infos.prettyName(id-1);
226  }
227 
228  private:
229  const ScoreInfos &_score;
230  const PlayerInfos &_infos;
231 };
232 
233 //-----------------------------------------------------------------------------
234 ScoreInfos::ScoreInfos(uint maxNbEntries, const PlayerInfos &infos)
235  : _maxNbEntries(maxNbEntries)
236 {
237  addItem("id", new Item((uint)0));
238  addItem("rank", new RankItem, false);
239  addItem("name", new ScoreNameItem(*this, infos));
240  addItem("score", Manager::createItem(Manager::ScoreDefault));
241  addItem("date", new DateItem);
242 }
243 
244 uint ScoreInfos::nbEntries() const
245 {
246  uint i = 0;
247  for (; i<_maxNbEntries; i++)
248  if ( item("score")->read(i)==item("score")->item()->defaultValue() )
249  break;
250  return i;
251 }
252 
253 //-----------------------------------------------------------------------------
254 const char *HS_ID = "player id";
255 const char *HS_REGISTERED_NAME = "registered name";
256 const char *HS_KEY = "player key";
257 const char *HS_WW_ENABLED = "ww hs enabled";
258 
259 PlayerInfos::PlayerInfos()
260 {
261  setGroup("players");
262 
263  // standard items
264  addItem("name", new NameItem);
265  Item *it = new Item((uint)0, i18n("Games Count"),TQt::AlignRight);
266  addItem("nb games", it, true, true);
267  it = Manager::createItem(Manager::MeanScoreDefault);
268  addItem("mean score", it, true, true);
269  it = Manager::createItem(Manager::BestScoreDefault);
270  addItem("best score", it, true, true);
271  addItem("date", new DateItem, true, true);
272  it = new Item(TQString(), i18n("Comment"), TQt::AlignLeft);
273  addItem("comment", it);
274 
275  // statistics items
276  addItem("nb black marks", new Item((uint)0), true, true); // legacy
277  addItem("nb lost games", new Item((uint)0), true, true);
278  addItem("nb draw games", new Item((uint)0), true, true);
279  addItem("current trend", new Item((int)0), true, true);
280  addItem("max lost trend", new Item((uint)0), true, true);
281  addItem("max won trend", new Item((uint)0), true, true);
282 
283  struct passwd *pwd = getpwuid(getuid());
284  TQString username = pwd->pw_name;
285 #ifdef HIGHSCORE_DIRECTORY
286  internal->hsConfig().setHighscoreGroup("players");
287  for (uint i=0; ;i++) {
288  if ( !internal->hsConfig().hasEntry(i+1, "username") ) {
289  _newPlayer = true;
290  _id = i;
291  break;
292  }
293  if ( internal->hsConfig().readEntry(i+1, "username")==username ) {
294  _newPlayer = false;
295  _id = i;
296  return;
297  }
298  }
299 #endif
300  internal->hsConfig().lockForWriting();
301  KEMailSettings emailConfig;
302  emailConfig.setProfile(emailConfig.defaultProfileName());
303  TQString name = emailConfig.getSetting(KEMailSettings::RealName);
304  if ( name.isEmpty() || isNameUsed(name) ) name = username;
305  if ( isNameUsed(name) ) name= TQString(ItemContainer::ANONYMOUS);
306 #ifdef HIGHSCORE_DIRECTORY
307  internal->hsConfig().writeEntry(_id+1, "username", username);
308  item("name")->write(_id, name);
309 #endif
310 
311  ConfigGroup cg;
312  _oldLocalPlayer = cg.config()->hasKey(HS_ID);
313  _oldLocalId = cg.config()->readUnsignedNumEntry(HS_ID);
314 #ifdef HIGHSCORE_DIRECTORY
315  if (_oldLocalPlayer) { // player already exists in local config file
316  // copy player data
317  TQString prefix = TQString("%1_").arg(_oldLocalId+1);
318  TQMap<TQString, TQString> entries =
319  cg.config()->entryMap("KHighscore_players");
320  TQMap<TQString, TQString>::const_iterator it;
321  for (it=entries.begin(); it!=entries.end(); ++it) {
322  TQString key = it.key();
323  if ( key.find(prefix)==0 ) {
324  TQString name = key.right(key.length()-prefix.length());
325  if ( name!="name" || !isNameUsed(it.data()) )
326  internal->hsConfig().writeEntry(_id+1, name, it.data());
327  }
328  }
329  }
330 #else
331  _newPlayer = !_oldLocalPlayer;
332  if (_oldLocalPlayer) _id = _oldLocalId;
333  else {
334  _id = nbEntries();
335  cg.config()->writeEntry(HS_ID, _id);
336  item("name")->write(_id, name);
337  }
338 #endif
339  _bound = true;
340  internal->hsConfig().writeAndUnlock();
341 }
342 
343 void PlayerInfos::createHistoItems(const TQMemArray<uint> &scores, bool bound)
344 {
345  Q_ASSERT( _histogram.size()==0 );
346  _bound = bound;
347  _histogram = scores;
348  for (uint i=1; i<histoSize(); i++)
349  addItem(histoName(i), new Item((uint)0), true, true);
350 }
351 
352 bool PlayerInfos::isAnonymous() const
353 {
354  return ( name()==ItemContainer::ANONYMOUS );
355 }
356 
357 uint PlayerInfos::nbEntries() const
358 {
359  internal->hsConfig().setHighscoreGroup("players");
360  TQStringList list = internal->hsConfig().readList("name", -1);
361  return list.count();
362 }
363 
364 TQString PlayerInfos::key() const
365 {
366  ConfigGroup cg;
367  return cg.config()->readEntry(HS_KEY, TQString());
368 }
369 
370 bool PlayerInfos::isWWEnabled() const
371 {
372  ConfigGroup cg;
373  return cg.config()->readBoolEntry(HS_WW_ENABLED, false);
374 }
375 
376 TQString PlayerInfos::histoName(uint i) const
377 {
378  const TQMemArray<uint> &sh = _histogram;
379  Q_ASSERT( i<sh.size() || (_bound || i==sh.size()) );
380  if ( i==sh.size() )
381  return TQString("nb scores greater than %1").arg(sh[sh.size()-1]);
382  return TQString("nb scores less than %1").arg(sh[i]);
383 }
384 
385 uint PlayerInfos::histoSize() const
386 {
387  return _histogram.size() + (_bound ? 0 : 1);
388 }
389 
390 void PlayerInfos::submitScore(const Score &score) const
391 {
392  // update counts
393  uint nbGames = item("nb games")->increment(_id);
394  switch (score.type()) {
395  case Lost:
396  item("nb lost games")->increment(_id);
397  break;
398  case Won: break;
399  case Draw:
400  item("nb draw games")->increment(_id);
401  break;
402  };
403 
404  // update mean
405  if ( score.type()==Won ) {
406  uint nbWonGames = nbGames - item("nb lost games")->read(_id).toUInt()
407  - item("nb draw games")->read(_id).toUInt()
408  - item("nb black marks")->read(_id).toUInt(); // legacy
409  double mean = (nbWonGames==1 ? 0.0
410  : item("mean score")->read(_id).toDouble());
411  mean += (double(score.score()) - mean) / nbWonGames;
412  item("mean score")->write(_id, mean);
413  }
414 
415  // update best score
416  Score best = score; // copy optionnal fields (there are not taken into account here)
417  best.setScore( item("best score")->read(_id).toUInt() );
418  if ( best<score ) {
419  item("best score")->write(_id, score.score());
420  item("date")->write(_id, score.data("date").toDateTime());
421  }
422 
423  // update trends
424  int current = item("current trend")->read(_id).toInt();
425  switch (score.type()) {
426  case Won: {
427  if ( current<0 ) current = 0;
428  current++;
429  uint won = item("max won trend")->read(_id).toUInt();
430  if ( (uint)current>won ) item("max won trend")->write(_id, current);
431  break;
432  }
433  case Lost: {
434  if ( current>0 ) current = 0;
435  current--;
436  uint lost = item("max lost trend")->read(_id).toUInt();
437  uint clost = -current;
438  if ( clost>lost ) item("max lost trend")->write(_id, clost);
439  break;
440  }
441  case Draw:
442  current = 0;
443  break;
444  }
445  item("current trend")->write(_id, current);
446 
447  // update histogram
448  if ( score.type()==Won ) {
449  const TQMemArray<uint> &sh = _histogram;
450  for (uint i=1; i<histoSize(); i++)
451  if ( i==sh.size() || score.score()<sh[i] ) {
452  item(histoName(i))->increment(_id);
453  break;
454  }
455  }
456 }
457 
458 bool PlayerInfos::isNameUsed(const TQString &newName) const
459 {
460  if ( newName==name() ) return false; // own name...
461  for (uint i=0; i<nbEntries(); i++)
462  if ( newName.lower()==item("name")->read(i).toString().lower() ) return true;
463  if ( newName==i18n(ItemContainer::ANONYMOUS_LABEL) ) return true;
464  return false;
465 }
466 
467 void PlayerInfos::modifyName(const TQString &newName) const
468 {
469  item("name")->write(_id, newName);
470 }
471 
472 void PlayerInfos::modifySettings(const TQString &newName,
473  const TQString &comment, bool WWEnabled,
474  const TQString &newKey) const
475 {
476  modifyName(newName);
477  item("comment")->write(_id, comment);
478  ConfigGroup cg;
479  cg.config()->writeEntry(HS_WW_ENABLED, WWEnabled);
480  if ( !newKey.isEmpty() ) cg.config()->writeEntry(HS_KEY, newKey);
481  if (WWEnabled) cg.config()->writeEntry(HS_REGISTERED_NAME, newName);
482 }
483 
484 TQString PlayerInfos::registeredName() const
485 {
486  ConfigGroup cg;
487  return cg.config()->readEntry(HS_REGISTERED_NAME, TQString());
488 }
489 
490 void PlayerInfos::removeKey()
491 {
492  ConfigGroup cg;
493 
494  // save old key/nickname
495  uint i = 0;
496  TQString str = "%1 old #%2";
497  TQString sk;
498  do {
499  i++;
500  sk = str.arg(HS_KEY).arg(i);
501  } while ( !cg.config()->readEntry(sk, TQString()).isEmpty() );
502  cg.config()->writeEntry(sk, key());
503  cg.config()->writeEntry(str.arg(HS_REGISTERED_NAME).arg(i),
504  registeredName());
505 
506  // clear current key/nickname
507  cg.config()->deleteEntry(HS_KEY);
508  cg.config()->deleteEntry(HS_REGISTERED_NAME);
509  cg.config()->writeEntry(HS_WW_ENABLED, false);
510 }
511 
512 //-----------------------------------------------------------------------------
513 ManagerPrivate::ManagerPrivate(uint nbGameTypes, Manager &m)
514  : manager(m), showStatistics(false), showDrawGames(false),
515  trackLostGames(false), trackDrawGames(false),
516  showMode(Manager::ShowForHigherScore),
517  _first(true), _nbGameTypes(nbGameTypes), _gameType(0)
518 {}
519 
520 void ManagerPrivate::init(uint maxNbEntries)
521 {
522  _hsConfig = new KHighscore(false, 0);
523  _playerInfos = new PlayerInfos;
524  _scoreInfos = new ScoreInfos(maxNbEntries, *_playerInfos);
525 }
526 
527 ManagerPrivate::~ManagerPrivate()
528 {
529  delete _scoreInfos;
530  delete _playerInfos;
531  delete _hsConfig;
532 }
533 
534 KURL ManagerPrivate::queryURL(QueryType type, const TQString &newName) const
535 {
536  KURL url = serverURL;
537  TQString nameItem = "nickname";
538  TQString name = _playerInfos->registeredName();
539  bool withVersion = true;
540  bool key = false;
541  bool level = false;
542 
543  switch (type) {
544  case Submit:
545  url.addPath("submit.php");
546  level = true;
547  key = true;
548  break;
549  case Register:
550  url.addPath("register.php");
551  name = newName;
552  break;
553  case Change:
554  url.addPath("change.php");
555  key = true;
556  if ( newName!=name )
557  Manager::addToQueryURL(url, "new_nickname", newName);
558  break;
559  case Players:
560  url.addPath("players.php");
561  nameItem = "highlight";
562  withVersion = false;
563  break;
564  case Scores:
565  url.addPath("highscores.php");
566  withVersion = false;
567  if ( _nbGameTypes>1 ) level = true;
568  break;
569  }
570 
571  if (withVersion) Manager::addToQueryURL(url, "version", version);
572  if ( !name.isEmpty() ) Manager::addToQueryURL(url, nameItem, name);
573  if (key) Manager::addToQueryURL(url, "key", _playerInfos->key());
574  if (level) {
575  TQString label = manager.gameTypeLabel(_gameType, Manager::WW);
576  if ( !label.isEmpty() ) Manager::addToQueryURL(url, "level", label);
577  }
578 
579  return url;
580 }
581 
582 // strings that needs to be translated (coming from the highscores server)
583 const char *DUMMY_STRINGS[] = {
584  I18N_NOOP("Undefined error."),
585  I18N_NOOP("Missing argument(s)."),
586  I18N_NOOP("Invalid argument(s)."),
587 
588  I18N_NOOP("Unable to connect to MySQL server."),
589  I18N_NOOP("Unable to select database."),
590  I18N_NOOP("Error on database query."),
591  I18N_NOOP("Error on database insert."),
592 
593  I18N_NOOP("Nickname already registered."),
594  I18N_NOOP("Nickname not registered."),
595  I18N_NOOP("Invalid key."),
596  I18N_NOOP("Invalid submit key."),
597 
598  I18N_NOOP("Invalid level."),
599  I18N_NOOP("Invalid score.")
600 };
601 
602 const char *UNABLE_TO_CONTACT =
603  I18N_NOOP("Unable to contact world-wide highscore server");
604 
605 bool ManagerPrivate::doQuery(const KURL &url, TQWidget *parent,
606  TQDomNamedNodeMap *map)
607 {
608  TDEIO::http_update_cache(url, true, 0); // remove cache !
609 
610  TQString tmpFile;
611  if ( !TDEIO::NetAccess::download(url, tmpFile, parent) ) {
612  TQString details = i18n("Server URL: %1").arg(url.host());
613  KMessageBox::detailedSorry(parent, i18n(UNABLE_TO_CONTACT), details);
614  return false;
615  }
616 
617  TQFile file(tmpFile);
618  if ( !file.open(IO_ReadOnly) ) {
619  TDEIO::NetAccess::removeTempFile(tmpFile);
620  TQString details = i18n("Unable to open temporary file.");
621  KMessageBox::detailedSorry(parent, i18n(UNABLE_TO_CONTACT), details);
622  return false;
623  }
624 
625  TQTextStream t(&file);
626  TQString content = t.read().stripWhiteSpace();
627  file.close();
628  TDEIO::NetAccess::removeTempFile(tmpFile);
629 
630  TQDomDocument doc;
631  if ( doc.setContent(content) ) {
632  TQDomElement root = doc.documentElement();
633  TQDomElement element = root.firstChild().toElement();
634  if ( element.tagName()=="success" ) {
635  if (map) *map = element.attributes();
636  return true;
637  }
638  if ( element.tagName()=="error" ) {
639  TQDomAttr attr = element.attributes().namedItem("label").toAttr();
640  if ( !attr.isNull() ) {
641  TQString msg = i18n(attr.value().latin1());
642  TQString caption = i18n("Message from world-wide highscores "
643  "server");
644  KMessageBox::sorry(parent, msg, caption);
645  return false;
646  }
647  }
648  }
649  TQString msg = i18n("Invalid answer from world-wide highscores server.");
650  TQString details = i18n("Raw message: %1").arg(content);
651  KMessageBox::detailedSorry(parent, msg, details);
652  return false;
653 }
654 
655 bool ManagerPrivate::getFromQuery(const TQDomNamedNodeMap &map,
656  const TQString &name, TQString &value,
657  TQWidget *parent)
658 {
659  TQDomAttr attr = map.namedItem(name).toAttr();
660  if ( attr.isNull() ) {
661  KMessageBox::sorry(parent,
662  i18n("Invalid answer from world-wide "
663  "highscores server (missing item: %1).").arg(name));
664  return false;
665  }
666  value = attr.value();
667  return true;
668 }
669 
670 Score ManagerPrivate::readScore(uint i) const
671 {
672  Score score(Won);
673  _scoreInfos->read(i, score);
674  return score;
675 }
676 
677 int ManagerPrivate::rank(const Score &score) const
678 {
679  uint nb = _scoreInfos->nbEntries();
680  uint i = 0;
681  for (; i<nb; i++)
682  if ( readScore(i)<score ) break;
683  return (i<_scoreInfos->maxNbEntries() ? (int)i : -1);
684 }
685 
686 bool ManagerPrivate::modifySettings(const TQString &newName,
687  const TQString &comment, bool WWEnabled,
688  TQWidget *widget)
689 {
690  TQString newKey;
691  bool newPlayer = false;
692 
693  if (WWEnabled) {
694  newPlayer = _playerInfos->key().isEmpty()
695  || _playerInfos->registeredName().isEmpty();
696  KURL url = queryURL((newPlayer ? Register : Change), newName);
697  Manager::addToQueryURL(url, "comment", comment);
698 
699  TQDomNamedNodeMap map;
700  bool ok = doQuery(url, widget, &map);
701  if ( !ok || (newPlayer && !getFromQuery(map, "key", newKey, widget)) )
702  return false;
703  }
704 
705  bool ok = _hsConfig->lockForWriting(widget); // no GUI when locking
706  if (ok) {
707  // check again name in case the config file has been changed...
708  // if it has, it is unfortunate because the WWW name is already
709  // committed but should be very rare and not really problematic
710  ok = ( !_playerInfos->isNameUsed(newName) );
711  if (ok)
712  _playerInfos->modifySettings(newName, comment, WWEnabled, newKey);
713  _hsConfig->writeAndUnlock();
714  }
715  return ok;
716 }
717 
718 void ManagerPrivate::convertToGlobal()
719 {
720  // read old highscores
721  KHighscore *tmp = _hsConfig;
722  _hsConfig = new KHighscore(true, 0);
723  TQValueVector<Score> scores(_scoreInfos->nbEntries());
724  for (uint i=0; i<scores.count(); i++)
725  scores[i] = readScore(i);
726 
727  // commit them
728  delete _hsConfig;
729  _hsConfig = tmp;
730  _hsConfig->lockForWriting();
731  for (uint i=0; i<scores.count(); i++)
732  if ( scores[i].data("id").toUInt()==_playerInfos->oldLocalId()+1 )
733  submitLocal(scores[i]);
734  _hsConfig->writeAndUnlock();
735 }
736 
737 void ManagerPrivate::setGameType(uint type)
738 {
739  if (_first) {
740  _first = false;
741  if ( _playerInfos->isNewPlayer() ) {
742  // convert legacy highscores
743  for (uint i=0; i<_nbGameTypes; i++) {
744  setGameType(i);
745  manager.convertLegacy(i);
746  }
747 
748 #ifdef HIGHSCORE_DIRECTORY
749  if ( _playerInfos->isOldLocalPlayer() ) {
750  // convert local to global highscores
751  for (uint i=0; i<_nbGameTypes; i++) {
752  setGameType(i);
753  convertToGlobal();
754  }
755  }
756 #endif
757  }
758  }
759 
760  Q_ASSERT( type<_nbGameTypes );
761  _gameType = kMin(type, _nbGameTypes-1);
762  TQString str = "scores";
763  TQString lab = manager.gameTypeLabel(_gameType, Manager::Standard);
764  if ( !lab.isEmpty() ) {
765  _playerInfos->setSubGroup(lab);
766  str += "_" + lab;
767  }
768  _scoreInfos->setGroup(str);
769 }
770 
771 void ManagerPrivate::checkFirst()
772 {
773  if (_first) setGameType(0);
774 }
775 
776 int ManagerPrivate::submitScore(const Score &ascore,
777  TQWidget *widget, bool askIfAnonymous)
778 {
779  checkFirst();
780 
781  Score score = ascore;
782  score.setData("id", _playerInfos->id() + 1);
783  score.setData("date", TQDateTime::currentDateTime());
784 
785  // ask new name if anonymous and winner
786  const char *dontAskAgainName = "highscore_ask_name_dialog";
787  TQString newName;
788  KMessageBox::ButtonCode dummy;
789  if ( score.type()==Won && askIfAnonymous && _playerInfos->isAnonymous()
790  && KMessageBox::shouldBeShownYesNo(dontAskAgainName, dummy) ) {
791  AskNameDialog d(widget);
792  if ( d.exec()==TQDialog::Accepted ) newName = d.name();
793  if ( d.dontAskAgain() )
794  KMessageBox::saveDontShowAgainYesNo(dontAskAgainName,
795  KMessageBox::No);
796  }
797 
798  int rank = -1;
799  if ( _hsConfig->lockForWriting(widget) ) { // no GUI when locking
800  // check again new name in case the config file has been changed...
801  if ( !newName.isEmpty() && !_playerInfos->isNameUsed(newName) )
802  _playerInfos->modifyName(newName);
803 
804  // commit locally
805  _playerInfos->submitScore(score);
806  if ( score.type()==Won ) rank = submitLocal(score);
807  _hsConfig->writeAndUnlock();
808  }
809 
810  if ( _playerInfos->isWWEnabled() )
811  submitWorldWide(score, widget);
812 
813  return rank;
814 }
815 
816 int ManagerPrivate::submitLocal(const Score &score)
817 {
818  int r = rank(score);
819  if ( r!=-1 ) {
820  uint nb = _scoreInfos->nbEntries();
821  if ( nb<_scoreInfos->maxNbEntries() ) nb++;
822  _scoreInfos->write(r, score, nb);
823  }
824  return r;
825 }
826 
827 bool ManagerPrivate::submitWorldWide(const Score &score,
828  TQWidget *widget) const
829 {
830  if ( score.type()==Lost && !trackLostGames ) return true;
831  if ( score.type()==Draw && !trackDrawGames ) return true;
832 
833  KURL url = queryURL(Submit);
834  manager.additionalQueryItems(url, score);
835  int s = (score.type()==Won ? score.score() : (int)score.type());
836  TQString str = TQString::number(s);
837  Manager::addToQueryURL(url, "score", str);
838  KMD5 context(TQString(_playerInfos->registeredName() + str).latin1());
839  Manager::addToQueryURL(url, "check", context.hexDigest());
840 
841  return doQuery(url, widget);
842 }
843 
844 void ManagerPrivate::exportHighscores(TQTextStream &s)
845 {
846  uint tmp = _gameType;
847 
848  for (uint i=0; i<_nbGameTypes; i++) {
849  setGameType(i);
850  if ( _nbGameTypes>1 ) {
851  if ( i!=0 ) s << endl;
852  s << "--------------------------------" << endl;
853  s << "Game type: "
854  << manager.gameTypeLabel(_gameType, Manager::I18N)
855  << endl;
856  s << endl;
857  }
858  s << "Players list:" << endl;
859  _playerInfos->exportToText(s);
860  s << endl;
861  s << "Highscores list:" << endl;
862  _scoreInfos->exportToText(s);
863  }
864 
865  setGameType(tmp);
866 }
867 
868 } // namespace
KHighscore
Class for managing highscore tables.
Definition: khighscore.h:85
KHighscore::lockForWriting
bool lockForWriting(TQWidget *widget=0)
Definition: khighscore.cpp:114

libtdegames

Skip menu "libtdegames"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

libtdegames

Skip menu "libtdegames"
  • libtdegames
Generated for libtdegames by doxygen 1.9.1
This website is maintained by Timothy Pearson.