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