80c5f9c393f975135cbffc34215196ded126b8ec
[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,YES);
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 + 16))
84                     {
85                       pbad->dir = RIGHT;
86                     }
87                   else if (issolid( pbad->base.x + pbad->base.width-1, (int) pbad->base.y + 16))
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 (pbad->dying != FALLING)
274                 {
275                   if(issolid(pbad->base.x, pbad->base.y + 32))
276                     {
277                       physic_set_state(&pbad->physic,PH_VT);
278                       physic_set_start_vy(&pbad->physic,6.);
279                       pbad->base.ym = physic_get_velocity(&pbad->physic);
280                     }
281                   else if(issolid(pbad->base.x, pbad->base.y - 1))
282                     { /* This works, but isn't the best solution imagineable */
283                       physic_set_state(&pbad->physic,PH_VT);
284                       physic_set_start_vy(&pbad->physic,0.);
285                       pbad->base.ym = physic_get_velocity(&pbad->physic);
286                     }
287                   else
288                     {
289                       pbad->base.ym = physic_get_velocity(&pbad->physic);
290                     }
291                 }
292               else
293                 {
294                   if(!physic_is_set(&pbad->physic))
295                     {
296                       physic_set_state(&pbad->physic,PH_VT);
297                       physic_set_start_vy(&pbad->physic,0.);
298                     }
299                   pbad->base.ym = physic_get_velocity(&pbad->physic);
300                 }
301
302               if (pbad->base.y > screen->h)
303                 pbad->base.alive = NO;
304             }
305           else if (pbad->kind == -1)
306           {}
307
308         }
309       else if (pbad->kind == -1)
310       {}
311
312
313     }
314
315   /* Handle mode timer: */
316
317   if (pbad->mode == FLAT /* && bad_guys[1].mode != HELD*/)
318     {
319       if(!timer_check(&pbad->timer))
320         pbad->mode = NORMAL;
321     }
322   /* else if (pbad->mode == KICK)
323      {
324        if (pbad->timer > 0)
325          pbad->timer--;
326      }*/
327
328
329   /* Handle dying timer: */
330
331   if (pbad->dying == SQUISHED)
332     {
333       /* Remove it if time's up: */
334       if(!timer_check(&pbad->timer))
335         pbad->base.alive = NO;
336     }
337
338
339   /* Remove if it's far off the screen: */
340
341   if (pbad->base.x < scroll_x - OFFSCREEN_DISTANCE)
342     pbad->base.alive = NO;
343   else /* !seen */
344     {
345       /* Once it's on screen, it's activated! */
346
347       if (pbad->base.x <= scroll_x + screen->w + OFFSCREEN_DISTANCE)
348         pbad->seen = YES;
349     }
350   /*}*/
351 }
352
353 void badguy_draw(bad_guy_type* pbad)
354 {
355   if (pbad->base.alive &&
356       pbad->base.x > scroll_x - 32 &&
357       pbad->base.x < scroll_x + screen->w)
358     {
359       if (pbad->kind == BAD_BSOD)
360         {
361           /* --- BLUE SCREEN OF DEATH MONSTER: --- */
362
363           if (pbad->dying == NO)
364             {
365               /* Alive: */
366
367               if (pbad->dir == LEFT)
368                 {
369                   texture_draw(&img_bsod_left[(frame / 5) % 4],
370                                pbad->base.x - scroll_x,
371                                pbad->base.y,
372                                NO_UPDATE);
373                 }
374               else
375                 {
376                   texture_draw(&img_bsod_right[(frame / 5) % 4],
377                                pbad->base.x - scroll_x,
378                                pbad->base.y,
379                                NO_UPDATE);
380                 }
381             }
382           else if (pbad->dying == FALLING)
383             {
384               /* Falling: */
385
386               if (pbad->dir == LEFT)
387                 {
388                   texture_draw(&img_bsod_falling_left,
389                                pbad->base.x - scroll_x,
390                                pbad->base.y,
391                                NO_UPDATE);
392                 }
393               else
394                 {
395                   texture_draw(&img_bsod_falling_right,
396                                pbad->base.x - scroll_x,
397                                pbad->base.y,
398                                NO_UPDATE);
399                 }
400             }
401           else if (pbad->dying == SQUISHED)
402             {
403               /* Dying - Squished: */
404
405               if (pbad->dir == LEFT)
406                 {
407                   texture_draw(&img_bsod_squished_left,
408                                pbad->base.x - scroll_x,
409                                pbad->base.y + 24,
410                                NO_UPDATE);
411                 }
412               else
413                 {
414                   texture_draw(&img_bsod_squished_right,
415                                pbad->base.x - scroll_x,
416                                pbad->base.y + 24,
417                                NO_UPDATE);
418                 }
419             }
420         }
421       else if (pbad->kind == BAD_LAPTOP)
422         {
423           /* --- LAPTOP MONSTER: --- */
424
425           if (pbad->dying == NO)
426             {
427               /* Alive: */
428
429               if (pbad->mode == NORMAL)
430                 {
431                   /* Not flat: */
432
433                   if (pbad->dir == LEFT)
434                     {
435                       texture_draw(&img_laptop_left[(frame / 5) % 3],
436                                    pbad->base.x - scroll_x,
437                                    pbad->base.y,
438                                    NO_UPDATE);
439                     }
440                   else
441                     {
442                       texture_draw(&img_laptop_right[(frame / 5) % 3],
443                                    pbad->base.x - scroll_x,
444                                    pbad->base.y,
445                                    NO_UPDATE);
446                     }
447                 }
448               else
449                 {
450                   /* Flat: */
451
452                   if (pbad->dir == LEFT)
453                     {
454                       texture_draw(&img_laptop_flat_left,
455                                    pbad->base.x - scroll_x,
456                                    pbad->base.y,
457                                    NO_UPDATE);
458                     }
459                   else
460                     {
461                       texture_draw(&img_laptop_flat_right,
462                                    pbad->base.x - scroll_x,
463                                    pbad->base.y,
464                                    NO_UPDATE);
465                     }
466                 }
467             }
468           else if (pbad->dying == FALLING)
469             {
470               /* Falling: */
471
472               if (pbad->dir == LEFT)
473                 {
474                   texture_draw(&img_laptop_falling_left,
475                                pbad->base.x - scroll_x,
476                                pbad->base.y,
477                                NO_UPDATE);
478                 }
479               else
480                 {
481                   texture_draw(&img_laptop_falling_right,
482                                pbad->base.x - scroll_x,
483                                pbad->base.y,
484                                NO_UPDATE);
485                 }
486             }
487         }
488       else if (pbad->kind == BAD_MONEY)
489         {
490           if (pbad->base.ym != 300 /* > -16*/)
491             {
492               if (pbad->dir == LEFT)
493                 {
494                   texture_draw(&img_money_left[0],
495                                pbad->base.x - scroll_x,
496                                pbad->base.y,
497                                NO_UPDATE);
498                 }
499               else
500                 {
501                   texture_draw(&img_money_right[0],
502                                pbad->base.x - scroll_x,
503                                pbad->base.y,
504                                NO_UPDATE);
505                 }
506             }
507           else
508             {
509               if (pbad->dir == LEFT)
510                 {
511                   texture_draw(&img_money_left[1],
512                                pbad->base.x - scroll_x,
513                                pbad->base.y,
514                                NO_UPDATE);
515                 }
516               else
517                 {
518                   texture_draw(&img_money_right[1],
519                                pbad->base.x - scroll_x,
520                                pbad->base.y,
521                                NO_UPDATE);
522                 }
523             }
524         }
525       else if (pbad->kind == -1)
526       {}
527     }
528 }
529
530 void badguy_collision(bad_guy_type* pbad, void *p_c_object, int c_object)
531 {
532   bad_guy_type* pbad_c = NULL;
533   player_type* pplayer_c = NULL;
534
535   switch (c_object)
536     {
537     case CO_BULLET:
538       pbad->dying = FALLING;
539       pbad->base.ym = -8;
540
541       /* Gain some points: */
542
543       if (pbad->kind == BAD_BSOD)
544         add_score(pbad->base.x - scroll_x, pbad->base.y,
545                   50 * score_multiplier);
546       else if (pbad->kind == BAD_LAPTOP)
547         add_score(pbad->base.x - scroll_x, pbad->base.y,
548                   25 * score_multiplier);
549       else if (pbad->kind == BAD_MONEY)
550         add_score(pbad->base.x - scroll_x, pbad->base.y,
551                   50 * score_multiplier);
552
553       /* Play death sound: */
554       play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
555       break;
556     case CO_BADGUY:
557       pbad_c = (bad_guy_type*) p_c_object;
558       if (pbad->mode != FLAT)
559         pbad->dir = !pbad->dir;
560       else
561         {
562           /* We're in kick mode, kill the other guy: */
563
564           pbad_c->dying = FALLING;
565           pbad_c->base.ym = -8;
566           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
567
568           add_score(pbad->base.x - scroll_x,
569                     pbad->base.y, 100);
570         }
571       pbad->dir = !pbad->dir;
572       break;
573     case CO_PLAYER:
574       pplayer_c = (player_type*) p_c_object;
575       if (pbad->kind == BAD_BSOD)
576         {
577           pbad->dying = SQUISHED;
578           timer_start(&pbad->timer,4000);
579           pplayer_c->base.ym = -KILL_BOUNCE_YM;
580
581           add_score(pbad->base.x - scroll_x, pbad->base.y,
582                     50 * score_multiplier);
583
584           play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
585         }
586       else if (pbad->kind == BAD_LAPTOP)
587         {
588           if (pbad->mode != KICK)
589             {
590               /* Flatten! */
591
592               play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
593               pbad->mode = FLAT;
594               pbad->base.xm = 4;
595
596               timer_start(&pbad->timer,10000);
597
598               pplayer_c->base.y = pplayer_c->base.y - 32;
599             }
600           else
601             {
602               /* Kick! */
603
604               pbad->mode = KICK;
605               play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
606
607               if (pplayer_c->base.x <= pbad->base.x)
608                 pbad->dir = RIGHT;
609               else
610                 pbad->dir = LEFT;
611
612               timer_start(&pbad->timer,5000);
613             }
614
615           pplayer_c->base.ym = -KILL_BOUNCE_YM;
616
617           add_score(pbad->base.x - scroll_x,
618                     pbad->base.y,
619                     25 * score_multiplier);
620
621           /* play_sound(sounds[SND_SQUISH]); */
622         }
623       break;
624     }
625
626 }