• 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
43namespace KExtHighscore
44{
45
46//-----------------------------------------------------------------------------
47const char ItemContainer::ANONYMOUS[] = "_";
48const char ItemContainer::ANONYMOUS_LABEL[] = I18N_NOOP("anonymous");
49
50ItemContainer::ItemContainer()
51 : _item(0)
52{}
53
54ItemContainer::~ItemContainer()
55{
56 delete _item;
57}
58
59void ItemContainer::setItem(Item *item)
60{
61 delete _item;
62 _item = item;
63}
64
65TQString ItemContainer::entryName() const
66{
67 if ( _subGroup.isEmpty() ) return _name;
68 return _name + "_" + _subGroup;
69}
70
71TQVariant 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
83TQString ItemContainer::pretty(uint i) const
84{
85 Q_ASSERT(_item);
86 return _item->pretty(i, read(i));
87}
88
89void 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
97uint ItemContainer::increment(uint i) const
98{
99 uint v = read(i).toUInt() + 1;
100 write(i, v);
101 return v;
102}
103
104//-----------------------------------------------------------------------------
105ItemArray::ItemArray()
106 : _group(""), _subGroup("") // no null groups
107{}
108
109ItemArray::~ItemArray()
110{
111 for (uint i=0; i<size(); i++) delete at(i);
112}
113
114int 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
121const 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
129ItemContainer *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
137void 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
147void 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
158void 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
167void 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
175void 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
183void 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
191void 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
200void 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//-----------------------------------------------------------------------------
216class 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//-----------------------------------------------------------------------------
234ScoreInfos::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
244uint 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//-----------------------------------------------------------------------------
254const char *HS_ID = "player id";
255const char *HS_REGISTERED_NAME = "registered name";
256const char *HS_KEY = "player key";
257const char *HS_WW_ENABLED = "ww hs enabled";
258
259PlayerInfos::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
343void 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
352bool PlayerInfos::isAnonymous() const
353{
354 return ( name()==ItemContainer::ANONYMOUS );
355}
356
357uint PlayerInfos::nbEntries() const
358{
359 internal->hsConfig().setHighscoreGroup("players");
360 TQStringList list = internal->hsConfig().readList("name", -1);
361 return list.count();
362}
363
364TQString PlayerInfos::key() const
365{
366 ConfigGroup cg;
367 return cg.config()->readEntry(HS_KEY, TQString());
368}
369
370bool PlayerInfos::isWWEnabled() const
371{
372 ConfigGroup cg;
373 return cg.config()->readBoolEntry(HS_WW_ENABLED, false);
374}
375
376TQString 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
385uint PlayerInfos::histoSize() const
386{
387 return _histogram.size() + (_bound ? 0 : 1);
388}
389
390void 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
458bool 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
467void PlayerInfos::modifyName(const TQString &newName) const
468{
469 item("name")->write(_id, newName);
470}
471
472void 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
484TQString PlayerInfos::registeredName() const
485{
486 ConfigGroup cg;
487 return cg.config()->readEntry(HS_REGISTERED_NAME, TQString());
488}
489
490void 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//-----------------------------------------------------------------------------
513ManagerPrivate::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
520void ManagerPrivate::init(uint maxNbEntries)
521{
522 _hsConfig = new KHighscore(false, 0);
523 _playerInfos = new PlayerInfos;
524 _scoreInfos = new ScoreInfos(maxNbEntries, *_playerInfos);
525}
526
527ManagerPrivate::~ManagerPrivate()
528{
529 delete _scoreInfos;
530 delete _playerInfos;
531 delete _hsConfig;
532}
533
534KURL 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)
583const 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
602const char *UNABLE_TO_CONTACT =
603 I18N_NOOP("Unable to contact world-wide highscore server");
604
605bool 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
655bool 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
670Score ManagerPrivate::readScore(uint i) const
671{
672 Score score(Won);
673 _scoreInfos->read(i, score);
674 return score;
675}
676
677int 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
686bool 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
718void 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
737void 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
771void ManagerPrivate::checkFirst()
772{
773 if (_first) setGameType(0);
774}
775
776int 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
816int 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
827bool 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
844void 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.4
This website is maintained by Timothy Pearson.