File indexing completed on 2024-03-24 04:05:10
0001 /*************************************************************************** 0002 * Copyright (C) 2005-2007 by Albert Astals Cid <aacid@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU General Public License as published by * 0006 * the Free Software Foundation; either version 2 of the License, or * 0007 * (at your option) any later version. * 0008 ***************************************************************************/ 0009 0010 #include "kiriki.h" 0011 0012 #include <stdlib.h> 0013 0014 #include <QHBoxLayout> 0015 #include <QHeaderView> 0016 #include <QItemSelectionModel> 0017 #include <QPainter> 0018 #include <QPointer> 0019 #include <QPrintDialog> 0020 #include <QPrinter> 0021 #include <QStyledItemDelegate> 0022 #include <QTimer> 0023 #include <QTreeView> 0024 #include <QDateTime> 0025 0026 #include <QApplication> 0027 #include <KConfigDialog> 0028 #include <KLocalizedString> 0029 #include <KMessageBox> 0030 #include <KGameHighScoreDialog> 0031 #include <KStandardAction> 0032 #include <KGameStandardAction> 0033 #include <KActionCollection> 0034 #include <QAction> 0035 #include <QStatusBar> 0036 #include <KToggleAction> 0037 #include "computer.h" 0038 #include "configwidget.h" 0039 #include "lateralwidget.h" 0040 #include "scores.h" 0041 #include "settings.h" 0042 #include "itemdelegate.h" 0043 0044 kiriki::kiriki() : KXmlGuiWindow(), m_hintGiven(false) 0045 { 0046 QWidget *w = new QWidget(this); 0047 QHBoxLayout *lay = new QHBoxLayout(w); 0048 0049 m_lateral = new lateralWidget(w); 0050 lay -> addWidget(m_lateral); 0051 0052 m_scoresWidget = new QTreeView(w); 0053 0054 m_delegateHighlighted = new QStyledItemDelegate(m_scoresWidget); 0055 0056 if (kirikiSettings::fontSize() > kirikiSettings::rowHeight()) 0057 { 0058 kirikiSettings::setRowHeight(kirikiSettings::fontSize()); 0059 } 0060 0061 m_itemDelegate = new itemDelegate(kirikiSettings::rowHeight(), m_scoresWidget); 0062 0063 m_scoresWidget -> setItemDelegate(m_itemDelegate); 0064 m_scoresWidget -> setSelectionBehavior(QAbstractItemView::SelectRows); 0065 m_scoresWidget -> setRootIsDecorated(false); 0066 m_scoresWidget -> header() -> setSectionResizeMode(QHeaderView::Stretch); 0067 m_scoresWidget -> header() -> setSectionsMovable(false); 0068 m_scoresWidget -> header() -> setStretchLastSection(false); 0069 m_scoresWidget -> header() -> hide(); 0070 m_scoresWidget -> setItemsExpandable(false); 0071 0072 // set minimum section size so that you don't get ... when making the widget small 0073 QFont f = m_scoresWidget -> font(); 0074 f.setBold(true); 0075 f.setPointSize(f.pointSize() + 5); 0076 QFontMetrics fm(f); 0077 m_scoresWidget -> header() -> setMinimumSectionSize(fm.boundingRect(QStringLiteral("9999")).width()); 0078 0079 connect(m_scoresWidget, &QTreeView::pressed, this, &kiriki::pressed); 0080 lay -> addWidget(m_scoresWidget, 1); 0081 0082 m_scores = nullptr; 0083 0084 // Game 0085 QAction *gameNewAction = KGameStandardAction::gameNew(this, &kiriki::newGame, actionCollection()); 0086 KGameStandardAction::highscores(this, &kiriki::showHighScores, actionCollection()); 0087 KGameStandardAction::print(this, &kiriki::print, actionCollection()); 0088 KGameStandardAction::quit(qApp, &QApplication::quit, actionCollection()); 0089 m_hintAction = KGameStandardAction::hint(this, &kiriki::showHint, actionCollection()); 0090 m_demoAction = KGameStandardAction::demo(this, &kiriki::demo, actionCollection()); 0091 connect(gameNewAction, &QAction::triggered, m_demoAction, &KToggleAction::setChecked); 0092 connect(gameNewAction, &QAction::triggered, m_demoAction, &KToggleAction::setDisabled); 0093 connect(gameNewAction, &QAction::triggered, m_hintAction, &QAction::setDisabled); 0094 connect(gameNewAction, &QAction::triggered, m_lateral, &lateralWidget::disableDemoMode); 0095 connect(gameNewAction, &QAction::triggered, m_lateral, &lateralWidget::unhighlightAllDice); 0096 connect(this, &kiriki::demoStarted, m_demoAction, &KToggleAction::setDisabled); 0097 connect(this, &kiriki::demoStarted, m_demoAction, &KToggleAction::setChecked); 0098 connect(this, &kiriki::demoStarted, m_hintAction, &QAction::setDisabled); 0099 connect(this, &kiriki::demoStarted, m_lateral, &lateralWidget::unhighlightAllDice); 0100 connect(m_lateral, &lateralWidget::newGameClicked, gameNewAction, &QAction::trigger); 0101 0102 // Preferences 0103 KStandardAction::preferences(this, &kiriki::showPreferences, actionCollection()); 0104 0105 setCentralWidget(w); 0106 setupGUI(Keys | Save | Create); 0107 show(); 0108 0109 if (kirikiSettings::startupDemoEnabled()) m_demoAction -> trigger(); 0110 else newGame(); 0111 } 0112 0113 void kiriki::pressed(const QModelIndex &index) 0114 { 0115 if (!m_scores -> currentPlayer().isHuman()) return; 0116 0117 if (index.column() == 0 || index.column() == m_scores -> currentPlayerNumber() + 1) play(index); 0118 0119 m_scoresWidget -> setItemDelegateForRow(m_highlightedRowIndex, nullptr); 0120 } 0121 0122 void kiriki::play(const QModelIndex &index) 0123 { 0124 play(m_scores->row(index.row()).scoreRow()); 0125 } 0126 0127 void kiriki::play(int scoreRow) 0128 { 0129 int score = -1; 0130 0131 if (scoreRow == 0) score = m_lateral -> getOnes(); 0132 else if (scoreRow == 1) score = m_lateral -> getTwos(); 0133 else if (scoreRow == 2) score = m_lateral -> getThrees(); 0134 else if (scoreRow == 3) score = m_lateral -> getFours(); 0135 else if (scoreRow == 4) score = m_lateral -> getFives(); 0136 else if (scoreRow == 5) score = m_lateral -> getSixs(); 0137 else if (scoreRow == 6) score = m_lateral -> getThreeOfAKind(); 0138 else if (scoreRow == 7) score = m_lateral -> getFourOfAKind(); 0139 else if (scoreRow == 8) score = m_lateral -> getFullHouse(); 0140 else if (scoreRow == 9) score = m_lateral -> getSStraight(); 0141 else if (scoreRow == 10) score = m_lateral -> getLStraight(); 0142 else if (scoreRow == 11) score = m_lateral -> getKiriki(); 0143 else if (scoreRow == 12) score = m_lateral -> totalSum(); 0144 else return; 0145 0146 Q_ASSERT(score != -1); 0147 int row = m_scores -> rowForScoreRow(scoreRow); 0148 if (m_scores -> setData(m_scores -> index(row, 0), score, Qt::EditRole)) nextTurn(); 0149 } 0150 0151 void kiriki::newGame() 0152 { 0153 delete m_scores; 0154 m_scores = new scores(); 0155 m_scores -> setParent(this); 0156 m_scoresWidget -> setModel(m_scores); 0157 m_lateral -> nextTurn(); 0158 0159 m_scoresWidget -> header() -> setSectionResizeMode(0, QHeaderView::Custom); 0160 m_scoresWidget -> resizeColumnToContents(0); 0161 statusBar()->hide(); 0162 if (m_demoAction -> isChecked()) playComputer(); 0163 connect(m_lateral, &lateralWidget::rolled, statusBar(), &QWidget::hide); 0164 } 0165 0166 void kiriki::demo() 0167 { 0168 if( 0169 m_scores && 0170 !m_scores -> allScores() && 0171 !m_scores -> currentPlayer().noScores() && 0172 KMessageBox::warningContinueCancel( 0173 this, 0174 i18n("Starting the demo will end the current game. Any progress will be lost. Do you want to continue?") 0175 ) == KMessageBox::Cancel 0176 ) 0177 { 0178 m_demoAction -> setChecked(false); 0179 return; 0180 } 0181 0182 bool preDemoHumans[6]; 0183 preDemoHumans[0] = kirikiSettings::player1IsHuman(); 0184 preDemoHumans[1] = kirikiSettings::player2IsHuman(); 0185 preDemoHumans[2] = kirikiSettings::player3IsHuman(); 0186 preDemoHumans[3] = kirikiSettings::player4IsHuman(); 0187 preDemoHumans[4] = kirikiSettings::player5IsHuman(); 0188 preDemoHumans[5] = kirikiSettings::player6IsHuman(); 0189 int preDemoNumPlayers = kirikiSettings::numberOfPlayers(); 0190 kirikiSettings::setPlayer1IsHuman(false); 0191 kirikiSettings::setPlayer2IsHuman(false); 0192 kirikiSettings::setPlayer3IsHuman(false); 0193 kirikiSettings::setPlayer4IsHuman(false); 0194 kirikiSettings::setPlayer5IsHuman(false); 0195 kirikiSettings::setPlayer6IsHuman(false); 0196 kirikiSettings::setNumberOfPlayers(6); 0197 newGame(); 0198 Q_EMIT demoStarted(); 0199 disconnect(m_lateral, &lateralWidget::rolled, statusBar(), &QWidget::hide); 0200 kirikiSettings::setPlayer1IsHuman(preDemoHumans[0]); 0201 kirikiSettings::setPlayer2IsHuman(preDemoHumans[1]); 0202 kirikiSettings::setPlayer3IsHuman(preDemoHumans[2]); 0203 kirikiSettings::setPlayer4IsHuman(preDemoHumans[3]); 0204 kirikiSettings::setPlayer5IsHuman(preDemoHumans[4]); 0205 kirikiSettings::setPlayer6IsHuman(preDemoHumans[5]); 0206 kirikiSettings::setNumberOfPlayers(preDemoNumPlayers); 0207 statusBar()->showMessage(i18n("Demonstration. Press \"New\" to start a new game.")); 0208 statusBar()->show(); 0209 m_lateral->enableDemoMode(); 0210 } 0211 0212 void kiriki::showHint() 0213 { 0214 if (!m_hintGiven && KMessageBox::Cancel == KMessageBox::warningContinueCancel( 0215 this, 0216 i18n("Asking for a hint will disqualify the current game from entering the high score list."), 0217 i18n("Confirm Hint Request"), 0218 KGuiItem(i18n("Give Hint Anyway"), QStringLiteral("arrow-right")) 0219 ) 0220 ) return; 0221 m_hintGiven = true; 0222 0223 for (int i = 0; i < 5; ++i) setComputerDiceValue(i, m_lateral -> getDice(i)); 0224 ComputerRolling(m_scores -> currentPlayer(), m_lateral -> getRolls()); 0225 if (computerDiceSelected() && m_lateral -> getRolls() < 3) 0226 { 0227 int rollAmount = 0; 0228 for (int i = 0; i < 5; ++i) 0229 { 0230 if (getComputerDiceSelected(i)) 0231 { 0232 ++rollAmount; 0233 m_lateral -> highlightDice(i, true); 0234 } 0235 } 0236 m_scoresWidget->selectionModel()->clearSelection(); 0237 statusBar()->showMessage(i18np("Roll highlighted die.", "Roll highlighted dice.", rollAmount)); 0238 statusBar()->show(); 0239 } 0240 else 0241 { 0242 static const int scoreRows[13] = { 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16 }; 0243 QModelIndex mi; 0244 mi = m_scores -> index(scoreRows[ComputerScoring(m_scores -> currentPlayer())], 0); 0245 m_highlightedRowIndex = mi.row(); 0246 m_scoresWidget -> setItemDelegateForRow(m_highlightedRowIndex, m_delegateHighlighted); 0247 QItemSelectionModel::SelectionFlags fl = QItemSelectionModel::Clear | 0248 QItemSelectionModel::Rows | 0249 QItemSelectionModel::Select; 0250 m_scoresWidget -> selectionModel() -> select(mi, fl); 0251 } 0252 } 0253 0254 void kiriki::settingsChanged() 0255 { 0256 if (m_fontSize != kirikiSettings::fontSize()) 0257 { 0258 m_scoresWidget -> resizeColumnToContents(0); 0259 m_scores->askForRedraw(); 0260 m_fontSize = kirikiSettings::fontSize(); 0261 } 0262 0263 if (m_rowHeight != kirikiSettings::rowHeight()) 0264 { 0265 m_rowHeight = kirikiSettings::rowHeight(); 0266 m_itemDelegate -> setHeight(m_rowHeight); 0267 m_scores -> askForRedraw(); 0268 } 0269 } 0270 0271 void kiriki::endGame() 0272 { 0273 const player &p = m_scores -> winner(); 0274 m_lateral -> setEnabled(false); 0275 m_lateral -> endGame(); 0276 m_hintAction -> setEnabled(false); 0277 if (p.isHuman()) 0278 { 0279 QPointer<KGameHighScoreDialog> sc = new KGameHighScoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Score | KGameHighScoreDialog::Date, this); 0280 if (m_hintGiven) m_hintGiven = false; 0281 else 0282 { 0283 KGameHighScoreDialog::FieldInfo scoreInfo; 0284 scoreInfo[KGameHighScoreDialog::Score].setNum(p.grandTotal()); 0285 const QDate date = QDate::currentDate(); 0286 QLocale l; 0287 const QString datestring = l.toString(date, QLocale::ShortFormat); 0288 scoreInfo[KGameHighScoreDialog::Date] = datestring; 0289 0290 if (sc->addScore(scoreInfo)) 0291 { 0292 sc->exec(); 0293 } 0294 } 0295 delete sc; 0296 } 0297 if (m_demoAction -> isChecked()) QTimer::singleShot(3000, this, &kiriki::demo); 0298 } 0299 0300 void kiriki::showHighScores() 0301 { 0302 KGameHighScoreDialog sc(KGameHighScoreDialog::Name | KGameHighScoreDialog::Score | KGameHighScoreDialog::Date, this); 0303 sc.exec(); 0304 } 0305 0306 void kiriki::showPreferences() 0307 { 0308 if(KConfigDialog::showDialog(QStringLiteral("settings"))) 0309 return; 0310 0311 int nPlayers = kirikiSettings::numberOfPlayers(); 0312 QString player1Name = kirikiSettings::player1Name(); 0313 QString player2Name = kirikiSettings::player2Name(); 0314 QString player3Name = kirikiSettings::player3Name(); 0315 QString player4Name = kirikiSettings::player4Name(); 0316 QString player5Name = kirikiSettings::player5Name(); 0317 QString player6Name = kirikiSettings::player6Name(); 0318 bool player2IsHuman = kirikiSettings::player2IsHuman(); 0319 bool player3IsHuman = kirikiSettings::player3IsHuman(); 0320 bool player4IsHuman = kirikiSettings::player4IsHuman(); 0321 bool player5IsHuman = kirikiSettings::player5IsHuman(); 0322 bool player6IsHuman = kirikiSettings::player6IsHuman(); 0323 m_fontSize = kirikiSettings::fontSize(); 0324 m_rowHeight = kirikiSettings::rowHeight(); 0325 0326 QPointer<KConfigDialog> configDialog = new KConfigDialog(this, QStringLiteral("settings"), kirikiSettings::self()); 0327 configDialog->setFaceType(KConfigDialog::Plain); 0328 configDialog->addPage(new configWidget(configDialog), QString(), QString()); 0329 connect(configDialog.data(), &KConfigDialog::settingsChanged, this, &kiriki::settingsChanged); 0330 configDialog->exec(); 0331 delete configDialog; 0332 0333 bool changed = nPlayers != kirikiSettings::numberOfPlayers() || 0334 player1Name != kirikiSettings::player1Name() || 0335 player2Name != kirikiSettings::player2Name() || 0336 player3Name != kirikiSettings::player3Name() || 0337 player4Name != kirikiSettings::player4Name() || 0338 player5Name != kirikiSettings::player5Name() || 0339 player6Name != kirikiSettings::player6Name() || 0340 player2IsHuman != kirikiSettings::player2IsHuman() || 0341 player3IsHuman != kirikiSettings::player3IsHuman() || 0342 player4IsHuman != kirikiSettings::player4IsHuman() || 0343 player5IsHuman != kirikiSettings::player5IsHuman() || 0344 player6IsHuman != kirikiSettings::player6IsHuman(); 0345 if (changed) 0346 { 0347 KMessageBox::information(this, i18n("Changes will be applied on next game.")); 0348 } 0349 } 0350 0351 void kiriki::print() 0352 { 0353 QPrinter printer; 0354 printer.setFullPage( true ); 0355 QPointer<QPrintDialog> printDialog = new QPrintDialog(&printer, this); 0356 if (printDialog->exec()) 0357 { 0358 QPainter painter(&printer); 0359 m_scores->print(painter, printer.width(), printer.height()); 0360 } 0361 delete printDialog; 0362 } 0363 0364 void kiriki::nextTurn() 0365 { 0366 if (m_scores -> allScores()) endGame(); 0367 else 0368 { 0369 m_scores -> nextPlayer(); 0370 0371 while (m_scores -> currentPlayer().allScores()) m_scores -> nextPlayer(); 0372 0373 m_lateral -> nextTurn(); 0374 if (!m_scores -> currentPlayer().isHuman()) 0375 { 0376 m_hintAction -> setEnabled(false); 0377 QTimer::singleShot(kirikiSettings::waitTime(), this, &kiriki::playComputer); 0378 } 0379 else 0380 { 0381 m_hintAction -> setEnabled(true); 0382 m_lateral -> setEnabled(true); 0383 } 0384 } 0385 } 0386 0387 void kiriki::playComputer() 0388 { 0389 if (!m_scores -> currentPlayer().isHuman()) 0390 { 0391 m_lateral -> setEnabled(false); 0392 for (int i = 0; i < 5; i++) setComputerDiceValue(i, m_lateral -> getDice(i)); 0393 ComputerRolling(m_scores -> currentPlayer(), m_lateral -> getRolls()); 0394 while (computerDiceSelected() && m_lateral -> getRolls() < 3) 0395 { 0396 for (int i = 0; i < 5; i++) m_lateral -> selectDice(i, getComputerDiceSelected(i)); 0397 m_lateral -> roll(); 0398 for (int i = 0; i < 5; i++) setComputerDiceValue(i, m_lateral -> getDice(i)); 0399 ComputerRolling(m_scores -> currentPlayer(), m_lateral -> getRolls()); 0400 } 0401 int row; 0402 row = ComputerScoring(m_scores -> currentPlayer()); 0403 play(row); 0404 } 0405 else m_lateral -> setEnabled(true); 0406 } 0407 0408 #include "moc_kiriki.cpp"