Corrected collition with bag of money
[supertux.git] / src / badguy.c
1 //
2 // C Implementation: badguy
3 //
4 // Description:
5 //
6 //
7 // Author: Tobias Glaesser <tobi.web@gmx.de> & Bill Kendrick, (C) 2004
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12
13 #include "globals.h"
14 #include "defines.h"
15 #include "badguy.h"
16 #include "scene.h"
17 #include "screen.h"
18
19 texture_type img_bsod_squished_left, img_bsod_squished_right,
20 img_bsod_falling_left, img_bsod_falling_right,
21 img_laptop_flat_left, img_laptop_flat_right,
22 img_laptop_falling_left, img_laptop_falling_right;
23 texture_type img_bsod_left[4], img_bsod_right[4],
24 img_laptop_left[3], img_laptop_right[3],
25 img_money_left[2], img_money_right[2];
26 bitmask *bm_bsod;
27
28 void badguy_create_bitmasks()
29 {
30   /*bm_bsod = img_bsod_left[0];*/
31 }
32
33 void badguy_init(bad_guy_type* pbad, float x, float y, int kind)
34 {
35   pbad->base.width = 32;
36   pbad->base.height = 32;
37   pbad->base.alive = YES;
38   pbad->mode = NORMAL;
39   pbad->dying = NO;
40   pbad->kind = kind;
41   pbad->base.x = x;
42   pbad->base.y = y;
43   pbad->base.xm = 1.3;
44   pbad->base.ym = 4.8;
45   pbad->dir = LEFT;
46   pbad->seen = NO;
47   timer_init(&pbad->timer);
48   physic_init(&pbad->physic);
49 }
50
51 void badguy_action(bad_guy_type* pbad)
52 {
53
54   if (pbad->base.alive)
55     {
56       if (pbad->seen)
57         {
58           if (pbad->kind == BAD_BSOD)
59             {
60               /* --- BLUE SCREEN OF DEATH MONSTER: --- */
61
62               /* Move left/right: */
63
64               if (pbad->dying == NO ||
65                   pbad->dying == FALLING)
66                 {
67                   if (pbad->dir == RIGHT)
68                     pbad->base.x = pbad->base.x + pbad->base.xm * frame_ratio;
69                   else if (pbad->dir == LEFT)
70                     pbad->base.x = pbad->base.x - pbad->base.xm * frame_ratio;
71                 }
72
73
74               /* Move vertically: */
75
76               pbad->base.y = pbad->base.y + pbad->base.ym * frame_ratio;
77
78
79               /* Bump into things horizontally: */
80
81               if (!pbad->dying)
82                 {
83                   if (issolid( pbad->base.x - 1, (int) pbad->base.y))
84                     {
85                       pbad->dir = RIGHT;
86                     }
87                   else if (issolid( pbad->base.x + pbad->base.width-1, (int) pbad->base.y))
88                     {
89                       pbad->dir = LEFT;
90                     }
91                 }
92
93  /* Fall if we get off the ground: */
94
95               if (pbad->dying != FALLING)
96                 {
97                   if (!issolid(pbad->base.x+16, pbad->base.y + 32))
98                     {
99                       if(!physic_is_set(&pbad->physic))
100                         {
101                           physic_set_state(&pbad->physic,PH_VT);
102                           physic_set_start_vy(&pbad->physic,2.);
103                         }
104
105                           pbad->base.ym = physic_get_velocity(&pbad->physic);
106                     }
107                   else
108                     {
109                       /* Land: */
110
111                       if (pbad->base.ym > 0)
112                         {
113                           pbad->base.y = (int)(pbad->base.y / 32) * 32;
114                           pbad->base.ym = 0;
115                         }
116                       physic_init(&pbad->physic);
117                     }
118                 }
119               else
120                 {
121                   if(!physic_is_set(&pbad->physic))
122                     {
123                       physic_set_state(&pbad->physic,PH_VT);
124                       physic_set_start_vy(&pbad->physic,2.);
125                     }
126                   pbad->base.ym = physic_get_velocity(&pbad->physic);
127                 }
128
129               if (pbad->base.y > screen->h)
130                 pbad->base.alive = NO;
131             }
132           else if (pbad->kind == BAD_LAPTOP)
133             {
134               /* --- LAPTOP MONSTER: --- */
135
136               /* Move left/right: */
137
138               if (pbad->mode != KICK && pbad->mode != HELD)
139                 {
140                   if (pbad->dying == NO ||
141                       pbad->dying == FALLING)
142                     {
143                       if (pbad->dir == RIGHT)
144                         pbad->base.x = pbad->base.x + pbad->base.xm * frame_ratio;
145                       else if (pbad->dir == LEFT)
146                         pbad->base.x = pbad->base.x - pbad->base.xm * frame_ratio;
147                     }
148                 }
149               else if (pbad->mode == KICK)
150                 {
151                   /* Obsolete
152                                   if (pbad->dir == RIGHT)
153                                     pbad->base.x = pbad->base.x + 16;
154                                   else if (pbad->dir == LEFT)
155                                     pbad->base.x = pbad->base.x - 16;*/
156                 }
157               else if (pbad->mode == HELD)
158                 { /* FIXME: The pbad object shouldn't know about pplayer objects. */
159                   /* If we're holding the laptop */
160                   if(tux.dir==RIGHT)
161                     {
162                       pbad->base.x = tux.base.x - 16;
163                       pbad->base.y = tux.base.y - 8 - (tux.size*16);
164                     }
165                   else /* facing left */
166                     {
167                       pbad->base.x = tux.base.x - 16;
168                       pbad->base.y = tux.base.y - 8 - (tux.size*16);
169                     }
170
171                   if(tux.input.fire != DOWN) /* SHOOT! */
172                     {
173                       pbad->dir=tux.dir;
174                       pbad->mode=KICK;
175                       pbad->base.ym-=8;
176                       play_sound(sounds[SND_KICK],SOUND_CENTER_SPEAKER);
177                     }
178                 }
179
180
181               /* Move vertically: */
182
183               if(pbad->mode != HELD)
184                 pbad->base.y = pbad->base.y + pbad->base.ym * frame_ratio;
185
186               /* Bump into things horizontally: */
187
188               /* Bump into things horizontally: */
189
190               if (!pbad->dying)
191                 {
192                   int changed = pbad->dir;
193                   if (issolid( pbad->base.x - 1, (int) pbad->base.y + 16))
194                     {
195                       pbad->dir = RIGHT;
196                     }
197                   else if (issolid( pbad->base.x + pbad->base.width-1, (int) pbad->base.y + 16))
198                     {
199                       pbad->dir = LEFT;
200                     }
201                   if(pbad->mode == KICK && changed != pbad->dir)
202                     {
203                       /* handle stereo sound */
204                       /* FIXME: In theory a badguy object doesn't know anything about player objects */
205                       if (tux.base.x  > pbad->base.x)
206                         play_sound(sounds[SND_RICOCHET], SOUND_LEFT_SPEAKER);
207                       else if (tux.base.x  < pbad->base.x)
208                         play_sound(sounds[SND_RICOCHET], SOUND_RIGHT_SPEAKER);
209                       else
210                         play_sound(sounds[SND_RICOCHET], SOUND_CENTER_SPEAKER);
211                     }
212
213                 }
214
215
216               /* Fall if we get off the ground: */
217
218               if (pbad->dying != FALLING)
219                 {
220                   if (!issolid(pbad->base.x+16, pbad->base.y + 32))
221                     {
222                       if(!physic_is_set(&pbad->physic))
223                         {
224                           physic_set_state(&pbad->physic,PH_VT);
225                           physic_set_start_vy(&pbad->physic,0.);
226                         }
227
228                       if(pbad->mode != HELD)
229                         {
230                           pbad->base.ym = physic_get_velocity(&pbad->physic);
231                         }
232                     }
233                   else
234                     {
235                       /* Land: */
236
237                       if (pbad->base.ym > 0)
238                         {
239                           pbad->base.y = (int)(pbad->base.y / 32) * 32;
240                           pbad->base.ym = 0;
241                         }
242                       physic_init(&pbad->physic);
243                     }
244                 }
245               else
246                 {
247                   if(!physic_is_set(&pbad->physic))
248                     {
249                       physic_set_state(&pbad->physic,PH_VT);
250                       physic_set_start_vy(&pbad->physic,0.);
251                     }
252                   pbad->base.ym = physic_get_velocity(&pbad->physic);
253                 }
254
255               if (pbad->base.y > screen->h)
256                 pbad->base.alive = NO;
257             }
258           else if (pbad->kind == BAD_MONEY)
259             {
260               /* --- MONEY BAGS: --- */
261
262
263               /* Move vertically: */
264
265               pbad->base.y = pbad->base.y + pbad->base.ym * frame_ratio;
266
267               if(physic_get_state(&pbad->physic) == -1)
268                 {
269                   physic_set_state(&pbad->physic,PH_VT);
270                   physic_set_start_vy(&pbad->physic,0.);
271                 }
272
273               if(issolid(pbad->base.x, pbad->base.y + 32))
274                 {
275                   physic_set_state(&pbad->physic,PH_VT);
276                   physic_set_start_vy(&pbad->physic,6.);
277                   pbad->base.ym = physic_get_velocity(&pbad->physic);
278                 }
279               else if(issolid(pbad->base.x, pbad->base.y - 1))
280                 { /* This works, but isn't the best solution imagineable */
281                   physic_set_state(&pbad->physic,PH_VT);
282                   physic_set_start_vy(&pbad->physic,0.);
283                   pbad->base.ym = physic_get_velocity(&pbad->physic);
284                 }
285               else
286                 {
287                   pbad->base.ym = physic_get_velocity(&pbad->physic);
288                 }
289
290               if (pbad->base.y > screen->h)
291                 pbad->base.alive = NO;
292             }
293           else if (pbad->kind == -1)
294           {}
295
296         }
297       else if (pbad->kind == -1)
298       {}
299
300
301     }
302
303   /* Handle mode timer: */
304
305   if (pbad->mode == FLAT /* && bad_guys[1].mode != HELD*/)
306     {
307       if(!timer_check(&pbad->timer))
308         pbad->mode = NORMAL;
309     }
310   /* else if (pbad->mode == KICK)
311      {
312        if (pbad->timer > 0)
313          pbad->timer--;
314      }*/
315
316
317   /* Handle dying timer: */
318
319   if (pbad->dying == SQUISHED)
320     {
321       /* Remove it if time's up: */
322       if(!timer_check(&pbad->timer))
323         pbad->base.alive = NO;
324     }
325
326
327   /* Remove if it's far off the screen: */
328
329   if (pbad->base.x < scroll_x - OFFSCREEN_DISTANCE)
330     pbad->base.alive = NO;
331   else /* !seen */
332     {
333       /* Once it's on screen, it's activated! */
334
335       if (pbad->base.x <= scroll_x + screen->w + OFFSCREEN_DISTANCE)
336         pbad->seen = YES;
337     }
338   /*}*/
339 }
340
341 void badguy_draw(bad_guy_type* pbad)
342 {
343   if (pbad->base.alive &&
344       pbad->base.x > scroll_x - 32 &&
345       pbad->base.x < scroll_x + screen->w)
346     {
347       if (pbad->kind == BAD_BSOD)
348         {
349           /* --- BLUE SCREEN OF DEATH MONSTER: --- */
350
351           if (pbad->dying == NO)
352             {
353               /* Alive: */
354
355               if (pbad->dir == LEFT)
356                 {
357                   texture_draw(&img_bsod_left[(frame / 5) % 4],
358                                pbad->base.x - scroll_x,
359                                pbad->base.y,
360                                NO_UPDATE);
361                 }
362               else
363                 {
364                   texture_draw(&img_bsod_right[(frame / 5) % 4],
365                                pbad->base.x - scroll_x,
366                                pbad->base.y,
367                                NO_UPDATE);
368                 }
369             }
370           else if (pbad->dying == FALLING)
371             {
372               /* Falling: */
373
374               if (pbad->dir == LEFT)
375                 {
376                   texture_draw(&img_bsod_falling_left,
377                                pbad->base.x - scroll_x,
378                                pbad->base.y,
379                                NO_UPDATE);
380                 }
381               else
382                 {
383                   texture_draw(&img_bsod_falling_right,
384                                pbad->base.x - scroll_x,
385                                pbad->base.y,
386                                NO_UPDATE);
387                 }
388             }
389           else if (pbad->dying == SQUISHED)
390             {
391               /* Dying - Squished: */
392
393               if (pbad->dir == LEFT)
394                 {
395                   texture_draw(&img_bsod_squished_left,
396                                pbad->base.x - scroll_x,
397                                pbad->base.y + 24,
398                                NO_UPDATE);
399                 }
400               else
401                 {
402                   texture_draw(&img_bsod_squished_right,
403                                pbad->base.x - scroll_x,
404                                pbad->base.y + 24,
405                                NO_UPDATE);
406                 }
407             }
408         }
409       else if (pbad->kind == BAD_LAPTOP)
410         {
411           /* --- LAPTOP MONSTER: --- */
412
413           if (pbad->dying == NO)
414             {
415               /* Alive: */
416
417               if (pbad->mode == NORMAL)
418                 {
419                   /* Not flat: */
420
421                   if (pbad->dir == LEFT)
422                     {
423                       texture_draw(&img_laptop_left[(frame / 5) % 3],
424                                    pbad->base.x - scroll_x,
425                                    pbad->base.y,
426                                    NO_UPDATE);
427                     }
428                   else
429                     {
430                       texture_draw(&img_laptop_right[(frame / 5) % 3],
431                                    pbad->base.x - scroll_x,
432                                    pbad->base.y,
433                                    NO_UPDATE);
434                     }
435                 }
436               else
437                 {
438                   /* Flat: */
439
440                   if (pbad->dir == LEFT)
441                     {
442                       texture_draw(&img_laptop_flat_left,
443                                    pbad->base.x - scroll_x,
444                                    pbad->base.y,
445                                    NO_UPDATE);
446                     }
447                   else
448                     {
449                       texture_draw(&img_laptop_flat_right,
450                                    pbad->base.x - scroll_x,
451                                    pbad->base.y,
452                                    NO_UPDATE);
453                     }
454                 }
455             }
456           else if (pbad->dying == FALLING)
457             {
458               /* Falling: */
459
460               if (pbad->dir == LEFT)
461                 {
462                   texture_draw(&img_laptop_falling_left,
463                                pbad->base.x - scroll_x,
464                                pbad->base.y,
465                                NO_UPDATE);
466                 }
467               else
468                 {
469                   texture_draw(&img_laptop_falling_right,
470                                pbad->base.x - scroll_x,
471                                pbad->base.y,
472                                NO_UPDATE);
473                 }
474             }
475         }
476       else if (pbad->kind == BAD_MONEY)
477         {
478           if (pbad->base.ym != 300 /* > -16*/)
479             {
480               if (pbad->dir == LEFT)
481                 {
482                   texture_draw(&img_money_left[0],
483                                pbad->base.x - scroll_x,
484                                pbad->base.y,
485                                NO_UPDATE);
486                 }
487               else
488                 {
489                   texture_draw(&img_money_right[0],
490                                pbad->base.x - scroll_x,
491                                pbad->base.y,
492                                NO_UPDATE);
493                 }
494             }
495           else
496             {
497               if (pbad->dir == LEFT)
498                 {
499                   texture_draw(&img_money_left[1],
500                                pbad->base.x - scroll_x,
501                                pbad->base.y,
502                                NO_UPDATE);
503                 }
504               else
505                 {
506                   texture_draw(&img_money_right[1],
507                                pbad->base.x - scroll_x,
508                                pbad->base.y,
509                                NO_UPDATE);
510                 }
511             }
512         }
513       else if (pbad->kind == -1)
514       {}
515     }
516 }
517
518 void badguy_collision(bad_guy_type* pbad, void *p_c_object, int c_object)
519 {
520   bad_guy_type* pbad_c = NULL;
521   player_type* pplayer_c = NULL;
522
523   switch (c_object)
524     {
525     case CO_BULLET:
526       pbad->dying = FALLING;
527       pbad->base.ym = -8;
528
529       /* Gain some points: */
530
531       if (pbad->kind == BAD_BSOD)
532         add_score(pbad->base.x - scroll_x, pbad->base.y,
533                   50 * score_multiplier);
534       else if (pbad->kind == BAD_LAPTOP)
535         add_score(pbad->base.x - scroll_x, pbad->base.y,
536                   25 * score_multiplier);
537
538       /* Play death sound: */
539       play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
540       break;
541     case CO_BADGUY:
542       pbad_c = (bad_guy_type*) p_c_object;
543       if (pbad->mode != FLAT)
544         pbad->dir = !pbad->dir;
545       else
546         {
547           /* We're in kick mode, kill the other guy: */
548
549           pbad_c->dying = FALLING;
550           pbad_c->base.ym = -8;
551           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
552
553           add_score(pbad->base.x - scroll_x,
554                     pbad->base.y, 100);
555         }
556       pbad->dir = !pbad->dir;
557       break;
558     case CO_PLAYER:
559       pplayer_c = (player_type*) p_c_object;
560       if (pbad->kind == BAD_BSOD)
561         {
562           pbad->dying = SQUISHED;
563           timer_start(&pbad->timer,4000);
564           pplayer_c->base.ym = -KILL_BOUNCE_YM;
565
566           add_score(pbad->base.x - scroll_x, pbad->base.y,
567                     50 * score_multiplier);
568
569           play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
570         }
571       else if (pbad->kind == BAD_LAPTOP)
572         {
573           if (pbad->mode != KICK)
574             {
575               /* Flatten! */
576
577               play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
578               pbad->mode = FLAT;
579               pbad->base.xm = 4;
580
581               timer_start(&pbad->timer,10000);
582
583               pplayer_c->base.y = pplayer_c->base.y - 32;
584             }
585           else
586             {
587               /* Kick! */
588
589               pbad->mode = KICK;
590               play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
591
592               if (pplayer_c->base.x <= pbad->base.x)
593                 pbad->dir = RIGHT;
594               else
595                 pbad->dir = LEFT;
596
597               timer_start(&pbad->timer,5000);
598             }
599
600           pplayer_c->base.ym = -KILL_BOUNCE_YM;
601
602           add_score(pbad->base.x - scroll_x,
603                     pbad->base.y,
604                     25 * score_multiplier);
605
606           /* play_sound(sounds[SND_SQUISH]); */
607         }
608       break;
609     }
610
611 }