File indexing completed on 2024-10-13 03:44:25

0001 /*
0002     SPDX-FileCopyrightText: 2013 Ashwin Rajeev <ashwin_rajeev@hotmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "gameview.h"
0008 
0009 // game
0010 #include "globals.h"
0011 #include "settings.h"
0012 // KDEGames
0013 #include <KGameSound>
0014 // KF
0015 #include <KMessageBox>
0016 #include <KLocalizedContext>
0017 #include <KLocalizedString>
0018 // Qt
0019 #include <QGraphicsObject>
0020 #include <QQmlContext>
0021 
0022 
0023 GameView::GameView(QWidget *parent) :
0024     QQuickWidget(parent),
0025     grid(new AbstractGrid),
0026     m_provider(new KGameThemeProvider)
0027 {
0028     QQmlEngine *engine = this->engine();
0029 
0030     auto *localizedContextObject = new KLocalizedContext(engine);
0031     engine->rootContext()->setContextObject(localizedContextObject);
0032 
0033     setResizeMode(SizeRootObjectToView);
0034 
0035     m_provider->discoverThemes(QStringLiteral("themes"));
0036     m_provider->setDeclarativeEngine(QStringLiteral("themeProvider"), engine);
0037     m_soundTurn = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/turn.wav")), this);
0038     m_soundClick = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/click.wav")), this);
0039     m_soundConnect = new KGameSound(QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("sounds/connect.wav")), this);
0040     QString path = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("qml/main.qml"));
0041 
0042     setSource(QUrl::fromLocalFile(path));
0043     updateSettings();
0044 
0045     connect(rootObject(), SIGNAL(clicked(int)),this, SLOT(clicked(int)));
0046     connect(rootObject(), SIGNAL(rotated(int,int)), this, SLOT(rotated(int,int)));
0047     connect(this, SIGNAL(setSize(QVariant,QVariant)),
0048             rootObject(), SLOT(setBoardSize(QVariant,QVariant)));
0049     connect(this, SIGNAL(newCell(QVariant,QVariant)),
0050             rootObject(), SLOT(addCell(QVariant,QVariant)));
0051     connect(this, SIGNAL(setSprite(QVariant,QVariant,QVariant)),
0052             rootObject(), SLOT(setSprite(QVariant,QVariant,QVariant)));
0053     connect(this, SIGNAL(lock(QVariant)), rootObject(), SLOT(lock(QVariant)));
0054     connect(this, SIGNAL(gameOver(QVariant)), rootObject(), SLOT(gameOver(QVariant)));
0055 }
0056 
0057 GameView::~GameView()
0058 {
0059     delete m_provider;
0060     delete grid;
0061 }
0062 
0063 void GameView::startNewGame(uint width, uint height, Wrapping w=NotWrapped)
0064 {
0065     setSize(width, height);
0066     grid->initializeGrid(width, height, w);
0067 
0068     for(int i = 0; i < grid->cellCount(); i++)
0069     {
0070         QString code = getCableCode(grid->cellAt(i)->cables());
0071         QString type = QStringLiteral("none");
0072         if(grid->cellAt(i)->isConnected()){
0073             code = QLatin1String("con") + code;
0074         }
0075         if(grid->cellAt(i)->isServer()){
0076             type = QStringLiteral("server");
0077         }
0078         else if(grid->cellAt(i)->isTerminal()) {
0079             type = (grid->cellAt(i)->isConnected())? QStringLiteral("computer2"): QStringLiteral("computer1");
0080         }
0081         newCell(code, type);
0082     }
0083 }
0084 
0085 void GameView::clicked(int index)
0086 {
0087     if (index >= 0) {
0088         rotatingCells.insert(index);
0089         Q_EMIT rotationStarted();
0090         if (Settings::playSounds()) {
0091             m_soundTurn->start();
0092         }
0093     }
0094     else if (Settings::playSounds()) { //invalid click
0095         m_soundClick->start();
0096     }
0097 }
0098 
0099 void GameView::rotated(int index, int angle)
0100 {
0101     switch (angle) {
0102     case 90: case -270:
0103         grid->cellAt(index)->rotateClockwise();
0104         break;
0105     case -90: case 270:
0106         grid->cellAt(index)->rotateCounterclockwise();
0107         break;
0108     case 180: case -180:
0109         grid->cellAt(index)->invert();
0110     }
0111     const QList<int> changedCells = grid->updateConnections();
0112     bool newTerminalConnected = false;
0113     rotatingCells.remove(index);
0114 
0115     for (int i : changedCells) {
0116         if(grid->cellAt(i)->isTerminal()){
0117             newTerminalConnected = true;
0118         }
0119         updateSprite(i);
0120     }
0121 
0122     if(newTerminalConnected && Settings::playSounds())
0123         m_soundConnect->start();
0124 
0125     if(!changedCells.contains(index)) {
0126         updateSprite(index);
0127     }
0128 
0129     if (Settings::autolock()) {
0130         Q_EMIT lock(index);
0131     }
0132     if (rotatingCells.count() == 0) {
0133         checkCompleted();
0134     }
0135 }
0136 
0137 void GameView::updateSprite(int index)
0138 {
0139     QString type = QStringLiteral("none");
0140     if(grid->cellAt(index)->isTerminal()){
0141         type = (grid->cellAt(index)->isConnected())? QStringLiteral("computer2"): QStringLiteral("computer1");
0142     }
0143 
0144     QString code = getCableCode(grid->cellAt(index)->cables());
0145     if(grid->cellAt(index)->isConnected()) {
0146         code.insert(0, QLatin1String("con"));
0147     }
0148 
0149     if (!rotatingCells.contains(index)) {
0150         setSprite(index, code, type);
0151     }
0152 }
0153 
0154 void GameView::checkCompleted()
0155 {
0156     if (!grid->allTerminalsConnected()) {
0157         return;
0158     }
0159     for(int i = 0; i < grid->cellCount(); ++i) {
0160         if (grid->cellAt(i)->cables() != None && !grid->cellAt(i)->isConnected()) {
0161             KMessageBox::information(this,
0162                 i18n("Note: to win the game all terminals "
0163                 "<strong>and all <em>cables</em></strong> "
0164                 "need to be connected to the server!"),
0165                 i18n("The game is not won yet!"),
0166                 QStringLiteral( "dontShowGameNotWonYet" ));
0167             return;
0168         }
0169     }
0170     Q_EMIT gameOver(QLatin1String("won"));
0171 }
0172 
0173 void GameView::solve()
0174 {
0175     if (!rotatingCells.isEmpty()) {
0176         return;
0177     }
0178     for(int i = 0; i < grid->cellCount(); i++) {
0179         grid->cellAt(i)->reset();
0180         QString code = QLatin1String("con") + getCableCode(grid->cellAt(i)->cables());
0181         if (grid->cellAt(i)->isTerminal()){
0182             setSprite(i, code, QLatin1String("computer2"));
0183         }
0184         else {
0185             setSprite(i, code, QLatin1String("none"));
0186         }
0187     }
0188     Q_EMIT gameOver(QLatin1String("solved"));
0189 }
0190 
0191 void GameView::updateSettings()
0192 {
0193     rootObject()->setProperty("rotateDuration", Settings::rotateDuration());
0194     rootObject()->setProperty("reverseButtons", Settings::reverseButtons());
0195 }
0196 
0197 QString GameView::getCableCode(int cables)
0198 {
0199     QHash<int, QString> directionNames;
0200     directionNames[Left]            = QStringLiteral("0001");
0201     directionNames[Down]            = QStringLiteral("0010");
0202     directionNames[Down|Left]       = QStringLiteral("0011");
0203     directionNames[Right]           = QStringLiteral("0100");
0204     directionNames[Right|Left]      = QStringLiteral("0101");
0205     directionNames[Right|Down]      = QStringLiteral("0110");
0206     directionNames[Right|Down|Left] = QStringLiteral("0111");
0207     directionNames[Up]              = QStringLiteral("1000");
0208     directionNames[Up|Left]         = QStringLiteral("1001");
0209     directionNames[Up|Down]         = QStringLiteral("1010");
0210     directionNames[Up|Down|Left]    = QStringLiteral("1011");
0211     directionNames[Up|Right]        = QStringLiteral("1100");
0212     directionNames[Up|Right|Left]   = QStringLiteral("1101");
0213     directionNames[Up|Right|Down]   = QStringLiteral("1110");
0214     return directionNames[cables];
0215 }
0216 
0217 #include "moc_gameview.cpp"