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