KBlocksWin.cpp 9.67 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/******************************************************************************
*   KBlocks, a falling blocks game by KDE                                     *
*   Copyright (C) 2009-2021 Mauricio Piacentini <mauricio@tabuleiro.com>      *
*                           Zhongjie Cai <squall.leonhart.cai@gmail.com>      *
*                           Julian Helfferich <julian.helfferich@mailbox.org> *
*                                                                             *
*   This program is free software; you can redistribute it and/or modify      *
*   it under the terms of the GNU General Public License as published by      *
*   the Free Software Foundation; either version 2 of the License, or         *
*   (at your option) any later version.                                       *
******************************************************************************/
12
13
14
15
16
17
18
#include "KBlocksWin.h"

#include <limits.h>

#include <KConfigDialog>
#include <kstandardgameaction.h>
#include <KStandardAction>
Laurent Montel's avatar
Laurent Montel committed
19
#include <highscore/kscoredialog.h>
Laurent Montel's avatar
Laurent Montel committed
20
#include <KLocalizedString>
21
22
#include <KToggleAction>
#include <KActionCollection>
Laurent Montel's avatar
Laurent Montel committed
23
#include <QStatusBar>
24
#include <KgDifficulty>
25
26

#include <QPixmapCache>
Martin Walch's avatar
Martin Walch committed
27
#include <QPointer>
Laurent Montel's avatar
Laurent Montel committed
28
#include <QLabel>
Laurent Montel's avatar
Laurent Montel committed
29
#include <QRandomGenerator>
30

31
32
33
#define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API
#include <libkdegamesprivate/kgamethemeselector.h>

34
#include "GameLogicInterface.h"
35
36
#include "KBlocksScene.h"
#include "SceneInterface.h"
37
38
#include "settings.h"

39
40
41
42
43
44
45
46
KBlocksWin::KBlocksWin(
    GameLogicInterface *p,
    GraphicsInterface *graphics,
    SoundInterface *sound,
    KBlocksPlayManager *pM,
    int capacity,
    int gamecount
) : KXmlGuiWindow()
47
48
{
    //Use up to 3MB for global application pixmap cache
Laurent Montel's avatar
Laurent Montel committed
49
50
    QPixmapCache::setCacheLimit(3 * 1024);

51
52
    mpKBPlayer = new KBlocksKeyboardPlayer(this);
    mpAIPlayer = new KBlocksAIPlayer();
Laurent Montel's avatar
Laurent Montel committed
53

54
55
56
    mMaxGameCapacity = capacity;
    mGameCount = gamecount;
    mpGameLogic = p;
57
    connect(mpGameLogic, &GameLogicInterface::allGamesStopped,
58
59
            this, &KBlocksWin::onAllGamesStopped);

60
    mpPlayManager = pM;
Laurent Montel's avatar
Laurent Montel committed
61

62
    mpGameScene = new KBlocksScene(mpGameLogic, graphics, sound, capacity);
Laurent Montel's avatar
Laurent Montel committed
63

Julian Helfferich's avatar
Julian Helfferich committed
64
    connect(mpKBPlayer, &KBlocksKeyboardPlayer::blockMoved,
65
            mpGameScene, &SceneInterface::playMoveSound);
Julian Helfferich's avatar
Julian Helfferich committed
66
    connect(mpKBPlayer, &KBlocksKeyboardPlayer::blockDropped,
67
            mpGameScene, &SceneInterface::playDropSound);
Julian Helfferich's avatar
Julian Helfferich committed
68

69
    mpGameView = new KBlocksView(mpGameScene, this);
Laurent Montel's avatar
Laurent Montel committed
70
    mpGameView->show();
71
    setCentralWidget(mpGameView);
Laurent Montel's avatar
Laurent Montel committed
72
    connect(mpGameView, &KBlocksView::focusEvent, this, &KBlocksWin::focusEvent);
Laurent Montel's avatar
Laurent Montel committed
73

74
75
76
77
78
79
80
    setAutoSaveSettings();
}

