1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 //Own
43 #include "states.h"
44 #include "graphicsscene.h"
45 #include "boat.h"
46 #include "submarine.h"
47 #include "torpedo.h"
48 #include "animationmanager.h"
49 #include "progressitem.h"
50 #include "textinformationitem.h"
51 
52 //Qt
53 #include <QtGui/QMessageBox>
54 #include <QtGui/QGraphicsView>
55 #include <QtCore/QStateMachine>
56 #include <QtGui/QKeyEventTransition>
57 #include <QtCore/QFinalState>
58 
PlayState(GraphicsScene * scene,QState * parent)59 PlayState::PlayState(GraphicsScene *scene, QState *parent)
60     : QState(parent),
61     scene(scene),
62     machine(0),
63     currentLevel(0),
64     score(0)
65 {
66 }
67 
~PlayState()68 PlayState::~PlayState()
69 {
70     delete machine;
71 }
72 
onEntry(QEvent *)73 void PlayState::onEntry(QEvent *)
74 {
75     //We are now playing?
76     if (machine) {
77         machine->stop();
78         //we hide the information
79         scene->textInformationItem->hide();
80         scene->clearScene();
81         currentLevel = 0;
82         score = 0;
83         delete machine;
84     }
85 
86     machine = new QStateMachine;
87 
88     //This state is when player is playing
89     LevelState *levelState = new LevelState(scene, this, machine);
90 
91     //This state is when the player is actually playing but the game is not paused
92     QState *playingState = new QState(levelState);
93     levelState->setInitialState(playingState);
94 
95     //This state is when the game is paused
96     PauseState *pauseState = new PauseState(scene, levelState);
97 
98     //We have one view, it receive the key press event
99     QKeyEventTransition *pressPplay = new QKeyEventTransition(scene->views().at(0), QEvent::KeyPress, Qt::Key_P);
100     pressPplay->setTargetState(pauseState);
101     QKeyEventTransition *pressPpause = new QKeyEventTransition(scene->views().at(0), QEvent::KeyPress, Qt::Key_P);
102     pressPpause->setTargetState(playingState);
103 
104     //Pause "P" is triggered, the player pause the game
105     playingState->addTransition(pressPplay);
106 
107     //To get back playing when the game has been paused
108     pauseState->addTransition(pressPpause);
109 
110     //This state is when player have lost
111     LostState *lostState = new LostState(scene, this, machine);
112 
113     //This state is when player have won
114     WinState *winState = new WinState(scene, this, machine);
115 
116     //The boat has been destroyed then the game is finished
117     levelState->addTransition(scene->boat, SIGNAL(boatExecutionFinished()),lostState);
118 
119     //This transition check if we won or not
120     WinTransition *winTransition = new WinTransition(scene, this, winState);
121 
122     //The boat has been destroyed then the game is finished
123     levelState->addTransition(winTransition);
124 
125     //This state is an animation when the score changed
126     UpdateScoreState *scoreState = new UpdateScoreState(this, levelState);
127 
128     //This transition update the score when a submarine die
129     UpdateScoreTransition *scoreTransition = new UpdateScoreTransition(scene, this, levelState);
130     scoreTransition->setTargetState(scoreState);
131 
132     //The boat has been destroyed then the game is finished
133     playingState->addTransition(scoreTransition);
134 
135     //We go back to play state
136     scoreState->addTransition(playingState);
137 
138     //We start playing!!!
139     machine->setInitialState(levelState);
140 
141     //Final state
142     QFinalState *final = new QFinalState(machine);
143 
144     //This transition is triggered when the player press space after completing a level
145     CustomSpaceTransition *spaceTransition = new CustomSpaceTransition(scene->views().at(0), this, QEvent::KeyPress, Qt::Key_Space);
146     spaceTransition->setTargetState(levelState);
147     winState->addTransition(spaceTransition);
148 
149     //We lost we should reach the final state
150     lostState->addTransition(lostState, SIGNAL(finished()), final);
151 
152     machine->start();
153 }
154 
LevelState(GraphicsScene * scene,PlayState * game,QState * parent)155 LevelState::LevelState(GraphicsScene *scene, PlayState *game, QState *parent) : QState(parent), scene(scene), game(game)
156 {
157 }
onEntry(QEvent *)158 void LevelState::onEntry(QEvent *)
159 {
160     initializeLevel();
161 }
162 
initializeLevel()163 void LevelState::initializeLevel()
164 {
165     //we re-init the boat
166     scene->boat->setPos(scene->width()/2, scene->sealLevel() - scene->boat->size().height());
167     scene->boat->setCurrentSpeed(0);
168     scene->boat->setCurrentDirection(Boat::None);
169     scene->boat->setBombsLaunched(0);
170     scene->boat->show();
171     scene->setFocusItem(scene->boat, Qt::OtherFocusReason);
172     scene->boat->run();
173 
174     scene->progressItem->setScore(game->score);
175     scene->progressItem->setLevel(game->currentLevel + 1);
176 
177     GraphicsScene::LevelDescription currentLevelDescription = scene->levelsData.value(game->currentLevel);
178 
179     for (int i = 0; i < currentLevelDescription.submarines.size(); ++i ) {
180 
181         QPair<int,int> subContent = currentLevelDescription.submarines.at(i);
182         GraphicsScene::SubmarineDescription submarineDesc = scene->submarinesData.at(subContent.first);
183 
184         for (int j = 0; j < subContent.second; ++j ) {
185             SubMarine *sub = new SubMarine(submarineDesc.type, submarineDesc.name, submarineDesc.points);
186             scene->addItem(sub);
187             int random = (qrand() % 15 + 1);
188             qreal x = random == 13 || random == 5 ? 0 : scene->width() - sub->size().width();
189             qreal y = scene->height() -(qrand() % 150 + 1) - sub->size().height();
190             sub->setPos(x,y);
191             sub->setCurrentDirection(x == 0 ? SubMarine::Right : SubMarine::Left);
192             sub->setCurrentSpeed(qrand() % 3 + 1);
193         }
194     }
195 }
196 
197 /** Pause State */
PauseState(GraphicsScene * scene,QState * parent)198 PauseState::PauseState(GraphicsScene *scene, QState *parent) : QState(parent),scene(scene)
199 {
200 }
onEntry(QEvent *)201 void PauseState::onEntry(QEvent *)
202 {
203     AnimationManager::self()->pauseAll();
204     scene->boat->setEnabled(false);
205 }
onExit(QEvent *)206 void PauseState::onExit(QEvent *)
207 {
208     AnimationManager::self()->resumeAll();
209     scene->boat->setEnabled(true);
210     scene->boat->setFocus();
211 }
212 
213 /** Lost State */
LostState(GraphicsScene * scene,PlayState * game,QState * parent)214 LostState::LostState(GraphicsScene *scene, PlayState *game, QState *parent) : QState(parent), scene(scene), game(game)
215 {
216 }
217 
onEntry(QEvent *)218 void LostState::onEntry(QEvent *)
219 {
220     //The message to display
221     QString message = QString("You lose on level %1. Your score is %2.").arg(game->currentLevel+1).arg(game->score);
222 
223     //We set the level back to 0
224     game->currentLevel = 0;
225 
226     //We set the score back to 0
227     game->score = 0;
228 
229     //We clear the scene
230     scene->clearScene();
231 
232     //We inform the player
233     scene->textInformationItem->setMessage(message);
234     scene->textInformationItem->show();
235 }
236 
onExit(QEvent *)237 void LostState::onExit(QEvent *)
238 {
239     //we hide the information
240     scene->textInformationItem->hide();
241 }
242 
243 /** Win State */
WinState(GraphicsScene * scene,PlayState * game,QState * parent)244 WinState::WinState(GraphicsScene *scene, PlayState *game, QState *parent) : QState(parent), scene(scene), game(game)
245 {
246 }
247 
onEntry(QEvent *)248 void WinState::onEntry(QEvent *)
249 {
250     //We clear the scene
251     scene->clearScene();
252 
253     QString message;
254     if (scene->levelsData.size() - 1 != game->currentLevel) {
255         message = QString("You win the level %1. Your score is %2.\nPress Space to continue.").arg(game->currentLevel+1).arg(game->score);
256         //We increment the level number
257         game->currentLevel++;
258     } else {
259         message = QString("You finish the game on level %1. Your score is %2.").arg(game->currentLevel+1).arg(game->score);
260         //We set the level back to 0
261         game->currentLevel = 0;
262         //We set the score back to 0
263         game->score = 0;
264     }
265 
266     //We inform the player
267     scene->textInformationItem->setMessage(message);
268     scene->textInformationItem->show();
269 }
270 
onExit(QEvent *)271 void WinState::onExit(QEvent *)
272 {
273     //we hide the information
274     scene->textInformationItem->hide();
275 }
276 
277 /** UpdateScore State */
UpdateScoreState(PlayState * g,QState * parent)278 UpdateScoreState::UpdateScoreState(PlayState *g, QState *parent) : QState(parent), game(g)
279 {
280 }
281 
282 /** Win transition */
UpdateScoreTransition(GraphicsScene * scene,PlayState * game,QAbstractState * target)283 UpdateScoreTransition::UpdateScoreTransition(GraphicsScene *scene, PlayState *game, QAbstractState *target)
284     : QSignalTransition(scene,SIGNAL(subMarineDestroyed(int))),
285     game(game), scene(scene)
286 {
287     setTargetState(target);
288 }
289 
eventTest(QEvent * event)290 bool UpdateScoreTransition::eventTest(QEvent *event)
291 {
292     if (!QSignalTransition::eventTest(event))
293         return false;
294     QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(event);
295     game->score += se->arguments().at(0).toInt();
296     scene->progressItem->setScore(game->score);
297     return true;
298 }
299 
300 /** Win transition */
WinTransition(GraphicsScene * scene,PlayState * game,QAbstractState * target)301 WinTransition::WinTransition(GraphicsScene *scene, PlayState *game, QAbstractState *target)
302     : QSignalTransition(scene,SIGNAL(allSubMarineDestroyed(int))),
303     game(game), scene(scene)
304 {
305     setTargetState(target);
306 }
307 
eventTest(QEvent * event)308 bool WinTransition::eventTest(QEvent *event)
309 {
310     if (!QSignalTransition::eventTest(event))
311         return false;
312     QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(event);
313     game->score += se->arguments().at(0).toInt();
314     scene->progressItem->setScore(game->score);
315     return true;
316 }
317 
318 /** Space transition */
CustomSpaceTransition(QWidget * widget,PlayState * game,QEvent::Type type,int key)319 CustomSpaceTransition::CustomSpaceTransition(QWidget *widget, PlayState *game, QEvent::Type type, int key)
320     :   QKeyEventTransition(widget, type, key),
321         game(game)
322 {
323 }
324 
eventTest(QEvent * event)325 bool CustomSpaceTransition::eventTest(QEvent *event)
326 {
327     if (!QKeyEventTransition::eventTest(event))
328         return false;
329     return (game->currentLevel != 0);
330 }
331