bad_guy vs. player collision fixes.
[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->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.ym-=8;
183                       play_sound(sounds[SND_KICK],SOUND_CENTER_SPEAKER);
184                     }
185                 }
186
187
188               /* Move vertically: */
189
190               if(pbad->mode != HELD)
191                 pbad->base.y = pbad->base.y + pbad->base.ym * frame_ratio;
192
193               if (pbad->dying != FALLING)
194                 collision_swept_object_map(&pbad->old_base,&pbad->base);
195               if (pbad->base.y > screen->h)
196                 pbad->base.alive = NO;
197               /* Bump into things horizontally: */
198
199               /* Bump into things horizontally: */
200
201               if (!pbad->dying)
202                 {
203                   int changed = pbad->dir;
204                   if (issolid( pbad->base.x, (int) pbad->base.y + 16))
205                     {
206                       pbad->dir = RIGHT;
207                     }
208                   else if (issolid( pbad->base.x + pbad->base.width, (int) pbad->base.y + 16))
209                     {
210                       pbad->dir = LEFT;
211                     }
212                   if(pbad->mode == KICK && changed != pbad->dir)
213                     {
214                       /* handle stereo sound */
215                       /* FIXME: In theory a badguy object doesn't know anything about player objects */
216                       if (tux.base.x  > pbad->base.x)
217                         play_sound(sounds[SND_RICOCHET], SOUND_LEFT_SPEAKER);
218                       else if (tux.base.x  < pbad->base.x)
219                         play_sound(sounds[SND_RICOCHET], SOUND_RIGHT_SPEAKER);
220                       else
221                         play_sound(sounds[SND_RICOCHET], SOUND_CENTER_SPEAKER);
222                     }
223
224                 }
225
226
227               /* Fall if we get off the ground: */
228
229               if (pbad->dying != FALLING)
230                 {
231                   if (!issolid(pbad->base.x+16, pbad->base.y + 32))
232                     {
233                       if(!physic_is_set(&pbad->physic))
234                         {
235                           physic_set_state(&pbad->physic,PH_VT);
236                           physic_set_start_vy(&pbad->physic,0.);
237                         }
238
239                       if(pbad->mode != HELD)
240                         {
241                           pbad->base.ym = physic_get_velocity(&pbad->physic);
242                         }
243                     }
244                   else
245                     {
246                       /* Land: */
247
248                       if (pbad->base.ym > 0)
249                         {
250                           pbad->base.y = (int)(pbad->base.y / 32) * 32;
251                           pbad->base.ym = 0;
252                         }
253                       physic_init(&pbad->physic);
254                     }
255                 }
256               else
257                 {
258                   if(!physic_is_set(&pbad->physic))
259                     {
260                       physic_set_state(&pbad->physic,PH_VT);
261                       physic_set_start_vy(&pbad->physic,0.);
262                     }
263                   pbad->base.ym = physic_get_velocity(&pbad->physic);
264                 }
265
266
267             }
268           else if (pbad->kind == BAD_MONEY)
269             {
270               /* --- MONEY BAGS: --- */
271
272
273               /* Move vertically: */
274
275               pbad->base.y = pbad->base.y + pbad->base.ym * frame_ratio;
276
277               if (pbad->dying != FALLING)
278                 collision_swept_object_map(&pbad->old_base,&pbad->base);
279
280               if (pbad->base.y > screen->h)
281                 pbad->base.alive = NO;
282
283               if(physic_get_state(&pbad->physic) == -1)
284                 {
285                   physic_set_state(&pbad->physic,PH_VT);
286                   physic_set_start_vy(&pbad->physic,0.);
287                 }
288
289               if (pbad->dying != FALLING)
290                 {
291                   if(issolid(pbad->base.x, pbad->base.y + 32))
292                     {
293                       physic_set_state(&pbad->physic,PH_VT);
294                       physic_set_start_vy(&pbad->physic,6.);
295                       pbad->base.ym = physic_get_velocity(&pbad->physic);
296                     }
297                   else if(issolid(pbad->base.x, pbad->base.y))
298                     { /* This works, but isn't the best solution imagineable */
299                       physic_set_state(&pbad->physic,PH_VT);
300                       physic_set_start_vy(&pbad->physic,0.);
301                       pbad->base.ym = physic_get_velocity(&pbad->physic);
302                       ++pbad->base.y;
303                     }
304                   else
305                     {
306                       pbad->base.ym = physic_get_velocity(&pbad->physic);
307                     }
308                 }
309               else
310                 {
311                   if(!physic_is_set(&pbad->physic))
312                     {
313                       physic_set_state(&pbad->physic,PH_VT);
314                       physic_set_start_vy(&pbad->physic,0.);
315                     }
316                   pbad->base.ym = physic_get_velocity(&pbad->physic);
317                 }
318             }
319           else if (pbad->kind == -1)
320           {}
321
322         }
323       else if (pbad->kind == -1)
324       {}
325
326
327     }
328
329   /* Handle mode timer: */
330
331   if (pbad->mode == FLAT && pbad->mode != HELD)
332     {
333       if(!timer_check(&pbad->timer))
334         pbad->mode = NORMAL;
335     }
336   else if (pbad->mode == KICK)
337     {
338       timer_check(&pbad->timer);
339     }
340
341
342   /* Handle dying timer: */
343
344   if (pbad->dying == SQUISHED)
345     {
346       /* Remove it if time's up: */
347       if(!timer_check(&pbad->timer))
348         pbad->base.alive = NO;
349     }
350
351
352   /* Remove if it's far off the screen: */
353
354   if (pbad->base.x < scroll_x - OFFSCREEN_DISTANCE)
355     pbad->base.alive = NO;
356   else /* !seen */
357     {
358       /* Once it's on screen, it's activated! */
359
360       if (pbad->base.x <= scroll_x + screen->w + OFFSCREEN_DISTANCE)
361         pbad->seen = YES;
362     }
363   /*}*/
364 }
365
366 void badguy_draw(bad_guy_type* pbad)
367 {
368   if (pbad->base.alive &&
369       pbad->base.x > scroll_x - 32 &&
370       pbad->base.x < scroll_x + screen->w)
371     {
372       if (pbad->kind == BAD_BSOD)
373         {
374           /* --- BLUE SCREEN OF DEATH MONSTER: --- */
375
376           if (pbad->dying == NO)
377             {
378               /* Alive: */
379
380               if (pbad->dir == LEFT)
381                 {
382                   texture_draw(&img_bsod_left[(frame / 5) % 4],
383                                pbad->base.x - scroll_x,
384                                pbad->base.y,
385                                NO_UPDATE);
386                 }
387               else
388                 {
389                   texture_draw(&img_bsod_right[(frame / 5) % 4],
390                                pbad->base.x - scroll_x,
391                                pbad->base.y,
392                                NO_UPDATE);
393                 }
394             }
395           else if (pbad->dying == FALLING)
396             {
397               /* Falling: */
398
399               if (pbad->dir == LEFT)
400                 {
401                   texture_draw(&img_bsod_falling_left,
402                                pbad->base.x - scroll_x,
403                                pbad->base.y,
404                                NO_UPDATE);
405                 }
406               else
407                 {
408                   texture_draw(&img_bsod_falling_right,
409                                pbad->base.x - scroll_x,
410                                pbad->base.y,
411                                NO_UPDATE);
412                 }
413             }
414           else if (pbad->dying == SQUISHED)
415             {
416               /* Dying - Squished: */
417
418               if (pbad->dir == LEFT)
419                 {
420                   texture_draw(&img_bsod_squished_left,
421                                pbad->base.x - scroll_x,
422                                pbad->base.y + 24,
423                                NO_UPDATE);
424                 }
425               else
426                 {
427                   texture_draw(&img_bsod_squished_right,
428                                pbad->base.x - scroll_x,
429                                pbad->base.y + 24,
430                                NO_UPDATE);
431                 }
432             }
433         }
434       else if (pbad->kind == BAD_LAPTOP)
435         {
436           /* --- LAPTOP MONSTER: --- */
437
438           if (pbad->dying == NO)
439             {
440               /* Alive: */
441
442               if (pbad->mode == NORMAL)
443                 {
444                   /* Not flat: */
445
446                   if (pbad->dir == LEFT)
447                     {
448                       texture_draw(&img_laptop_left[(frame / 5) % 3],
449                                    pbad->base.x - scroll_x,
450                                    pbad->base.y,
451                                    NO_UPDATE);
452                     }
453                   else
454                     {
455                       texture_draw(&img_laptop_right[(frame / 5) % 3],
456                                    pbad->base.x - scroll_x,
457                                    pbad->base.y,
458                                    NO_UPDATE);
459                     }
460                 }
461               else
462                 {
463                   /* Flat: */
464
465                   if (pbad->dir == LEFT)
466                     {
467                       texture_draw(&img_laptop_flat_left,
468                                    pbad->base.x - scroll_x,
469                                    pbad->base.y,
470                                    NO_UPDATE);
471                     }
472                   else
473                     {
474                       texture_draw(&img_laptop_flat_right,
475                                    pbad->base.x - scroll_x,
476                                    pbad->base.y,
477                                    NO_UPDATE);
478                     }
479                 }
480             }
481           else if (pbad->dying == FALLING)
482             {
483               /* Falling: */
484
485               if (pbad->dir == LEFT)
486                 {
487                   texture_draw(&img_laptop_falling_left,
488                                pbad->base.x - scroll_x,
489                                pbad->base.y,
490                                NO_UPDATE);
491                 }
492               else
493                 {
494                   texture_draw(&img_laptop_falling_right,
495                                pbad->base.x - scroll_x,
496                                pbad->base.y,
497                                NO_UPDATE);
498                 }
499             }
500         }
501       else if (pbad->kind == BAD_MONEY)
502         {
503           if (pbad->base.ym != 300 /* > -16*/)
504             {
505               if (pbad->dir == LEFT)
506                 {
507                   texture_draw(&img_money_left[0],
508                                pbad->base.x - scroll_x,
509                                pbad->base.y,
510                                NO_UPDATE);
511                 }
512               else
513                 {
514                   texture_draw(&img_money_right[0],
515                                pbad->base.x - scroll_x,
516                                pbad->base.y,
517                                NO_UPDATE);
518                 }
519             }
520           else
521             {
522               if (pbad->dir == LEFT)
523                 {
524                   texture_draw(&img_money_left[1],
525                                pbad->base.x - scroll_x,
526                                pbad->base.y,
527                                NO_UPDATE);
528                 }
529               else
530                 {
531                   texture_draw(&img_money_right[1],
532                                pbad->base.x - scroll_x,
533                                pbad->base.y,
534                                NO_UPDATE);
535                 }
536             }
537         }
538       else if (pbad->kind == -1)
539       {}
540     }
541 }
542
543 void badguy_collision(bad_guy_type* pbad, void *p_c_object, int c_object)
544 {
545   bad_guy_type* pbad_c = NULL;
546   player_type* pplayer_c = NULL;
547
548   switch (c_object)
549     {
550     case CO_BULLET:
551       pbad->dying = FALLING;
552       pbad->base.ym = -8;
553
554       /* Gain some points: */
555
556       if (pbad->kind == BAD_BSOD)
557         add_score(pbad->base.x - scroll_x, pbad->base.y,
558                   50 * score_multiplier);
559       else if (pbad->kind == BAD_LAPTOP)
560         add_score(pbad->base.x - scroll_x, pbad->base.y,
561                   25 * score_multiplier);
562       else if (pbad->kind == BAD_MONEY)
563         add_score(pbad->base.x - scroll_x, pbad->base.y,
564                   50 * score_multiplier);
565
566       /* Play death sound: */
567       play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
568       break;
569     case CO_BADGUY:
570       pbad_c = (bad_guy_type*) p_c_object;
571       if (pbad->mode == NORMAL)
572       {
573       /* do nothing */
574       }
575       else
576         {
577           /* We're in kick mode, kill the other guy: */
578
579           pbad_c->dying = FALLING;
580           pbad_c->base.ym = -8;
581           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
582
583           add_score(pbad->base.x - scroll_x,
584                     pbad->base.y, 100);
585         }
586       break;
587     case CO_PLAYER:
588       pplayer_c = (player_type*) p_c_object;
589       if(pbad->kind != BAD_MONEY)
590         {
591           if (pbad->kind == BAD_BSOD)
592             {
593               pbad->dying = SQUISHED;
594               timer_start(&pbad->timer,4000);
595               physic_set_state(&pplayer_c->vphysic,PH_VT);
596               physic_set_start_vy(&pplayer_c->vphysic,2.);
597               pplayer_c->base.y = pbad->base.y - pplayer_c->base.height;
598
599               add_score(pbad->base.x - scroll_x, pbad->base.y,
600                         50 * score_multiplier);
601
602               play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
603             }
604           else if (pbad->kind == BAD_LAPTOP)
605             {
606
607               if (pbad->mode == NORMAL || pbad->mode == KICK)
608                 {
609                   /* Flatten! */
610
611                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
612                   pbad->mode = FLAT;
613                   pbad->base.xm = 4;
614
615                   timer_start(&pbad->timer,10000);
616
617                   physic_set_state(&pplayer_c->vphysic,PH_VT);
618                   physic_set_start_vy(&pplayer_c->vphysic,2.);
619                   pplayer_c->base.y = pbad->base.y - pplayer_c->base.height;
620                 }
621               else if (pbad->mode == FLAT)
622                 {
623                   /* Kick! */
624
625                   play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
626
627                   if (pplayer_c->base.x <= pbad->base.x)
628                     pbad->dir = RIGHT;
629                   else
630                     pbad->dir = LEFT;
631
632                   pbad->base.xm = 8;
633
634                   timer_start(&pbad->timer,5000);
635                 }
636
637               physic_set_state(&pplayer_c->vphysic,PH_VT);
638               physic_set_start_vy(&pplayer_c->vphysic,2.);
639               pplayer_c->base.y = pbad->base.y - pplayer_c->base.height;
640               
641               add_score(pbad->base.x - scroll_x,
642                         pbad->base.y,
643                         25 * score_multiplier);
644
645               /* play_sound(sounds[SND_SQUISH]); */
646             }
647           score_multiplier++;
648         }
649       break;
650     }
651
652 }