KBlocksWin::~KBlocksWin()
{
    delete mpGameView;
    delete mpGameScene;
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    delete mpAIPlayer;
    delete mpKBPlayer;
}

void KBlocksWin::setGamesPerLine(int count)
{
    mpGameScene->setGamesPerLine(count);
}

void KBlocksWin::setGameAnimEnabled(bool flag)
{
    mpGameScene->setGameAnimEnabled(flag);
    mGameAnim = flag;
}

void KBlocksWin::setWaitForAllUpdate(bool flag)
{
    mpGameScene->setWaitForAllUpdate(flag);
    mWaitForAll = flag;
}

void KBlocksWin::setUpdateInterval(int interval)
{
    mpGameScene->setUpdateInterval(interval);
}

void KBlocksWin::addScore(int gameIndex, int lineCount)
{
    mpGameScene->addScore(gameIndex, lineCount);
110
111
}

112
void KBlocksWin::startGame()
113
{
Laurent Montel's avatar
Laurent Montel committed
114
    mpGameLogic->setGameSeed(QRandomGenerator::global()->generate());
Laurent Montel's avatar
Laurent Montel committed
115
    if (mpGameLogic->startGame(mGameCount)) {
116
        mpPlayManager->startGame();
Laurent Montel's avatar
Laurent Montel committed
117

118
119
        mpGameScene->createGameItemGroups(mGameCount, false);
        mpGameScene->startGame();
Laurent Montel's avatar
Laurent Montel committed
120

121
        int levelUpTime = 0;
Laurent Montel's avatar
Laurent Montel committed
122
123
124
125
126
127
128
        switch ((int) Kg::difficultyLevel()) {
        case KgDifficultyLevel::Medium:
            levelUpTime = 5;
            break;
        case KgDifficultyLevel::Hard:
            levelUpTime = 10;
            break;
129
130
        }
        mpGameLogic->levelUpGame(levelUpTime);
Laurent Montel's avatar
Laurent Montel committed
131

132
        Kg::difficulty()->setGameRunning(true);
Laurent Montel's avatar
Laurent Montel committed
133
    } else {
134
135
136
        stopGame();
        startGame();
    }
137

138
139
    mpGameView->fitInView(mpGameScene->sceneRect(), Qt::KeepAspectRatio);

Laurent Montel's avatar
Laurent Montel committed
140
    mScore->setText(i18n("Points: %1 - Lines: %2 - Level: %3", 0, 0, 0));
141
142
143

    m_pauseAction->setEnabled(true);
    m_pauseAction->setChecked(false);
144
145
}

146
void KBlocksWin::stopGame()
147
{
148
    if (mpGameLogic->hasSingleGames()) {
149
        mpGameScene->stopGame();
150
151
        mpGameLogic->deleteSingleGames();
        // Clear the game field
152
153
154
155
        mpGameScene->deleteGameItemGroups();
    }
}

156
void KBlocksWin::pauseGame()
157
{
158
159
160
    mpGameLogic->pauseGame(m_pauseAction->isChecked());
    mpPlayManager->pauseGame(m_pauseAction->isChecked());
    mpGameScene->pauseGame(m_pauseAction->isChecked());
161
162
163

    mpKBPlayer->pauseGame(m_pauseAction->isChecked());
    mpAIPlayer->pauseGame(m_pauseAction->isChecked());
Laurent Montel's avatar
Laurent Montel committed
164

165
    Kg::difficulty()->setGameRunning(!m_pauseAction->isChecked());
166
167
}

168
169
170
171
172
173
174
void KBlocksWin::onAllGamesStopped()
{
    mpPlayManager->stopGame();
    m_pauseAction->setEnabled(false);
    Kg::difficulty()->setGameRunning(false);
}

