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 "PuyoAnimations.h"
27 #include "AnimatedPuyo.h"
28 #include "PuyoView.h"
29 #include "IosImgProcess.h"
30 #include "SDL_Painter.h"
31 #include "audio.h"
32 
33 /* not clean, but basta */
34 extern SDL_Painter painter;
35 extern IIM_Surface *puyoEyes;
36 extern IIM_Surface *puyoEye[3];
37 extern IIM_Surface *puyoEyesSwirl[4];
38 extern IIM_Surface *shrinkingPuyo[5][5];
39 extern IIM_Surface *explodingPuyo[5][5];
40 
41 /* Base class implementation */
Animation()42 Animation::Animation()
43 {
44     finishedFlag = false;
45     enabled = true;
46 }
47 
isFinished() const48 bool Animation::isFinished() const
49 {
50     return finishedFlag;
51 }
52 
isEnabled() const53 bool Animation::isEnabled() const
54 {
55     return enabled;
56 }
57 
58 
59 /* Neutral falling animation */
60 IIM_Surface *NeutralAnimation::neutral = NULL;
NeutralAnimation(AnimatedPuyo & puyo,int delay)61 NeutralAnimation::NeutralAnimation(AnimatedPuyo &puyo, int delay) : PuyoAnimation(puyo)
62 {
63     if (neutral == NULL)
64         neutral = PuyoView::getSurfaceForState(PUYO_NEUTRAL);
65 	this->X = attachedPuyo.getScreenCoordinateX();
66 	this->Y = attachedPuyo.getScreenCoordinateY();
67 	this->currentY = attachedPuyo.getAttachedView()->getScreenCoordinateY(0);
68     step = 0;
69     this->delay = delay;
70     attachedPuyo.getAttachedView()->disallowCycle();
71 }
72 
cycle()73 void NeutralAnimation::cycle()
74 {
75     if (delay >=0) {
76         delay--;
77     }
78     else {
79         currentY += (int)step;
80         step += 0.5;
81         if (currentY >= Y) {
82             audio_sound_play(sound_bim[random() % 2]);
83             finishedFlag = true;
84             attachedPuyo.getAttachedView()->allowCycle();
85         }
86     }
87 }
88 
draw(int semiMove)89 void NeutralAnimation::draw(int semiMove)
90 {
91 	SDL_Rect drect;
92 	drect.x = X;
93 	drect.y = currentY;
94 	drect.w = neutral->w;
95 	drect.h = neutral->h;
96 	painter.requestDraw(neutral, &drect);
97 }
98 
99 /* Animation synchronization helper */
AnimationSynchronizer()100 AnimationSynchronizer::AnimationSynchronizer()
101 {
102     currentCounter = 0;
103     currentUsage = 0;
104 }
105 
push()106 void AnimationSynchronizer::push()
107 {
108     currentCounter++;
109 }
110 
pop()111 void AnimationSynchronizer::pop()
112 {
113     currentCounter--;
114 }
115 
isSynchronized()116 bool AnimationSynchronizer::isSynchronized()
117 {
118     return (currentCounter <= 0);
119 }
120 
incrementUsage()121 void AnimationSynchronizer::incrementUsage()
122 {
123     currentUsage++;
124 }
125 
decrementUsage()126 void AnimationSynchronizer::decrementUsage()
127 {
128     currentUsage--;
129     if (currentUsage == 0)
130         delete this;
131 }
132 
133 /* Companion turning around main puyo animation */
TurningAnimation(AnimatedPuyo & companionPuyo,int vector,bool counterclockwise)134 TurningAnimation::TurningAnimation(AnimatedPuyo &companionPuyo, int vector,
135                                    bool counterclockwise) : PuyoAnimation(companionPuyo)
136 {
137     this->counterclockwise = counterclockwise;
138     companionVector = vector;
139     targetSurface = attachedPuyo.getAttachedView()->getSurfaceForPuyo(&attachedPuyo);
140     cpt = 0;
141     angle = 0;
142     step = (3.14 / 2) / 4;
143 }
144 
cycle()145 void TurningAnimation::cycle()
146 {
147     if (cpt == 0) {
148         audio_sound_play(sound_fff);
149     }
150     cpt++;
151     angle += step;
152     if (cpt == 4)
153         finishedFlag = true;
154 }
155 
draw(int semiMove)156 void TurningAnimation::draw(int semiMove)
157 {
158     if (targetSurface == NULL)
159         return;
160     X = attachedPuyo.getScreenCoordinateX();
161     Y = attachedPuyo.getScreenCoordinateY();
162 
163     float offsetA = sin(angle) * TSIZE;
164     float offsetB = cos(angle) * TSIZE * (counterclockwise ? -1 : 1);
165     SDL_Rect drect, drect2;
166     drect.w = targetSurface->w;
167     drect.h = targetSurface->h;
168     drect.y = -semiMove * TSIZE / 2;
169     switch (companionVector) {
170         case 0:
171             drect.x = (short)(X - offsetB);
172             drect.y += (short)(Y + offsetA - TSIZE);
173             break;
174         case 1:
175             drect.x = (short)(X - offsetA + TSIZE);
176             drect.y += (short)(Y - offsetB);
177             break;
178         case 2:
179             drect.x = (short)(X + offsetB);
180             drect.y += (short)(Y - offsetA + TSIZE);
181             break;
182         case 3:
183             drect.x = (short)(X + offsetA - TSIZE);
184             drect.y += (short)(Y + offsetB);
185             break;
186 
187         case -3:
188             drect.x = (short)(X + offsetB);
189             drect.y += (short)(Y + offsetA - TSIZE);
190             break;
191     }
192     drect2 = drect;
193     painter.requestDraw(targetSurface, &drect);
194     painter.requestDraw(puyoEyes, &drect2);
195 }
196 
197 /* Puyo falling and bouncing animation */
198 
199 const int FallingAnimation::BOUNCING_OFFSET_NUM = 12;
200 const int FallingAnimation::BOUNCING_OFFSET[] = { -1, -3, -5, -4, -2, 0, -6, -9, -11, -9, -6, 0 };
201 
FallingAnimation(AnimatedPuyo & puyo,int originY,int xOffset,int yOffset,int step)202 FallingAnimation::FallingAnimation(AnimatedPuyo &puyo, int originY, int xOffset, int yOffset, int step) : PuyoAnimation(puyo)
203 {
204     this->xOffset = xOffset;
205     this->yOffset = yOffset;
206     this->step    = 0/*step*/;
207     this->X  = (attachedPuyo.getPuyoX()*TSIZE) + xOffset;
208     this->Y  = (originY*TSIZE) + yOffset;
209     puyoFace = PuyoView::getSurfaceForState(attachedPuyo.getPuyoState());
210     bouncing = BOUNCING_OFFSET_NUM - 1;
211     if (originY == attachedPuyo.getPuyoY()) {
212         bouncing = -1;
213     }
214     attachedPuyo.getAttachedView()->disallowCycle();
215 }
216 
cycle()217 void FallingAnimation::cycle()
218 {
219     Y += step++;
220     if (Y >= (attachedPuyo.getPuyoY()*TSIZE) + yOffset)
221     {
222         bouncing--;
223         if (bouncing < 0) {
224             finishedFlag = true;
225             audio_sound_play(sound_bam1);
226             attachedPuyo.getAttachedView()->allowCycle();
227         }
228         else {
229             if (BOUNCING_OFFSET[bouncing] == 0)
230                 audio_sound_play(sound_bam1);
231         }
232         Y = (attachedPuyo.getPuyoY()*TSIZE) + yOffset;
233     }
234 }
235 
draw(int semiMove)236 void FallingAnimation::draw(int semiMove)
237 {
238     if (puyoFace) {
239         SDL_Rect drect;
240         drect.x = X;
241         drect.y = Y + (bouncing>=0?BOUNCING_OFFSET[bouncing]:0);
242         // drect.y = -semiMove() * TSIZE / 2;
243         drect.w = puyoFace->w;
244         drect.h = puyoFace->h;
245         painter.requestDraw(puyoFace, &drect);
246         if (attachedPuyo.getPuyoState() != PUYO_NEUTRAL)
247             painter.requestDraw(puyoEyesSwirl[(bouncing/2)%4], &drect);
248     }
249 }
250 
251 /* Puyo exploding and vanishing animation */
VanishAnimation(AnimatedPuyo & puyo,int delay,int xOffset,int yOffset,AnimationSynchronizer * synchronizer)252 VanishAnimation::VanishAnimation(AnimatedPuyo &puyo, int delay, int xOffset, int yOffset, AnimationSynchronizer *synchronizer) : PuyoAnimation(puyo)
253 {
254     puyoFace = PuyoView::getSurfaceForState(attachedPuyo.getPuyoState());
255     this->xOffset = xOffset;
256     this->yOffset = yOffset;
257     this->X = (attachedPuyo.getPuyoX()*TSIZE) + xOffset;
258     this->Y = (attachedPuyo.getPuyoY()*TSIZE) + yOffset;
259     this->color = attachedPuyo.getPuyoState();
260     if (color > PUYO_EMPTY)
261         color -= PUYO_BLUE;
262     iter = 0;
263     once = false;
264     enabled = false;
265     this->synchronizer = synchronizer;
266     synchronizer->incrementUsage();
267     synchronizer->push();
268     this->delay = delay;
269     attachedPuyo.getAttachedView()->disallowCycle();
270 }
271 
~VanishAnimation()272 VanishAnimation::~VanishAnimation()
273 {
274     synchronizer->decrementUsage();
275 }
276 
cycle()277 void VanishAnimation::cycle()
278 {
279     if (once == false) {
280         once = true;
281         synchronizer->pop();
282     }
283     else if (synchronizer->isSynchronized()) {
284         enabled = true;
285         iter ++;
286         if (iter == 20 + delay) {
287             attachedPuyo.getAttachedView()->allowCycle();
288         }
289         else if (iter == 50 + delay) {
290             finishedFlag = true;
291             attachedPuyo.setVisible(false);
292         }
293     }
294 }
295 
draw(int semiMove)296 void VanishAnimation::draw(int semiMove)
297 {
298     if (iter < (10 + delay)) {
299         if (puyoFace && (iter % 2 == 0)) {
300             SDL_Rect drect;
301             drect.x = X;
302             drect.y = Y;
303             drect.w = puyoFace->w;
304             drect.h = puyoFace->h;
305             painter.requestDraw(puyoFace, &drect);
306             if (color != PUYO_NEUTRAL)
307                 painter.requestDraw(puyoEyes, &drect);
308         }
309     }
310     else {
311         if (puyoFace) {
312             SDL_Rect drect, xrect;
313             drect.x = X;
314             drect.y = Y;// + (2.5 * pow(iter - 16, 2) - 108);
315                 drect.w = puyoFace->w;
316                 drect.h = puyoFace->h;
317                 int iter2 = iter - 10 - delay;
318                 int shrinkingImage = (iter - 10 - delay) / 4;
319                 if (shrinkingImage < 4) {
320                     painter.requestDraw(shrinkingPuyo[shrinkingImage][color], &drect);
321                     int xrectY = Y + (int)(2.5 * pow(iter - 16 - delay, 2) - 108);
322                     xrect.w = explodingPuyo[shrinkingImage][color]->w;
323                     xrect.h = explodingPuyo[shrinkingImage][color]->h;
324                     xrect.x = X - iter2 * iter2;
325                     xrect.y = xrectY;
326                     painter.requestDraw(explodingPuyo[shrinkingImage][color], &xrect);
327                     xrect.x = X - iter2;
328                     xrect.y = xrectY + iter2;
329                     painter.requestDraw(explodingPuyo[shrinkingImage][color], &xrect);
330                     xrect.x = X + iter2;
331                     xrect.y = xrectY + iter2;
332                     painter.requestDraw(explodingPuyo[shrinkingImage][color], &xrect);
333                     xrect.x = X + iter2 * iter2;
334                     xrect.y = xrectY;
335                     painter.requestDraw(explodingPuyo[shrinkingImage][color], &xrect);
336                 }
337         }
338     }
339 }
340 
VanishSoundAnimation(int phase,AnimationSynchronizer * synchronizer)341 VanishSoundAnimation::VanishSoundAnimation(int phase, AnimationSynchronizer *synchronizer)
342 {
343     once = false;
344     step = 0;
345     this->phase = phase;
346     this->synchronizer = synchronizer;
347     synchronizer->incrementUsage();
348     synchronizer->push();
349 }
350 
~VanishSoundAnimation()351 VanishSoundAnimation::~VanishSoundAnimation()
352 {
353     synchronizer->decrementUsage();
354 }
355 
cycle()356 void VanishSoundAnimation::cycle()
357 {
358     if (once == false) {
359         once = true;
360         synchronizer->pop();
361     }
362     else if (synchronizer->isSynchronized()) {
363         step++;
364         if (step == 1) {
365             audio_sound_play(sound_splash[phase>7?7:phase]);
366             finishedFlag = true;
367         }
368     }
369 }
370 
draw(int semiMove)371 void VanishSoundAnimation::draw(int semiMove)
372 {
373     // do nothing
374 }
375