Now supports multiple levels.
[ghostsoverboard] / seascene.cpp
1 /**************************************************************************
2         Ghosts Overboard - a game for Maemo 5
3
4         Copyright (C) 2011  Heli Hyvättinen
5
6         This file is part of Ghosts Overboard
7
8         Ghosts Overboard is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 2 of the License, or
11         (at your option) any later version.
12
13         This program is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 **************************************************************************/
22
23 #include "seascene.h"
24 #include "octopus.h"
25 #include "ship.h"
26 #include <QGraphicsPixmapItem>
27 #include <QDebug>
28 #include <QMessageBox>
29 #include <QTime>
30
31 const QString ghostImageFilename_ = ":/pix/aave.png";
32 const QString rockImageFilename_ =":/pix/kari.png";
33 const QString octopusImageFilename_= ":/pix/tursas.png";
34
35
36 SeaScene::SeaScene(QObject *parent) :
37     QGraphicsScene(parent)
38 {
39     paused_ = false;
40     screenLitKeeper_.keepScreenLit(true);
41
42     //set background
43
44     QPixmap waves (":/pix/meri.png");
45     waves.scaled(20,20);
46     setBackgroundBrush(QBrush(waves));
47
48     //set random seed
49
50     qsrand(QTime::currentTime().msec()+2);  //+2 to avoid setting it to 1
51
52
53
54 }
55
56 void SeaScene::setupMap(int ghosts, int rocks, int octopuses, int octopusSpeed)
57 {
58     //empty the map
59
60     clear();
61
62     //empty the list of moving items
63
64     movingItems_.clear();
65
66     //empty the list of free slots
67     freeTiles_.clear();
68
69     //fill the list of free slots
70
71     int numberOfXTiles  = width() / 40;
72     int numberOfYTiles = height() /40;
73
74 //    qDebug() << numberOfXTiles << " slots in x direction";
75 //    qDebug() << numberOfYTiles << " slots in y rirection";
76
77     for (int i = 0; i < numberOfXTiles; i++ )
78     {
79         for (int j = 0; j < numberOfYTiles; j++)
80         {
81             freeTiles_.append(QPointF(i*40,j*40));
82         }
83     }
84
85
86     //spread the rocks
87
88     for (int i = 0; i < rocks; i++)
89     {
90         QPointF * pPosition = findRandomFreeSlot();
91
92         //If there was no room no point to continue
93         if (pPosition == NULL)
94             break;
95
96         QPixmap rockPixmap (":/pix/kari.png");
97         QGraphicsPixmapItem * pRock = addPixmap(rockPixmap);
98         pRock->setData(0,"rock");
99         pRock->setPos(*pPosition);
100         delete pPosition;
101
102     }
103
104     //spread the ghosts
105
106     ghostsLeft_ = ghosts;
107     spreadGhosts(ghosts);
108
109
110
111     //spread the octopuses
112
113     QList <Octopus*> octopusList;
114
115     for (int i=0; i < octopuses; i++)
116     {
117         QPointF * pPosition = findRandomFreeSlot();
118
119         //If there was no room no point to continue
120         if (pPosition == NULL)
121             break;
122
123     QPixmap octopusPixmap (":/pix/tursas.png");
124     Octopus * pOctopus = new Octopus(octopusPixmap,octopusSpeed);
125     pOctopus->setData(0,"octopus");
126     pOctopus->setPos(*pPosition);
127     addItem(pOctopus);
128     pOctopus->startMoving();
129     movingItems_.append(pOctopus);
130     connect(this,SIGNAL(pauseOn()),pOctopus,SLOT(stopMoving()));
131     connect(this,SIGNAL(pauseOff()),pOctopus,SLOT(startMoving()));
132     octopusList.append(pOctopus);
133     delete pPosition;
134
135     }
136
137
138     //place the ship
139
140     QPointF * pPosition = findRandomFreeSlot();
141     if (pPosition == NULL)
142     {
143         // Game cannot begin without a free position for ship, so give an error message and return
144
145         QMessageBox::critical(NULL,"Error! Too many objects on screen","No free space to place the ship. The game cannot start. Please choose another level.");
146         return;
147     }
148
149     QList<QPixmap> shipImages;
150     shipImages.append(QPixmap(":/pix/laiva.png"));
151     shipImages.append(QPixmap(":/pix/laiva_1aave.png"));
152     shipImages.append(QPixmap(":/pix/laiva_2aave.png"));
153     shipImages.append(QPixmap(":/pix/laiva_3aave.png"));
154     shipImages.append(QPixmap(":/pix/laiva_4aave.png"));
155     shipImages.append(QPixmap(":/pix/laiva_5aave.png"));
156     shipImages.append(QPixmap(":/pix/laiva_6aave.png"));
157     shipImages.append(QPixmap(":/pix/laiva_7aave.png"));
158     shipImages.append(QPixmap(":/pix/laiva_8aave.png"));
159     shipImages.append(QPixmap(":/pix/laiva_9aave.png"));
160     shipImages.append(QPixmap(":/pix/laiva_10aave.png"));
161
162     Ship * pShip = new Ship (shipImages);
163     pShip->setData(0,"ship");
164     pShip->setPos(*pPosition);
165     addItem(pShip);
166     connect(pShip,SIGNAL(pickingGhost(QGraphicsItem*)),this, SLOT(removeGhost(QGraphicsItem*)) );
167     connect(pShip,SIGNAL(droppingGhosts(int)),this,SLOT(ghostsDropped(int)));
168     pShip->startMoving();
169     movingItems_.append(pShip);
170     connect(this,SIGNAL(pauseOn()),pShip,SLOT(stopMoving()));
171     connect(this,SIGNAL(pauseOff()),pShip,SLOT(startMoving()));
172     foreach (Octopus* pOctopus, octopusList)
173     {
174         connect(pOctopus,SIGNAL(droppingGhosts()),pShip,SLOT(dropAllGhosts()));
175     }
176     delete pPosition;
177 }
178
179 void SeaScene::setupMap(Level level)
180 {
181     setupMap(level.getNumberOfGhosts(),level.getNumberOfRocks(),level.getNumberOfOctopuses(),level.getOctopusSpeed());
182 }
183
184 void SeaScene::spreadGhosts(int ghosts)
185 {
186
187
188     //the octopuses and the ship may have moved from their original positions,
189     //so the list of free slots must be adjusted to exclude their current positions
190
191     QList<QPointF> temporarilyReservedSlots;
192
193     foreach (QGraphicsItem* pItem, movingItems_)
194     {
195         if (pItem == NULL)
196         {
197  //           qDebug() << "NULL item in movingItems_";
198             continue;
199         }
200
201         //round x and y down to fit the slot size
202         int x = pItem->x();
203         x = x/40;
204         x = x*40;
205
206         int y = pItem->y();
207         y = y/40;
208         y=y*40;
209
210
211         QPointF position (x,y);
212
213         //remove the tiles (potentially) occupied by the item from free slots and place in temp list if was in the list before
214
215         if (freeTiles_.removeOne(position))
216             temporarilyReservedSlots.append(position);
217
218
219         position.setX(x+40);
220
221         if (freeTiles_.removeOne(position))
222             temporarilyReservedSlots.append(position);
223
224         position.setY(y+40);
225
226         if (freeTiles_.removeOne(position))
227             temporarilyReservedSlots.append(position);
228
229         position.setX(x);
230
231         if (freeTiles_.removeOne(position))
232             temporarilyReservedSlots.append(position);
233
234     }
235
236
237     //spread ghosts in random free slots
238
239     for (int i=0; i < ghosts; i++)
240     {
241         QPointF * pPosition = findRandomFreeSlot();
242
243         //If there was no room no point to continue
244         if (pPosition == NULL)
245             return;
246
247         QPixmap ghostPixmap(":/pix/aave.png");
248         QGraphicsPixmapItem * pGhost = addPixmap(ghostPixmap);
249         pGhost->setData(0,"ghost");
250         pGhost->setPos(*pPosition);
251         delete pPosition;
252     }
253
254     //return the slots occupied by moving items to free slots
255     freeTiles_.append(temporarilyReservedSlots);
256
257     //clear temp for the next round
258     temporarilyReservedSlots.clear();
259 }
260
261 QPointF* SeaScene::findRandomFreeSlot()
262 {
263     if (freeTiles_.isEmpty())
264         return NULL;
265
266     int index = qrand()%freeTiles_.size();
267
268 //    qDebug()  << index << " index";
269     return new QPointF (freeTiles_.takeAt(index));
270
271 }
272
273 void SeaScene::removeGhost(QGraphicsItem *pGhost)
274 {
275     removeItem(pGhost);  //remove the item from scene
276     freeTiles_.append(pGhost->scenePos()); //add the item's position to free slots
277     delete pGhost;
278     ghostsLeft_--;
279     if (ghostsLeft_ == 0)
280     {
281         emit allGhostsPicked();
282  //       qDebug() << "All ghosts picked!";
283     }
284 }
285
286 void SeaScene::ghostsDropped(int ghosts)
287 {
288     ghostsLeft_ += ghosts;
289
290     spreadGhosts(ghosts);
291 }
292
293 void SeaScene::pause(bool paused)
294 {
295     //    qDebug() << "pause pressed " << paused;
296         if (paused_ == paused)
297                 return;
298
299         paused_ = paused;
300
301         if (paused == false)
302         {
303      //       qDebug() << "starting to move again";
304             emit pauseOff();
305             screenLitKeeper_.keepScreenLit(true);
306         }
307
308         else
309         {
310      //       qDebug("about to stop movement");
311             emit pauseOn();
312             screenLitKeeper_.keepScreenLit(false);
313         }
314 }