175
void KBlocksWin::singleGame()
176
{
177
178
179
180
    mpPlayManager->stopGame();
    mpPlayManager->clearGamePlayer();
    mpPlayManager->addGamePlayer(mpKBPlayer, -1, -1);
    mGameCount = 1;
Laurent Montel's avatar
Laurent Montel committed
181

182
183
184
185
186
187
188
189
190
191
    startGame();
}

void KBlocksWin::pveStepGame()
{
    mpPlayManager->stopGame();
    mpPlayManager->clearGamePlayer();
    mpPlayManager->addGamePlayer(mpKBPlayer, -1, -1);
    mpPlayManager->addGamePlayer(mpAIPlayer, 200, 50);
    mGameCount = 2;
Laurent Montel's avatar
Laurent Montel committed
192

193
194
    mpGameLogic->setGameStandbyMode(true);
    setWaitForAllUpdate(true);
Laurent Montel's avatar
Laurent Montel committed
195

196
197
198
199
200
    startGame();
}

void KBlocksWin::focusEvent(bool flag)
{
Laurent Montel's avatar
Laurent Montel committed
201
202
    if (!flag) {
        if (m_pauseAction->isChecked()) {
203
204
205
206
207
208
209
210
            return;
        }
    }
    mpGameLogic->pauseGame(flag);
    mpPlayManager->pauseGame(flag);
    mpGameScene->pauseGame(flag, true);
}

211
void KBlocksWin::closeEvent(QCloseEvent *event)
212
{
Laurent Montel's avatar
Laurent Montel committed
213
    Settings::self()->save();
214
    KXmlGuiWindow::closeEvent(event);
215
216
217
218
219
}

void KBlocksWin::showHighscore()
{
    KScoreDialog ksdialog(KScoreDialog::Name | KScoreDialog::Level | KScoreDialog::Score, this);
220
    ksdialog.initFromDifficulty(Kg::difficulty());
221
222
223
224
225
    ksdialog.exec();
}

void KBlocksWin::configureSettings()
{
226
    if (KConfigDialog::showDialog(QStringLiteral("settings"))) {
227
228
        return;
    }
229
230
    KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), Settings::self());
    dialog->addPage(new KGameThemeSelector(dialog, Settings::self()), i18n("Theme"), QStringLiteral("games-config-theme"));
Laurent Montel's avatar
Laurent Montel committed
231
    dialog->setFaceType(KConfigDialog::Plain); //only one page -> no page selection necessary
Laurent Montel's avatar
Laurent Montel committed
232
    connect(dialog, &KConfigDialog::settingsChanged, mpGameView, &KBlocksView::settingsChanged);
233
    //connect(dialog, SIGNAL(hidden()), view, SLOT(resumeFromConfigure()));
234
235
236
    dialog->show();
}

237
void KBlocksWin::onScoreChanged(int index, int points, int lines, int level)
238
{
Laurent Montel's avatar
Laurent Montel committed
239
240
    if (index == 0) { // TODO : game id?? multi game display??
        mScore->setText(i18n("Points: %1 - Lines: %2 - Level: %3", points, lines, level));
241
    }
242
243
}

244
void KBlocksWin::onIsHighscore(int index, int points, int level)
245
{
Laurent Montel's avatar
Laurent Montel committed
246
247
    if (index == 0) { // TODO : game id?? multi game display??
        QPointer<KScoreDialog> ksdialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Level | KScoreDialog::Score, this);
Martin Walch's avatar
Martin Walch committed
248
        ksdialog->initFromDifficulty(Kg::difficulty());
249
        KScoreDialog::FieldInfo info;
Laurent Montel's avatar
Laurent Montel committed
250
251
252
        info[KScoreDialog::Score].setNum(points);
        info[KScoreDialog::Level].setNum(level);
        if (ksdialog->addScore(info)) {
Martin Walch's avatar
Martin Walch committed
253
            ksdialog->exec();
254
        }
Martin Walch's avatar
Martin Walch committed
255
        delete ksdialog;
256
257
258
    }
}

