- renamed *.c to *.cxx
[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.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       {
335         pbad->mode = NORMAL;
336         pbad->base.xm = 4;
337         }
338     }
339   else if (pbad->mode == KICK)
340     {
341       timer_check(&pbad->timer);
342     }
343
344
345   /* Handle dying timer: */
346
347   if (pbad->dying == SQUISHED)
348     {
349       /* Remove it if time's up: */
350       if(!timer_check(&pbad->timer))
351         pbad->base.alive = NO;
352     }
353
354
355   /* Remove if it's far off the screen: */
356
357   if (pbad->base.x < scroll_x - OFFSCREEN_DISTANCE)
358     pbad->base.alive = NO;
359   else /* !seen */
360     {
361       /* Once it's on screen, it's activated! */
362
363       if (pbad->base.x <= scroll_x + screen->w + OFFSCREEN_DISTANCE)
364         pbad->seen = YES;
365     }
366   /*}*/
367 }
368
369 void badguy_draw(bad_guy_type* pbad)
370 {
371   if (pbad->base.alive &&
372       pbad->base.x > scroll_x - 32 &&
373       pbad->base.x < scroll_x + screen->w)
374     {
375       if (pbad->kind == BAD_BSOD)
376         {
377           /* --- BLUE SCREEN OF DEATH MONSTER: --- */
378
379           if (pbad->dying == NO)
380             {
381               /* Alive: */
382
383               if (pbad->dir == LEFT)
384                 {
385                   texture_draw(&img_bsod_left[(frame / 5) % 4],
386                                pbad->base.x - scroll_x,
387                                pbad->base.y,
388                                NO_UPDATE);
389                 }
390               else
391                 {
392                   texture_draw(&img_bsod_right[(frame / 5) % 4],
393                                pbad->base.x - scroll_x,
394                                pbad->base.y,
395                                NO_UPDATE);
396                 }
397             }
398           else if (pbad->dying == FALLING)
399             {
400               /* Falling: */
401
402               if (pbad->dir == LEFT)
403                 {
404                   texture_draw(&img_bsod_falling_left,
405                                pbad->base.x - scroll_x,
406                                pbad->base.y,
407                                NO_UPDATE);
408                 }
409               else
410                 {
411                   texture_draw(&img_bsod_falling_right,
412                                pbad->base.x - scroll_x,
413                                pbad->base.y,
414                                NO_UPDATE);
415                 }
416             }
417           else if (pbad->dying == SQUISHED)
418             {
419               /* Dying - Squished: */
420
421               if (pbad->dir == LEFT)
422                 {
423                   texture_draw(&img_bsod_squished_left,
424                                pbad->base.x - scroll_x,
425                                pbad->base.y + 24,
426                                NO_UPDATE);
427                 }
428               else
429                 {
430                   texture_draw(&img_bsod_squished_right,
431                                pbad->base.x - scroll_x,
432                                pbad->base.y + 24,
433                                NO_UPDATE);
434                 }
435             }
436         }
437       else if (pbad->kind == BAD_LAPTOP)
438         {
439           /* --- LAPTOP MONSTER: --- */
440
441           if (pbad->dying == NO)
442             {
443               /* Alive: */
444
445               if (pbad->mode == NORMAL)
446                 {
447                   /* Not flat: */
448
449                   if (pbad->dir == LEFT)
450                     {
451                       texture_draw(&img_laptop_left[(frame / 5) % 3],
452                                    pbad->base.x - scroll_x,
453                                    pbad->base.y,
454                                    NO_UPDATE);
455                     }
456                   else
457                     {
458                       texture_draw(&img_laptop_right[(frame / 5) % 3],
459                                    pbad->base.x - scroll_x,
460                                    pbad->base.y,
461                                    NO_UPDATE);
462                     }
463                 }
464               else
465                 {
466                   /* Flat: */
467
468                   if (pbad->dir == LEFT)
469                     {
470                       texture_draw(&img_laptop_flat_left,
471                                    pbad->base.x - scroll_x,
472                                    pbad->base.y,
473                                    NO_UPDATE);
474                     }
475                   else
476                     {
477                       texture_draw(&img_laptop_flat_right,
478                                    pbad->base.x - scroll_x,
479                                    pbad->base.y,
480                                    NO_UPDATE);
481                     }
482                 }
483             }
484           else if (pbad->dying == FALLING)
485             {
486               /* Falling: */
487
488               if (pbad->dir == LEFT)
489                 {
490                   texture_draw(&img_laptop_falling_left,
491                                pbad->base.x - scroll_x,
492                                pbad->base.y,
493                                NO_UPDATE);
494                 }
495               else
496                 {
497                   texture_draw(&img_laptop_falling_right,
498                                pbad->base.x - scroll_x,
499                                pbad->base.y,
500                                NO_UPDATE);
501                 }
502             }
503         }
504       else if (pbad->kind == BAD_MONEY)
505         {
506           if (pbad->base.ym != 300 /* > -16*/)
507             {
508               if (pbad->dir == LEFT)
509                 {
510                   texture_draw(&img_money_left[0],
511                                pbad->base.x - scroll_x,
512                                pbad->base.y,
513                                NO_UPDATE);
514                 }
515               else
516                 {
517                   texture_draw(&img_money_right[0],
518                                pbad->base.x - scroll_x,
519                                pbad->base.y,
520                                NO_UPDATE);
521                 }
522             }
523           else
524             {
525               if (pbad->dir == LEFT)
526                 {
527                   texture_draw(&img_money_left[1],
528                                pbad->base.x - scroll_x,
529                                pbad->base.y,
530                                NO_UPDATE);
531                 }
532               else
533                 {
534                   texture_draw(&img_money_right[1],
535                                pbad->base.x - scroll_x,
536                                pbad->base.y,
537                                NO_UPDATE);
538                 }
539             }
540         }
541       else if (pbad->kind == -1)
542       {}
543     }
544 }
545
546 void badguy_collision(bad_guy_type* pbad, void *p_c_object, int c_object)
547 {
548   bad_guy_type* pbad_c = NULL;
549   player_type* pplayer_c = NULL;
550
551   switch (c_object)
552     {
553     case CO_BULLET:
554       pbad->dying = FALLING;
555       pbad->base.ym = -8;
556
557       /* Gain some points: */
558
559       if (pbad->kind == BAD_BSOD)
560         add_score(pbad->base.x - scroll_x, pbad->base.y,
561                   50 * score_multiplier);
562       else if (pbad->kind == BAD_LAPTOP)
563         add_score(pbad->base.x - scroll_x, pbad->base.y,
564                   25 * score_multiplier);
565       else if (pbad->kind == BAD_MONEY)
566         add_score(pbad->base.x - scroll_x, pbad->base.y,
567                   50 * score_multiplier);
568
569       /* Play death sound: */
570       play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
571       break;
572     case CO_BADGUY:
573       pbad_c = (bad_guy_type*) p_c_object;
574       if (pbad->mode == NORMAL)
575       {
576       /* do nothing */
577       }
578       else if(pbad->mode == KICK)
579         {
580           /* We're in kick mode, kill the other guy
581              and yourself(wuahaha) : */
582
583           pbad_c->dying = FALLING;
584           pbad_c->base.ym = -8;
585           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
586
587           add_score(pbad->base.x - scroll_x,
588                     pbad->base.y, 100);
589                   pbad_c->dying = FALLING;
590                   
591           pbad->dying = FALLING;
592           pbad->base.ym = -8;
593
594           add_score(pbad_c->base.x - scroll_x,
595                     pbad_c->base.y, 100);
596         }
597       break;
598     case CO_PLAYER:
599       pplayer_c = (player_type*) p_c_object;
600       if(pbad->kind != BAD_MONEY)
601         {
602           if (pbad->kind == BAD_BSOD)
603             {
604               pbad->dying = SQUISHED;
605               timer_start(&pbad->timer,4000);
606               physic_set_state(&pplayer_c->vphysic,PH_VT);
607               physic_set_start_vy(&pplayer_c->vphysic,2.);
608               pplayer_c->base.y = pbad->base.y - pplayer_c->base.height - 1;
609
610               add_score(pbad->base.x - scroll_x, pbad->base.y,
611                         50 * score_multiplier);
612
613               play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
614             }
615           else if (pbad->kind == BAD_LAPTOP)
616             {
617
618               if (pbad->mode == NORMAL || pbad->mode == KICK)
619                 {
620                   /* Flatten! */
621
622                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
623                   pbad->mode = FLAT;
624                   pbad->base.xm = 4;
625
626                   timer_start(&pbad->timer,10000);
627
628                   physic_set_state(&pplayer_c->vphysic,PH_VT);
629                   physic_set_start_vy(&pplayer_c->vphysic,2.);
630                   pplayer_c->base.y = pbad->base.y - pplayer_c->base.height - 1;
631                 }
632               else if (pbad->mode == FLAT)
633                 {
634                   /* Kick! */
635                   play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
636
637                   if (pplayer_c->base.x <= pbad->base.x)
638                     pbad->dir = RIGHT;
639                   else
640                     pbad->dir = LEFT;
641
642                   pbad->base.xm = 5;
643                   pbad->mode = KICK;
644
645                   timer_start(&pbad->timer,5000);
646                 }
647                 
648               physic_set_state(&pplayer_c->vphysic,PH_VT);
649               physic_set_start_vy(&pplayer_c->vphysic,2.);
650               pplayer_c->base.y = pbad->base.y - pplayer_c->base.height - 1;
651               
652               add_score(pbad->base.x - scroll_x,
653                         pbad->base.y,
654                         25 * score_multiplier);
655
656               /* play_sound(sounds[SND_SQUISH]); */
657             }
658           score_multiplier++;
659         }
660       break;
661     }
662
663 }