ad763e76adb9143321c5b244bcadd6784166897d
[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         pbad->dir = !pbad->dir;
573       else
574         {
575           /* We're in kick mode, kill the other guy: */
576
577           pbad_c->dying = FALLING;
578           pbad_c->base.ym = -8;
579           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
580
581           add_score(pbad->base.x - scroll_x,
582                     pbad->base.y, 100);
583         }
584       break;
585     case CO_PLAYER:
586       pplayer_c = (player_type*) p_c_object;
587       if(pbad->kind != BAD_MONEY)
588         {
589           if (pbad->kind == BAD_BSOD)
590             {
591               pbad->dying = SQUISHED;
592               timer_start(&pbad->timer,4000);
593               physic_set_state(&pplayer_c->vphysic,PH_VT);
594               physic_set_start_vy(&pplayer_c->vphysic,2.);
595
596               add_score(pbad->base.x - scroll_x, pbad->base.y,
597                         50 * score_multiplier);
598
599               play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
600             }
601           else if (pbad->kind == BAD_LAPTOP)
602             {
603
604               if (pbad->mode == NORMAL || pbad->mode == KICK)
605                 {
606                   /* Flatten! */
607
608                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
609                   pbad->mode = FLAT;
610                   pbad->base.xm = 4;
611
612                   timer_start(&pbad->timer,10000);
613
614                   physic_set_state(&pplayer_c->vphysic,PH_VT);
615                   physic_set_start_vy(&pplayer_c->vphysic,2.);
616                 }
617               else if (pbad->mode == FLAT)
618                 {
619                   /* Kick! */
620
621                   play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
622
623                   if (pplayer_c->base.x <= pbad->base.x)
624                     pbad->dir = RIGHT;
625                   else
626                     pbad->dir = LEFT;
627
628                   pbad->base.xm = 8;
629
630                   timer_start(&pbad->timer,5000);
631                 }
632
633               physic_set_state(&pplayer_c->vphysic,PH_VT);
634               physic_set_start_vy(&pplayer_c->vphysic,2.);
635
636               add_score(pbad->base.x - scroll_x,
637                         pbad->base.y,
638                         25 * score_multiplier);
639
640               /* play_sound(sounds[SND_SQUISH]); */
641             }
642           score_multiplier++;
643         }
644       break;
645     }
646
647 }