1 /* FloboPuyo
2 * Copyright (C) 2004
3 * Florent Boudet <flobo@ios-software.com>,
4 * Jean-Christophe Hoelt <jeko@ios-software.com>,
5 * Guillaume Borios <gyom@ios-software.com>
6 *
7 * iOS Software <http://www.ios-software.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 *
24 */
25
26 #include <stdlib.h>
27 #include <math.h>
28 #include <unistd.h>
29 #include "PuyoView.h"
30 #include "PuyoAnimations.h"
31 #include "AnimatedPuyo.h"
32 #include "PuyoGame.h"
33 #include "audio.h"
34 #include "IosImgProcess.h"
35 #include "HiScores.h"
36 #include "PuyoDoomMelt.h"
37
38 #include "SDL_Painter.h"
39 SDL_Painter painter;
40
41 SDL_Surface *display;
42 IIM_Surface *background, *fallingBlue, *fallingRed, *fallingGreen, *fallingViolet, *fallingYellow, *neutral;
43 IIM_Surface *bigNeutral;
44 IIM_Surface *puyoEyes;
45 IIM_Surface *puyoFaces[5][16];
46 IIM_Surface *puyoShadow;
47
48
49
50 static char PuyoGroupImageIndex[2][2][2][2] =
51 { { // empty bottom
52 { // empty right
53 { // empty top
54 0, // empty left
55 4, // full left
56 },
57 { // full top
58 3, // empty left
59 10, // full left
60 }
61 },
62 { // full right
63 { // empty top
64 2, // empty left
65 9, // full left
66 },
67 { // full top
68 8, // empty left
69 14, // full left
70 }
71 }
72 },
73 { // full bottom
74 { // empty right
75 { // empty top
76 1, // empty left
77 7, // full left
78 },
79 { // full top
80 6, // empty left
81 13, // full left
82 }
83 },
84 { // full right
85 { // empty top
86 5, // empty left
87 12, // full left
88 },
89 { // full top
90 11, // empty left
91 15, // full left
92 }
93 }
94 }
95 };
96
97
98
PuyoView(PuyoRandomSystem * attachedRandom,int xOffset,int yOffset,int nXOffset,int nYOffset)99 PuyoView::PuyoView(PuyoRandomSystem *attachedRandom, int xOffset, int yOffset, int nXOffset, int nYOffset)
100 :attachedPuyoFactory(this), attachedPainter(painter)
101 {
102 attachedGame = new PuyoGame(attachedRandom, &attachedPuyoFactory);
103 attachedGame->setDelegate(this);
104
105 this->xOffset = xOffset;
106 this->yOffset = yOffset - TSIZE;
107 this->nXOffset = nXOffset;
108 this->nYOffset = nYOffset;
109 gameRunning = true;
110 enemyGame = NULL;
111 skippedCycle = false;
112 cycleAllowance = 0;
113 }
114
setEnemyGame(PuyoGame * enemyGame)115 void PuyoView::setEnemyGame(PuyoGame *enemyGame)
116 {
117 this->enemyGame = enemyGame;
118 }
119
getSurfaceForState(PuyoState state)120 IIM_Surface *PuyoView::getSurfaceForState(PuyoState state)
121 {
122 switch (state) {
123 case PUYO_BLUE:
124 return fallingBlue;
125 break;
126 case PUYO_RED:
127 return fallingRed;
128 break;
129 case PUYO_GREEN:
130 return fallingGreen;
131 break;
132 case PUYO_VIOLET:
133 return fallingViolet;
134 break;
135 case PUYO_YELLOW:
136 return fallingYellow;
137 break;
138 case PUYO_FALLINGBLUE:
139 return fallingBlue;
140 break;
141 case PUYO_FALLINGRED:
142 return fallingRed;
143 break;
144 case PUYO_FALLINGGREEN:
145 return fallingGreen;
146 break;
147 case PUYO_FALLINGVIOLET:
148 return fallingViolet;
149 break;
150 case PUYO_FALLINGYELLOW:
151 return fallingYellow;
152 break;
153 case PUYO_NEUTRAL:
154 return neutral;
155 break;
156 default:
157 return NULL;
158 break;
159 }
160 }
161
getSurfaceForPuyo(PuyoPuyo * puyo)162 IIM_Surface *PuyoView::getSurfaceForPuyo(PuyoPuyo *puyo)
163 {
164 int i = puyo->getPuyoX();
165 int j = puyo->getPuyoY();
166 PuyoState currentPuyoState = puyo->getPuyoState();
167 AnimatedPuyo *down = (AnimatedPuyo *)(attachedGame->getPuyoAt(i, j+1));
168 AnimatedPuyo *right = (AnimatedPuyo *)(attachedGame->getPuyoAt(i+1, j));
169 AnimatedPuyo *up = (AnimatedPuyo *)(attachedGame->getPuyoAt(i, j-1));
170 AnimatedPuyo *left = (AnimatedPuyo *)(attachedGame->getPuyoAt(i-1, j));
171
172 PuyoState downState = (down == NULL) || (down->isRenderingAnimation()) ? PUYO_EMPTY : down->getPuyoState();
173 PuyoState rightState = (right == NULL) || (right->isRenderingAnimation()) ? PUYO_EMPTY : right->getPuyoState();
174 PuyoState upState = (up == NULL) || (up->isRenderingAnimation()) ? PUYO_EMPTY : up->getPuyoState();
175 PuyoState leftState = (left == NULL) || (left->isRenderingAnimation()) ? PUYO_EMPTY : left->getPuyoState();
176
177 int currentIndex = PuyoGroupImageIndex
178 [downState == currentPuyoState ? 1 : 0]
179 [rightState == currentPuyoState ? 1 : 0]
180 [upState == currentPuyoState ? 1 : 0]
181 [leftState == currentPuyoState ? 1 : 0];
182 switch (currentPuyoState) {
183 case PUYO_VIOLET:
184 return puyoFaces[0][currentIndex];
185 case PUYO_RED:
186 return puyoFaces[1][currentIndex];
187 case PUYO_BLUE:
188 return puyoFaces[2][currentIndex];
189 case PUYO_GREEN:
190 return puyoFaces[3][currentIndex];
191 case PUYO_YELLOW:
192 return puyoFaces[4][currentIndex];
193 default:
194 return getSurfaceForState(currentPuyoState);
195 }
196 }
197
cycleAnimation()198 void PuyoView::cycleAnimation()
199 {
200 // Cycling every puyo's animation
201 for (int i = 0, j = attachedGame->getPuyoCount() ; i < j ; i++) {
202 AnimatedPuyo *currentPuyo =
203 (AnimatedPuyo *)(attachedGame->getPuyoAtIndex(i));
204 currentPuyo->cycleAnimation();
205 }
206 // Cycling dead puyo's animations
207 attachedPuyoFactory.cycleWalhalla();
208
209 // Cycling view's animations
210 if (viewAnimations.getSize() > 0) {
211 PuyoAnimation *currentAnimation = (PuyoAnimation *)(viewAnimations.getElementAt(0));
212 if (currentAnimation->isFinished()) {
213 viewAnimations.removeElementAt(0);
214 delete currentAnimation;
215 }
216 else {
217 currentAnimation->cycle();
218 }
219 }
220
221 // If there is a skipped cycle to do, do it
222 if ((skippedCycle || attachedGame->isEndOfCycle()) && attachedGame->isGameRunning() && cycleAllowed()) {
223 attachedGame->cycle();
224 skippedCycle = false;
225 }
226 }
227
cycleGame()228 void PuyoView::cycleGame()
229 {
230 // If we are not allowed to cycle the game, mark it
231 if (cycleAllowed()) {
232 skippedCycle = false;
233 attachedGame->cycle();
234 }
235 else {
236 skippedCycle = true;
237 }
238 }
239
moveLeft()240 void PuyoView::moveLeft()
241 {
242 if (cycleAllowed()) attachedGame->moveLeft();
243 }
244
moveRight()245 void PuyoView::moveRight()
246 {
247 if (cycleAllowed()) attachedGame->moveRight();
248 }
249
rotateLeft()250 void PuyoView::rotateLeft()
251 {
252 if (cycleAllowed()) attachedGame->rotate(true);
253 }
254
rotateRight()255 void PuyoView::rotateRight()
256 {
257 if (cycleAllowed()) attachedGame->rotate(false);
258 }
259
260
render()261 void PuyoView::render()
262 {
263
264 SDL_Rect drect;
265 SDL_Rect vrect;
266 vrect.x = xOffset;
267 vrect.y = yOffset;
268 vrect.w = TSIZE * PUYODIMX;
269 vrect.h = TSIZE * PUYODIMY;
270
271 bool displayFallings = this->cycleAllowed();
272
273 for (int i = 0 ; i < PUYODIMX ; i++) {
274 for (int j = 0 ; j < PUYODIMY ; j++) {
275 AnimatedPuyo *currentPuyo = (AnimatedPuyo *)(attachedGame->getPuyoAt(i, j));
276 if ((currentPuyo != NULL) && (displayFallings || !currentPuyo->isFalling()) && (getSurfaceForPuyo(currentPuyo) != neutral)
277 && (currentPuyo->getVisible()) && (currentPuyo->isRenderingAnimation() == false)) {
278 drect.x = xOffset + i * TSIZE;
279 drect.y = yOffset + j * TSIZE;
280 if (currentPuyo->getPuyoState() < PUYO_EMPTY)
281 drect.y -= attachedGame->getSemiMove() * TSIZE / 2;
282 drect.w = puyoShadow->w;
283 drect.h = puyoShadow->h;
284 if (drect.y + drect.h > vrect.y + vrect.h)
285 drect.h -= (drect.y + drect.h - vrect.y - vrect.h);
286 if (drect.x + drect.w > vrect.x + vrect.w)
287 drect.w -= (drect.x + drect.w - vrect.x - vrect.w);
288 attachedPainter.requestDraw(puyoShadow, &drect);
289 }
290 }
291 }
292 for (int i = 0, j = attachedGame->getPuyoCount() ; i < j ; i++) {
293 AnimatedPuyo *currentPuyo = (AnimatedPuyo *)(attachedGame->getPuyoAtIndex(i));
294 if (displayFallings || !currentPuyo->isFalling()) currentPuyo->render();
295 }
296 // drawing the walhalla
297 attachedPuyoFactory.renderWalhalla();
298
299 drect.x = nXOffset;
300 drect.y = nYOffset;
301 drect.w = TSIZE;
302 drect.h = TSIZE * 2;
303 // Drawing next puyos
304 IIM_Surface *currentSurface = getSurfaceForState(attachedGame->getNextFalling());
305 if (currentSurface != NULL) {
306 drect.x = nXOffset;
307 drect.y = nYOffset + TSIZE;
308 drect.w = currentSurface->w;
309 drect.h = currentSurface->h;
310 attachedPainter.requestDraw(currentSurface, &drect);
311 if (currentSurface != neutral) attachedPainter.requestDraw(puyoEyes, &drect);
312 }
313 currentSurface = getSurfaceForState(attachedGame->getNextCompanion());
314 if (currentSurface != NULL) {
315 drect.x = nXOffset;
316 drect.y = nYOffset;
317 drect.w = currentSurface->w;
318 drect.h = currentSurface->h;
319 attachedPainter.requestDraw(currentSurface, &drect);
320 if (currentSurface != neutral) attachedPainter.requestDraw(puyoEyes, &drect);
321 }
322
323 // Drawing the view animation
324 if (viewAnimations.getSize() > 0) {
325 PuyoAnimation *currentAnimation = (PuyoAnimation *)(viewAnimations.getElementAt(0));
326 if (!currentAnimation->isFinished()) {
327 currentAnimation->draw(0);
328 }
329 }
330 }
331
renderNeutral()332 void PuyoView::renderNeutral()
333 {
334 SDL_Rect drect;
335
336 // Drawing neutral puyos
337 int numBigNeutral = attachedGame->getNeutralPuyos() / PUYODIMX;
338 int numNeutral = attachedGame->getNeutralPuyos() % PUYODIMX;
339 int drect_x = xOffset;
340 int compressor = 0;
341
342 int width = numBigNeutral * bigNeutral->w + numNeutral * neutral->w;
343 if (width > TSIZE * PUYODIMX) {
344 compressor = (width - TSIZE * PUYODIMX) / (numNeutral + numBigNeutral);
345 }
346
347 for (int cpt = 0 ; cpt < numBigNeutral ; cpt++) {
348 drect.x = drect_x;
349 drect.y = yOffset + 3 + TSIZE;
350 drect.w = bigNeutral->w;
351 drect.h = bigNeutral->h;
352 attachedPainter.requestDraw(bigNeutral, &drect);
353 drect_x += bigNeutral->w - compressor;
354 }
355 for (int cpt = 0 ; cpt < numNeutral ; cpt++) {
356 drect.x = drect_x;
357 drect.y = yOffset + 3 + TSIZE;
358 drect.w = neutral->w;
359 drect.h = neutral->h;
360 attachedPainter.requestDraw(neutral, &drect);
361 drect_x += neutral->w - compressor;
362 }
363 }
364
gameDidAddNeutral(PuyoPuyo * neutralPuyo,int neutralIndex)365 void PuyoView::gameDidAddNeutral(PuyoPuyo *neutralPuyo, int neutralIndex) {
366 int x = neutralPuyo->getPuyoX();
367 int y = neutralPuyo->getPuyoY();
368 ((AnimatedPuyo *)neutralPuyo)->addAnimation(new NeutralAnimation(*((AnimatedPuyo *)neutralPuyo), neutralIndex * 4));
369 }
370
companionDidTurn(PuyoPuyo * companionPuyo,int companionVector,bool counterclockwise)371 void PuyoView::companionDidTurn(PuyoPuyo *companionPuyo, int companionVector, bool counterclockwise)
372 {
373 ((AnimatedPuyo *)companionPuyo)->addAnimation(new TurningAnimation(*(AnimatedPuyo *)companionPuyo,
374 companionVector, counterclockwise));
375 }
376
puyoDidFall(PuyoPuyo * puyo,int originX,int originY)377 void PuyoView::puyoDidFall(PuyoPuyo *puyo, int originX, int originY)
378 {
379 ((AnimatedPuyo *)puyo)->addAnimation(new FallingAnimation(*(AnimatedPuyo *)puyo, originY, xOffset, yOffset, 16));
380 }
381
puyoWillVanish(IosVector & puyoGroup,int groupNum,int phase)382 void PuyoView::puyoWillVanish(IosVector &puyoGroup, int groupNum, int phase)
383 {
384 AnimationSynchronizer *synchronizer = new AnimationSynchronizer();
385 viewAnimations.addElement(new VanishSoundAnimation(phase, synchronizer));
386 for (int i = 0, j = puyoGroup.getSize() ; i < j ; i++) {
387 AnimatedPuyo *currentPuyo = (AnimatedPuyo *)(puyoGroup.getElementAt(i));
388 currentPuyo->addAnimation(new VanishAnimation(*currentPuyo, i*2 , xOffset, yOffset, synchronizer));
389 }
390 // A revoir
391 if (groupNum == 0) {
392 if (phase>=2) {
393 audio_sound_play(sound_yahoohoo3[(int)((float)NB_YAHOOHOO3 * random()/(RAND_MAX+1.0))]);
394 }
395 if (phase==1) {
396 audio_sound_play(sound_yahoohoo2[(int)((float)NB_YAHOOHOO2 * random()/(RAND_MAX+1.0))]);
397 }
398 else {
399 audio_sound_play(sound_yahoohoo1[(int)((float)NB_YAHOOHOO1 * random()/(RAND_MAX+1.0))]);
400 }
401 }
402 }
403
gameDidEndCycle()404 void PuyoView::gameDidEndCycle()
405 {
406 if (enemyGame != NULL) {
407 if (attachedGame->getNeutralPuyos() < 0)
408 enemyGame->increaseNeutralPuyos(- attachedGame->getNeutralPuyos());
409 }
410 }
411
cycleAllowed()412 bool PuyoView::cycleAllowed()
413 {
414 if (cycleAllowance < 0)
415 return false;
416 return true;
417 }
418
419
gameLost()420 void PuyoView::gameLost()
421 {
422 gameRunning = false;
423 }
424
425
426
427
428