259
void KBlocksWin::levelChanged()
260
261
{
    //Scene reads the difficulty level for us
262
263
264
265
266
    if (mGameCount == 1) {
        singleGame();
    } else {
        pveStepGame();
    }
267
268
269
270
271
272
273
274
275
276
277
    mpGameView->setFocus(Qt::MouseFocusReason);
}

void KBlocksWin::setSoundsEnabled(bool enabled)
{
    mpGameScene->setSoundsEnabled(enabled);
    Settings::setSounds(enabled);
}

void KBlocksWin::setupGUILayout()
{
278
    QAction *action;
Laurent Montel's avatar
Laurent Montel committed
279

280
281
    action = KStandardGameAction::gameNew(this, SLOT(singleGame()), actionCollection());
    action->setText(i18n("Single Game"));
282
    actionCollection()->addAction(QStringLiteral("newGame"), action);
Laurent Montel's avatar
Laurent Montel committed
283

Laurent Montel's avatar
Laurent Montel committed
284
    action = new QAction(this);
285
    action->setText(i18n("Human vs AI"));
286
    actionCollection()->addAction(QStringLiteral("pve_step"), action);
Laurent Montel's avatar
Laurent Montel committed
287
    connect(action, &QAction::triggered, this, &KBlocksWin::pveStepGame);
Laurent Montel's avatar
Laurent Montel committed
288

289
    m_pauseAction = KStandardGameAction::pause(this, SLOT(pauseGame()), actionCollection());
290
    actionCollection()->addAction(QStringLiteral("pauseGame"), m_pauseAction);
291
    m_pauseAction->setEnabled(false);
Laurent Montel's avatar
Laurent Montel committed
292

293
    action = KStandardGameAction::highscores(this, SLOT(showHighscore()), actionCollection());
294
    actionCollection()->addAction(QStringLiteral("showHighscores"), action);
Laurent Montel's avatar
Laurent Montel committed
295

296
    action = KStandardGameAction::quit(this, SLOT(close()), actionCollection());
297
    actionCollection()->addAction(QStringLiteral("quit"), action);
Laurent Montel's avatar
Laurent Montel committed
298

299
    KStandardAction::preferences(this, SLOT(configureSettings()), actionCollection());
Laurent Montel's avatar
Laurent Montel committed
300

Antoni Bella Pérez's avatar
Antoni Bella Pérez committed
301
    KToggleAction *soundAction = new KToggleAction(i18n("&Play Sounds"), this);
302
    soundAction->setChecked(Settings::sounds());
303
    actionCollection()->addAction(QStringLiteral("sounds"), soundAction);
Laurent Montel's avatar
Laurent Montel committed
304
    connect(soundAction, &KToggleAction::triggered, this, &KBlocksWin::setSoundsEnabled);
305
    mpGameScene->setSoundsEnabled(Settings::sounds());
Laurent Montel's avatar
Laurent Montel committed
306

307
    // TODO
Laurent Montel's avatar
Laurent Montel committed
308
    mScore = new QLabel(i18n("Points: 0 - Lines: 0 - Level: 0"));
Laurent Montel's avatar
Laurent Montel committed
309
    statusBar()->addPermanentWidget(mScore);
Laurent Montel's avatar
Laurent Montel committed
310
311
    connect(mpGameScene, &KBlocksScene::scoreChanged, this, &KBlocksWin::onScoreChanged);
    connect(mpGameScene, &KBlocksScene::isHighscore, this, &KBlocksWin::onIsHighscore);
Laurent Montel's avatar
Laurent Montel committed
312

313
314
315
316
    Kg::difficulty()->addStandardLevelRange(
        KgDifficultyLevel::Easy, KgDifficultyLevel::Hard
    );
    KgDifficultyGUI::init(this);
317
    connect(Kg::difficulty(), &KgDifficulty::currentLevelChanged, this, &KBlocksWin::levelChanged);
Laurent Montel's avatar
Laurent Montel committed
318

319
320
321
    setupGUI();
}