File indexing completed on 2024-04-28 04:04:38

0001 /*
0002     This file is part of the game 'KTron'
0003 
0004     SPDX-FileCopyrightText: 1998-2000 Matthias Kiefer <matthias.kiefer@gmx.de>
0005     SPDX-FileCopyrightText: 2005 Benjamin C. Meyer <ben at meyerhome dot net>
0006     SPDX-FileCopyrightText: 2008-2009 Stas Verberkt <legolas at legolasweb dot nl>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 
0010 */
0011 
0012 #include "ktron.h"
0013 #include "renderer.h"
0014 #include "settings.h"
0015 #include "ui_general.h"
0016 
0017 #include <KGameDifficulty>
0018 #include <KGameHighScoreDialog>
0019 #include <KGameStandardAction>
0020 #include <KGameThemeSelector>
0021 
0022 #include <QApplication>
0023 #include <QStatusBar>
0024 
0025 #include <KActionCollection>
0026 #include <KConfigDialog>
0027 #include <KLocalizedString>
0028 #include <KMessageBox>
0029 #include <KShortcutsDialog>
0030 
0031 //UI
0032 class General : public QWidget, public Ui::General
0033 {
0034 public:
0035     explicit General(QWidget *parent = nullptr)
0036         : QWidget(parent)
0037         {
0038             setupUi(this);
0039         }
0040 };
0041 
0042 /**
0043  * Constructor
0044  */
0045 KTron::KTron(QWidget *parent) : KXmlGuiWindow(parent, Qt::WindowFlags()) {
0046     m_tron = new Tron(this);
0047     connect(m_tron, &Tron::gameEnds, this, &KTron::changeStatus);
0048     connect(m_tron, &Tron::updatedScore, this, &KTron::updateScore);
0049     connect(m_tron, &Tron::pauseBlocked, this, &KTron::blockPause);
0050     m_tron->setMinimumSize(700,420);
0051     setCentralWidget(m_tron);
0052 
0053     // create statusbar
0054     for (auto &label : m_statusBarLabel) {
0055         label = new QLabel(this);
0056         label->setAlignment(Qt::AlignCenter);
0057         statusBar()->addWidget(label, 1);
0058     }
0059 
0060     // We match up keyboard events ourselves in Tron::keyPressEvent()
0061     // We must disable the actions, otherwise we don't get the keyPressEvent's
0062 
0063     m_player0Up = actionCollection()->addAction( QStringLiteral( "Pl1Up" ));
0064     m_player0Up->setText(i18n("Right Player / KSnake mode: Up"));
0065     KActionCollection::setDefaultShortcut(m_player0Up, Qt::Key_Up);
0066     connect(m_player0Up, &QAction::triggered, this, &KTron::triggerKey0Up);
0067     addAction(m_player0Up);
0068 
0069     m_player0Down = actionCollection()->addAction( QStringLiteral( "Pl1Down" ));
0070     m_player0Down->setText(i18n("Right Player / KSnake mode: Down"));
0071     KActionCollection::setDefaultShortcut(m_player0Down, Qt::Key_Down);
0072     connect(m_player0Down, &QAction::triggered, this, &KTron::triggerKey0Down);
0073     addAction(m_player0Down);
0074 
0075     m_player0Right = actionCollection()->addAction( QStringLiteral( "Pl1Right" ));
0076     m_player0Right->setText(i18n("Right Player / KSnake mode: Right"));
0077     KActionCollection::setDefaultShortcut(m_player0Right, Qt::Key_Right);
0078     connect(m_player0Right, &QAction::triggered, this, &KTron::triggerKey0Right);
0079     addAction(m_player0Right);
0080 
0081     m_player0Left = actionCollection()->addAction( QStringLiteral( "Pl1Left" ));
0082     m_player0Left->setText(i18n("Right Player / KSnake mode: Left"));
0083     KActionCollection::setDefaultShortcut(m_player0Left, Qt::Key_Left);
0084     connect(m_player0Left, &QAction::triggered, this, &KTron::triggerKey0Left);
0085     addAction(m_player0Left);
0086 
0087     m_player0Accelerate = actionCollection()->addAction( QStringLiteral( "Pl1Ac" ));
0088     m_player0Accelerate->setText(i18n("Right Player: Accelerator"));
0089     KActionCollection::setDefaultShortcut(m_player0Accelerate, Qt::Key_0);
0090     m_player0Accelerate->setEnabled(false); // Alternate handling, because of up/down events
0091     addAction(m_player0Accelerate);
0092 
0093     m_player1Up = actionCollection()->addAction( QStringLiteral( "Pl2Up" ));
0094     m_player1Up->setText(i18n("Left Player: Up"));
0095     KActionCollection::setDefaultShortcut(m_player1Up, Qt::Key_W);
0096     connect(m_player1Up, &QAction::triggered, this, &KTron::triggerKey1Up);
0097     addAction(m_player1Up);
0098 
0099     m_player1Down = actionCollection()->addAction( QStringLiteral( "Pl2Down" ));
0100     m_player1Down->setText(i18n("Left Player: Down"));
0101     KActionCollection::setDefaultShortcut(m_player1Down, Qt::Key_S);
0102     connect(m_player1Down, &QAction::triggered, this, &KTron::triggerKey1Down);
0103     addAction(m_player1Down);
0104 
0105     m_player1Right = actionCollection()->addAction( QStringLiteral( "Pl2Right" ));;
0106     m_player1Right->setText(i18n("Left Player: Right"));
0107     KActionCollection::setDefaultShortcut(m_player1Right, Qt::Key_D);
0108     connect(m_player1Right, &QAction::triggered, this, &KTron::triggerKey1Right);
0109     addAction(m_player1Right);
0110 
0111     m_player1Left = actionCollection()->addAction( QStringLiteral( "Pl2Left" ));
0112     m_player1Left->setText(i18n("Left Player: Left"));
0113     KActionCollection::setDefaultShortcut(m_player1Left, Qt::Key_A);
0114     connect(m_player1Left, &QAction::triggered, this, &KTron::triggerKey1Left);
0115     addAction(m_player1Left);
0116 
0117     m_player1Accelerate = actionCollection()->addAction( QStringLiteral( "Pl2Ac" ));
0118     m_player1Accelerate->setText(i18n("Left Player: Accelerator"));
0119     KActionCollection::setDefaultShortcut(m_player1Accelerate, Qt::Key_Q);
0120     m_player1Accelerate->setEnabled(false); // Alternate handling, because of up/down events
0121     addAction(m_player1Accelerate);
0122 
0123     // Pause
0124     m_pauseButton = KGameStandardAction::pause(m_tron, &Tron::togglePause, actionCollection());
0125     m_pauseButton->setEnabled(false);
0126     // New
0127     KGameStandardAction::gameNew(m_tron, &Tron::newGame, actionCollection());
0128     // Quit
0129     KGameStandardAction::quit(qApp, &QApplication::quit, actionCollection());
0130     // Settings
0131     KStandardAction::preferences(this, &KTron::showSettings, actionCollection());
0132     // Configure keys
0133     KStandardAction::keyBindings(this, &KTron::optionsConfigureKeys, actionCollection());
0134     // Highscores
0135     KGameStandardAction::highscores(this, &KTron::showHighscores, actionCollection());
0136 
0137     //difficulty
0138     KGameDifficulty::global()->addStandardLevelRange(
0139         KGameDifficultyLevel::VeryEasy, KGameDifficultyLevel::VeryHard,
0140         KGameDifficultyLevel::Easy //default
0141     );
0142     KGameDifficultyGUI::init(this);
0143     connect(KGameDifficulty::global(), &KGameDifficulty::currentLevelChanged, m_tron, &Tron::loadSettings);
0144     connect(Renderer::self()->themeProvider(), &KGameThemeProvider::currentThemeChanged,
0145         [this](const KGameTheme *theme) {
0146         Settings::setTheme(QString::fromUtf8(theme->identifier()));
0147         });
0148 
0149     setupGUI( KXmlGuiWindow::Keys | StatusBar | Save | Create);
0150     loadSettings();
0151     m_tron->loadSettings();
0152 }
0153 
0154 KTron::~KTron()
0155 {
0156     delete m_tron;
0157 }
0158 
0159 void KTron::loadSettings() {
0160     if (!Renderer::self()->loadTheme(Settings::theme()))
0161     {
0162         KMessageBox::error(this, i18n("Failed to load \"%1\" theme. Please check your installation.", Settings::theme()));
0163     }
0164 
0165     m_tron->getPlayer(0)->setName(Settings::namePlayer1());
0166     m_tron->getPlayer(1)->setName(Settings::namePlayer2());
0167     Settings::setNamePlayer1(m_tron->getPlayer(0)->getName());
0168     if (!m_tron->getPlayer(1)->isComputer()) {
0169         Settings::setNamePlayer2(m_tron->getPlayer(1)->getName());
0170     }
0171 
0172     updateStatusbar();
0173 }
0174 
0175 void KTron::updateStatusbar() {
0176     QString message;
0177 
0178     if (!m_tron->running() && m_tron->hasWinner()) {
0179         QString winnerName = m_tron->getPlayer(m_tron->getWinner())->getName();
0180 
0181         message = i18n("%1 has won!", winnerName);
0182     }
0183     else if (m_tron->paused()) {
0184         message = i18n("Game paused");
0185     }
0186     else {
0187         message = QString();
0188     }
0189 
0190     m_statusBarLabel[0]->setText(message);
0191 
0192     if (Settings::gameType() == Settings::EnumGameType::Snake)
0193     {
0194         QString string = QStringLiteral( "%1: %2").arg(m_tron->getPlayer(0)->getName()).arg(m_tron->getPlayer(0)->getScore());
0195         m_statusBarLabel[1]->setText(string);
0196         m_statusBarLabel[2]->clear();
0197     }
0198     else
0199     {
0200         for (int i = 0; i < 2; ++i) {
0201             QString name = m_tron->getPlayer(1 - i)->getName();
0202             int score = m_tron->getPlayer(1 - i)->getScore();
0203 
0204             QString string = QStringLiteral( "%1: %2").arg(name).arg(score);
0205             m_statusBarLabel[i+1]->setText(string);
0206         }
0207     }
0208 }
0209 
0210 void KTron::blockPause(bool block)
0211 {
0212     //qCDebug(KSNAKEDUEL_LOG) << "Setting pause button state to: "  << !block;
0213     m_pauseButton->setEnabled(!block);
0214 }
0215 
0216 void KTron::updateScore()
0217 {
0218     updateStatusbar();
0219 }
0220 
0221 void KTron::changeStatus() {
0222     updateStatusbar();
0223 
0224     if (Settings::gameType() == Settings::EnumGameType::Snake)
0225     {
0226         KGameHighScoreDialog scoreDialog(KGameHighScoreDialog::Score | KGameHighScoreDialog::Name, this);
0227         scoreDialog.initFromDifficulty(KGameDifficulty::global());
0228 
0229         KGameHighScoreDialog::FieldInfo scoreInfo;
0230         scoreInfo[KGameHighScoreDialog::Name] = m_tron->getPlayer(0)->getName();
0231         scoreInfo[KGameHighScoreDialog::Score].setNum(m_tron->getPlayer(0)->getScore());
0232         if (scoreDialog.addScore(scoreInfo) != 0)
0233             scoreDialog.exec();
0234     }
0235 }
0236 
0237 void KTron::paletteChange(const QPalette &){
0238    update();
0239    m_tron->updatePixmap();
0240    m_tron->update();
0241 }
0242 
0243 /**
0244  * Show Settings dialog.
0245  */
0246 void KTron::showSettings(){
0247     if (KConfigDialog::showDialog(QStringLiteral( "settings" )))
0248         return;
0249 
0250     m_generalConfigDialog = new General();
0251 
0252     if (Settings::gameType() == Settings::EnumGameType::Snake) {
0253         m_generalConfigDialog->namePlayer1Label->setText(i18n("Player Name:"));
0254         m_generalConfigDialog->namePlayer2Label->setText(i18n("Opponent:"));
0255     }
0256     else {
0257         m_generalConfigDialog->namePlayer1Label->setText(i18n("Right player:"));
0258         m_generalConfigDialog->namePlayer2Label->setText(i18n("Left player:"));
0259     }
0260 
0261     KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral( "settings" ), Settings::self());
0262     dialog->addPage(m_generalConfigDialog, i18n("General"), QStringLiteral( "games-config-options" ));
0263     dialog->addPage(new KGameThemeSelector(Renderer::self()->themeProvider(), KGameThemeSelector::EnableNewStuffDownload, dialog), i18n("Theme"), QStringLiteral( "games-config-theme" ));
0264     connect(dialog, &KConfigDialog::settingsChanged, this, &KTron::loadSettings);
0265     connect(dialog, &KConfigDialog::settingsChanged, m_tron, &Tron::loadSettings);
0266     dialog->show();
0267 }
0268 
0269 /**
0270  * Show highscores
0271  */
0272 void KTron::showHighscores() {
0273     KGameHighScoreDialog scoreDialog(KGameHighScoreDialog::Score | KGameHighScoreDialog::Name, this);
0274     scoreDialog.initFromDifficulty(KGameDifficulty::global());
0275     scoreDialog.exec();
0276 }
0277 
0278 /**
0279  * Close KTron
0280  */
0281 void KTron::close() {
0282     Settings::self()->save();
0283 }
0284 
0285 void KTron::closeEvent(QCloseEvent *event)
0286 {
0287     close();
0288     event->accept();
0289 }
0290 
0291 void KTron::optionsConfigureKeys()
0292 {
0293     KShortcutsDialog::showDialog(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, this);
0294 }
0295 
0296 // Key events
0297 void KTron::keyPressEvent(QKeyEvent *e)
0298 {
0299     if (m_player0Accelerate->shortcuts().contains(e->key()))
0300     {
0301         triggerKey0Accelerate(true);
0302     }
0303     else if (m_player1Accelerate->shortcuts().contains(e->key()))
0304     {
0305         triggerKey1Accelerate(true);
0306     }
0307 }
0308 
0309 void KTron::keyReleaseEvent(QKeyEvent *e)
0310 {
0311     if (m_player0Accelerate->shortcuts().contains(e->key()))
0312     {
0313         triggerKey0Accelerate(false);
0314     }
0315     else if (m_player1Accelerate->shortcuts().contains(e->key()))
0316     {
0317         triggerKey1Accelerate(false);
0318     }
0319 }
0320 
0321 // Triggers
0322 void KTron::triggerKey0Up(bool b)
0323 {
0324     m_tron->triggerKey(0, KBAction::UP, b);
0325 }
0326 
0327 void KTron::triggerKey0Down(bool b)
0328 {
0329     m_tron->triggerKey(0, KBAction::DOWN, b);
0330 }
0331 
0332 void KTron::triggerKey0Left(bool b)
0333 {
0334     m_tron->triggerKey(0, KBAction::LEFT, b);
0335 }
0336 
0337 void KTron::triggerKey0Right(bool b)
0338 {
0339     m_tron->triggerKey(0, KBAction::RIGHT, b);
0340 }
0341 
0342 void KTron::triggerKey0Accelerate(bool b)
0343 {
0344     m_tron->triggerKey(0, KBAction::ACCELERATE, b);
0345 }
0346 
0347 void KTron::triggerKey1Up(bool b)
0348 {
0349     m_tron->triggerKey(1, KBAction::UP, b);
0350 }
0351 
0352 void KTron::triggerKey1Down(bool b)
0353 {
0354     m_tron->triggerKey(1, KBAction::DOWN, b);
0355 }
0356 
0357 void KTron::triggerKey1Left(bool b)
0358 {
0359     m_tron->triggerKey(1, KBAction::LEFT, b);
0360 }
0361 
0362 void KTron::triggerKey1Right(bool b)
0363 {
0364     m_tron->triggerKey(1, KBAction::RIGHT, b);
0365 }
0366 
0367 void KTron::triggerKey1Accelerate(bool b)
0368 {
0369     m_tron->triggerKey(1, KBAction::ACCELERATE, b);
0370 }
0371 
0372 #include "moc_ktron.cpp"