File indexing completed on 2024-04-21 04:01:59
0001 /* 0002 SPDX-FileCopyrightText: 1998 Andreas Wüst <AndreasWuest@gmx.de> 0003 SPDX-FileCopyrightText: 2006-2009 Dmitry Suzdalev <dimsuz@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "gamewidget.h" 0009 0010 #include "highscores.h" 0011 #include "playfield.h" 0012 #include "prefs.h" 0013 #include "katomic_debug.h" 0014 0015 #include <KMessageBox> 0016 #include <KLocalizedString> 0017 #include <KConfig> 0018 0019 #include <QGraphicsView> 0020 #include <QResizeEvent> 0021 #include <QApplication> // for qApp->quit() 0022 #include <QVBoxLayout> 0023 #include <QTimer> // Next Level after N seconds 0024 #include <QFileDialog> 0025 0026 GameWidget::GameWidget ( const QString& levelSet, QWidget *parent ) 0027 : QWidget( parent ), m_allowAnyLevelSwitch( false ), m_moves(0), m_level(0) 0028 { 0029 m_highscore = new KAtomicHighscores(); 0030 m_levelHighscore = 0; 0031 0032 QVBoxLayout *top = new QVBoxLayout(this); 0033 top->setContentsMargins(0, 0, 0, 0); 0034 0035 // playfield 0036 m_playField = new PlayField(this); 0037 0038 m_view = new QGraphicsView(m_playField, this); 0039 int defaultFieldSize = FIELD_SIZE*MIN_ELEM_SIZE; 0040 // reserve some room for molecule preview 0041 m_view->setMinimumSize( defaultFieldSize+defaultFieldSize/4, defaultFieldSize ); 0042 m_view->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 0043 m_view->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); 0044 m_view->setFrameStyle( QFrame::NoFrame ); 0045 m_view->setCacheMode( QGraphicsView::CacheBackground ); 0046 0047 // TODO uncomment DontSavePainterState optimization back after this bug in Qt 4.6 preview will be 0048 // fixed (darktears promised it will get fixed in 4.6.0 release). Bug is about wrong coordinates 0049 // for QPainter passed to QGS::drawForeground() function 0050 m_view->setOptimizationFlags( 0051 //QGraphicsView::DontSavePainterState | 0052 QGraphicsView::DontAdjustForAntialiasing ); 0053 0054 top->addWidget(m_view, 1); 0055 0056 connect(m_playField, &PlayField::gameOver, this, &GameWidget::gameOver); 0057 connect(m_playField, &PlayField::updateMoves, this, &GameWidget::updateMoves); 0058 0059 // Next level after some seconds after ending the game. See gameOver, nextLevel and prevLevel 0060 m_timer = new QTimer(this); 0061 m_timer->setSingleShot(true); 0062 connect(m_timer, &QTimer::timeout, this, &GameWidget::nextLevel); 0063 0064 setLevelSet(levelSet); 0065 } 0066 0067 GameWidget::~GameWidget() 0068 { 0069 delete m_highscore; 0070 } 0071 0072 0073 bool GameWidget::setLevelSet(const QString& levelSet) 0074 { 0075 if (m_levelSet.name() == levelSet) 0076 { 0077 //qCDebug(KATOMIC_LOG) << "level set named" << levelSet << "is already loaded"; 0078 return true; 0079 } 0080 0081 bool res = m_levelSet.load(levelSet); 0082 if (!res) 0083 { 0084 KMessageBox::error(this, i18n("Failed to load level set \"%1\". Check if it is installed on your computer.", levelSet)); 0085 //qCDebug(KATOMIC_LOG) << "failed to load levelset" << levelSet; 0086 return false; 0087 } 0088 0089 int lastPlayed = lastPlayedLevel(); 0090 int maxLevel = maxAccessibleLevel(); 0091 0092 int startingLevel = qMin(lastPlayed, maxLevel); 0093 switchToLevel(startingLevel); 0094 0095 return true; 0096 } 0097 0098 const LevelSet& GameWidget::levelSet() const 0099 { 0100 return m_levelSet; 0101 } 0102 0103 QString GameWidget::currentMolecule() const 0104 { 0105 return m_playField->moleculeName(); 0106 } 0107 0108 void GameWidget::moveUp() 0109 { 0110 if(!m_playField->isLevelFinished()) 0111 m_playField->moveSelectedAtom( PlayField::Up ); 0112 } 0113 0114 void GameWidget::moveDown() 0115 { 0116 if(!m_playField->isLevelFinished()) 0117 m_playField->moveSelectedAtom( PlayField::Down ); 0118 } 0119 0120 void GameWidget::moveLeft() 0121 { 0122 if(!m_playField->isLevelFinished()) 0123 m_playField->moveSelectedAtom( PlayField::Left ); 0124 } 0125 0126 void GameWidget::moveRight() 0127 { 0128 if(!m_playField->isLevelFinished()) 0129 m_playField->moveSelectedAtom( PlayField::Right ); 0130 } 0131 0132 void GameWidget::gameOver(int moves) { 0133 // writing this info only in normal mode 0134 if ( !m_allowAnyLevelSwitch && 0135 maxAccessibleLevel() < m_level+1 ) 0136 { 0137 saveMaxAccessibleLevel( m_level+1 ); 0138 } 0139 0140 QString message = i18n( "Level %1 finished. ", m_level ); 0141 0142 if( m_highscore->addScore( moves , m_levelSet.name(), m_level ) ) // new highscore! 0143 { 0144 message += i18n("Congratulations! You have a new highscore!" ); 0145 } 0146 0147 m_playField->showMessage( message ); 0148 Q_EMIT statsChanged(m_level, moves, m_highscore->levelHighscore(m_levelSet.name(), m_level)); 0149 if (!m_allowAnyLevelSwitch) 0150 { 0151 // reuse this signal to allow switching levels over toolbar 0152 Q_EMIT levelChanged(m_level); 0153 // after 4 seconds, nextLevel 0154 m_timer->start(4000); 0155 } 0156 } 0157 0158 void GameWidget::updateMoves(int moves) 0159 { 0160 m_moves = moves; 0161 Q_EMIT statsChanged(m_level, moves, m_levelHighscore); 0162 } 0163 0164 void GameWidget::switchToLevel (int l) 0165 { 0166 const LevelData* levelData = m_levelSet.levelData(l); 0167 if (levelData) 0168 { 0169 m_level=l; 0170 0171 m_playField->setLevelData(levelData); 0172 0173 m_levelHighscore = m_highscore->levelHighscore( m_levelSet.name(), m_level ); 0174 0175 Q_EMIT statsChanged(m_level, 0, m_levelHighscore); 0176 Q_EMIT levelChanged(m_level); 0177 0178 saveLastPlayedLevel(); 0179 } 0180 else { 0181 //qCDebug(KATOMIC_LOG) << "failed to load level" << l; 0182 } 0183 } 0184 0185 void GameWidget::restartLevel() 0186 { 0187 switchToLevel(m_level); 0188 } 0189 0190 void GameWidget::saveGame() 0191 { 0192 QString fileName = QFileDialog::getSaveFileName( this, QString(), QString(), QStringLiteral("*.katomic") ); 0193 if(fileName.isEmpty()) 0194 return; 0195 KConfig config(fileName, KConfig::SimpleConfig); 0196 KConfigGroup gr = config.group(QStringLiteral("Savegame")); 0197 gr.writeEntry( "Level", m_level ); 0198 gr.writeEntry( "LevelSet", m_levelSet.name() ); 0199 m_playField->saveGame( gr ); 0200 } 0201 0202 void GameWidget::loadGame() 0203 { 0204 QString fileName = QFileDialog::getOpenFileName( this, QString(), QString(), QStringLiteral("*.katomic") ); 0205 if(fileName.isEmpty()) 0206 return; 0207 KConfig config(fileName, KConfig::SimpleConfig); 0208 KConfigGroup gr = config.group(QStringLiteral("Savegame")); 0209 QString levelSet = gr.readEntry("LevelSet"); 0210 if (levelSet.isEmpty()) 0211 { 0212 //qCDebug(KATOMIC_LOG) << "note: savegame file doesn't contain info about levelset, assuming default one"; 0213 levelSet = QStringLiteral(DEFAULT_LEVELSET_NAME); 0214 } 0215 0216 bool res = setLevelSet(levelSet); 0217 if (res) 0218 { 0219 int l = gr.readEntry( "Level", 1 ); 0220 switchToLevel(l); 0221 m_playField->loadGame( gr ); 0222 } 0223 } 0224 0225 void GameWidget::showHighscores () 0226 { 0227 // TODO: Implement me! Please... 8-) 0228 } 0229 0230 int GameWidget::currentHighScore() const 0231 { 0232 return m_levelHighscore; 0233 } 0234 0235 void GameWidget::prevLevel() 0236 { 0237 // if user hits toolbar buttons, stop timer 0238 if (m_timer->isActive()) 0239 m_timer->stop(); 0240 0241 if (isPrevLevelAvailable()) 0242 { 0243 switchToLevel(m_level-1); 0244 } 0245 } 0246 0247 void GameWidget::nextLevel() 0248 { 0249 // if user hits toolbar buttons, stop timer 0250 if (m_timer->isActive()) 0251 m_timer->stop(); 0252 0253 if (isNextLevelAvailable()) 0254 { 0255 switchToLevel(m_level+1); 0256 } 0257 } 0258 0259 void GameWidget::resizeEvent( QResizeEvent* ev) 0260 { 0261 m_playField->resize( ev->size().width(), ev->size().height() ); 0262 } 0263 0264 void GameWidget::saveLastPlayedLevel() 0265 { 0266 KSharedConfigPtr cfg = KSharedConfig::openConfig(); 0267 KConfigGroup grp(cfg, m_levelSet.name()); 0268 grp.writeEntry("LastPlayedLevel", m_level); 0269 0270 Preferences::setLastPlayedLevelSet(m_levelSet.name()); 0271 } 0272 0273 void GameWidget::saveMaxAccessibleLevel(int level) 0274 { 0275 KSharedConfigPtr cfg = KSharedConfig::openConfig(); 0276 KConfigGroup grp(cfg, m_levelSet.name()); 0277 grp.writeEntry("MaxAccessibleLevel", level); 0278 } 0279 0280 int GameWidget::lastPlayedLevel() const 0281 { 0282 KSharedConfigPtr cfg = KSharedConfig::openConfig(); 0283 KConfigGroup grp(cfg, m_levelSet.name()); 0284 int lastPlayed = grp.readEntry("LastPlayedLevel", 1); 0285 lastPlayed = qMax(1, lastPlayed); // can't be less than 1 0286 //qCDebug(KATOMIC_LOG) << "last played level:" << lastPlayed; 0287 return lastPlayed; 0288 } 0289 0290 int GameWidget::maxAccessibleLevel() const 0291 { 0292 KSharedConfigPtr cfg = KSharedConfig::openConfig(); 0293 KConfigGroup grp(cfg, m_levelSet.name()); 0294 int maxAccessible = grp.readEntry("MaxAccessibleLevel", 1); 0295 //qCDebug(KATOMIC_LOG) << "max accessible level:" << maxAccessible; 0296 return maxAccessible; 0297 } 0298 0299 bool GameWidget::isNextLevelAvailable() const 0300 { 0301 bool avail = m_allowAnyLevelSwitch ? true : 0302 (m_level != maxAccessibleLevel() && m_level <= m_levelSet.levelCount()); 0303 return avail; 0304 } 0305 0306 bool GameWidget::isPrevLevelAvailable() const 0307 { 0308 return m_level > 1; 0309 } 0310 0311 #include "moc_gamewidget.cpp"