splitted actions commands for different badguys into seperate functions
[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_bsod(bad_guy_type* pbad)
60 {
61   /* --- BLUE SCREEN OF DEATH MONSTER: --- */
62
63   /* Move left/right: */
64   if (pbad->dying == DYING_NOT ||
65       pbad->dying == DYING_FALLING)
66     {
67       if (pbad->dir == RIGHT)
68         pbad->base.x = pbad->base.x + pbad->base.xm * frame_ratio;
69       else if (pbad->dir == LEFT)
70         pbad->base.x = pbad->base.x - pbad->base.xm * frame_ratio;
71     }
72
73
74   /* Move vertically: */
75
76   pbad->base.y = pbad->base.y + pbad->base.ym * frame_ratio;
77
78   if (pbad->dying != DYING_FALLING)
79     collision_swept_object_map(&pbad->old_base,&pbad->base);
80   if (pbad->base.y > screen->h)
81     bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(pbad));
82                 
83   /* Bump into things horizontally: */
84
85   if (!pbad->dying)
86     {
87       if (issolid( pbad->base.x, (int) pbad->base.y + 16))
88         {
89           pbad->dir = RIGHT;
90         }
91       else if (issolid( pbad->base.x + pbad->base.width, (int) pbad->base.y + 16))
92         {
93           pbad->dir = LEFT;
94         }
95     }
96
97   /* Fall if we get off the ground: */
98
99   if (pbad->dying != DYING_FALLING)
100     {
101       if (!issolid(pbad->base.x+16, pbad->base.y + 32))
102         {
103           if(!physic_is_set(&pbad->physic))
104             {
105               physic_set_state(&pbad->physic,PH_VT);
106               physic_set_start_vy(&pbad->physic,2.);
107             }
108
109           pbad->base.ym = physic_get_velocity(&pbad->physic);
110         }
111       else
112         {
113           /* Land: */
114
115           if (pbad->base.ym > 0)
116             {
117               pbad->base.y = (int)(pbad->base.y / 32) * 32;
118               pbad->base.ym = 0;
119             }
120           physic_init(&pbad->physic);
121         }
122     }
123   else
124     {
125       if(!physic_is_set(&pbad->physic))
126         {
127           physic_set_state(&pbad->physic,PH_VT);
128           physic_set_start_vy(&pbad->physic,2.);
129         }
130       pbad->base.ym = physic_get_velocity(&pbad->physic);
131     }
132
133   if (pbad->base.y > screen->h)
134     bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(pbad));
135 }
136
137 void badguy_action_laptop(bad_guy_type* pbad)
138 {
139   /* --- LAPTOP MONSTER: --- */
140
141   /* Move left/right: */
142
143   if (pbad->mode == NORMAL || pbad->mode == KICK)
144     {
145       if (pbad->dying == DYING_NOT ||
146           pbad->dying == 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 != DYING_FALLING)
195     collision_swept_object_map(&pbad->old_base,&pbad->base);
196   if (pbad->base.y > screen->h)
197     bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(pbad));
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 != 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 void badguy_action_money(bad_guy_type* pbad)
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 != DYING_FALLING)
278     collision_swept_object_map(&pbad->old_base,&pbad->base);
279
280   if (pbad->base.y > screen->h)
281     bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(pbad));
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 != 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
320 void badguy_action(bad_guy_type* pbad)
321
322   if (pbad->seen)
323     {
324       switch (pbad->kind)
325         {
326         case BAD_BSOD:
327           badguy_action_bsod(pbad);
328           break;
329     
330         case BAD_LAPTOP:
331           badguy_action_bsod(pbad);
332           break;
333       
334         case BAD_MONEY:
335           badguy_action_money(pbad);
336           break;
337         }
338     }
339
340   /* Handle mode timer: */
341   if (pbad->mode == FLAT && pbad->mode != HELD)
342     {
343       if(!timer_check(&pbad->timer))
344         {
345           pbad->mode = NORMAL;
346           pbad->base.xm = 4;
347         }
348     }
349   else if (pbad->mode == KICK)
350     {
351       timer_check(&pbad->timer);
352     }
353
354   // Handle dying timer:
355   if (pbad->dying == DYING_SQUISHED)
356     {
357       /* Remove it if time's up: */
358       if(!timer_check(&pbad->timer))
359         bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(pbad));
360     }
361
362   // Remove if it's far off the screen:
363   if (pbad->base.x < scroll_x - OFFSCREEN_DISTANCE)
364     {
365       bad_guys.erase(static_cast<std::vector<bad_guy_type>::iterator>(pbad));
366       return;
367     }
368   else /* !seen */
369     {
370       // Once it's on screen, it's activated!
371       if (pbad->base.x <= scroll_x + screen->w + OFFSCREEN_DISTANCE)
372         pbad->seen = true;
373     }
374 }
375
376 void badguy_draw_bsod(bad_guy_type* pbad)
377 {
378   /* --- BLUE SCREEN OF DEATH MONSTER: --- */
379   if (pbad->dying == DYING_NOT)
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         }
389       else
390         {
391           texture_draw(&img_bsod_right[(frame / 5) % 4],
392                        pbad->base.x - scroll_x,
393                        pbad->base.y);
394         }
395     }
396   else if (pbad->dying == DYING_FALLING)
397     {
398       /* Falling: */
399
400       if (pbad->dir == LEFT)
401         {
402           texture_draw(&img_bsod_falling_left,
403                        pbad->base.x - scroll_x,
404                        pbad->base.y);
405         }
406       else
407         {
408           texture_draw(&img_bsod_falling_right,
409                        pbad->base.x - scroll_x,
410                        pbad->base.y);
411         }
412     }
413   else if (pbad->dying == DYING_SQUISHED)
414     {
415       /* Dying - Squished: */
416
417       if (pbad->dir == LEFT)
418         {
419           texture_draw(&img_bsod_squished_left,
420                        pbad->base.x - scroll_x,
421                        pbad->base.y + 24);
422         }
423       else
424         {
425           texture_draw(&img_bsod_squished_right,
426                        pbad->base.x - scroll_x,
427                        pbad->base.y + 24);
428         }
429     }
430 }
431
432 void badguy_draw_laptop(bad_guy_type* pbad)
433 {
434   /* --- LAPTOP MONSTER: --- */
435   if (pbad->dying == DYING_NOT)
436     {
437       /* Alive: */
438
439       if (pbad->mode == NORMAL)
440         {
441           /* Not flat: */
442
443           if (pbad->dir == LEFT)
444             {
445               texture_draw(&img_laptop_left[(frame / 5) % 3],
446                            pbad->base.x - scroll_x,
447                            pbad->base.y);
448             }
449           else
450             {
451               texture_draw(&img_laptop_right[(frame / 5) % 3],
452                            pbad->base.x - scroll_x,
453                            pbad->base.y);
454             }
455         }
456       else
457         {
458           /* Flat: */
459
460           if (pbad->dir == LEFT)
461             {
462               texture_draw(&img_laptop_flat_left,
463                            pbad->base.x - scroll_x,
464                            pbad->base.y);
465             }
466           else
467             {
468               texture_draw(&img_laptop_flat_right,
469                            pbad->base.x - scroll_x,
470                            pbad->base.y);
471             }
472         }
473     }
474   else if (pbad->dying == DYING_FALLING)
475     {
476       /* Falling: */
477
478       if (pbad->dir == LEFT)
479         {
480           texture_draw(&img_laptop_falling_left,
481                        pbad->base.x - scroll_x,
482                        pbad->base.y);
483         }
484       else
485         {
486           texture_draw(&img_laptop_falling_right,
487                        pbad->base.x - scroll_x,
488                        pbad->base.y);
489         }
490     }
491 }
492
493 void badguy_draw_money(bad_guy_type* pbad)
494 {
495   if (pbad->base.ym != 300 /* > -16*/)
496     {
497       if (pbad->dir == LEFT)
498         {
499           texture_draw(&img_money_left[0],
500                        pbad->base.x - scroll_x,
501                        pbad->base.y);
502         }
503       else
504         {
505           texture_draw(&img_money_right[0],
506                        pbad->base.x - scroll_x,
507                        pbad->base.y);
508         }
509     }
510   else
511     {
512       if (pbad->dir == LEFT)
513         {
514           texture_draw(&img_money_left[1],
515                        pbad->base.x - scroll_x,
516                        pbad->base.y);
517         }
518       else
519         {
520           texture_draw(&img_money_right[1],
521                        pbad->base.x - scroll_x,
522                        pbad->base.y);
523         }
524     }
525 }
526
527 void badguy_draw(bad_guy_type* pbad)
528 {
529   // Don't try to draw stuff that is outside of the screen
530   if (pbad->base.x > scroll_x - 32 &&
531       pbad->base.x < scroll_x + screen->w)
532     {
533       switch (pbad->kind)
534         {
535         case BAD_BSOD:
536           badguy_draw_bsod(pbad);
537           break;
538     
539         case BAD_LAPTOP:
540           badguy_draw_laptop(pbad);
541           break;
542     
543         case BAD_MONEY:
544           badguy_draw_money(pbad);
545           break;
546
547         default:
548           puts("Unknown badguy type");
549           break;
550         }
551     }
552 }
553
554 void badguy_collision(bad_guy_type* pbad, void *p_c_object, int c_object)
555 {
556   bad_guy_type* pbad_c = NULL;
557   player_type* pplayer_c = NULL;
558
559   switch (c_object)
560     {
561     case CO_BULLET:
562       pbad->dying = DYING_FALLING;
563       pbad->base.ym = -8;
564
565       /* Gain some points: */
566
567       if (pbad->kind == BAD_BSOD)
568         add_score(pbad->base.x - scroll_x, pbad->base.y,
569                   50 * score_multiplier);
570       else if (pbad->kind == BAD_LAPTOP)
571         add_score(pbad->base.x - scroll_x, pbad->base.y,
572                   25 * score_multiplier);
573       else if (pbad->kind == BAD_MONEY)
574         add_score(pbad->base.x - scroll_x, pbad->base.y,
575                   50 * score_multiplier);
576
577       /* Play death sound: */
578       play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
579       break;
580
581     case CO_BADGUY:
582       pbad_c = (bad_guy_type*) p_c_object;
583       if (pbad->mode == NORMAL)
584       {
585       /* do nothing */
586       }
587       else if(pbad->mode == KICK)
588         {
589           /* We're in kick mode, kill the other guy
590              and yourself(wuahaha) : */
591
592           pbad_c->dying = DYING_FALLING;
593           pbad_c->base.ym = -8;
594           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
595
596           add_score(pbad->base.x - scroll_x,
597                     pbad->base.y, 100);
598                   pbad_c->dying = DYING_FALLING;
599                   
600           pbad->dying = DYING_FALLING;
601           pbad->base.ym = -8;
602
603           add_score(pbad_c->base.x - scroll_x,
604                     pbad_c->base.y, 100);
605         }
606       break;
607
608     case CO_PLAYER:
609       pplayer_c = (player_type*) p_c_object;
610       if(pbad->kind != BAD_MONEY)
611         {
612           if (pbad->kind == BAD_BSOD)
613             {
614               pbad->dying = DYING_SQUISHED;
615               timer_start(&pbad->timer,4000);
616               physic_set_state(&pplayer_c->vphysic,PH_VT);
617               physic_set_start_vy(&pplayer_c->vphysic,2.);
618               pplayer_c->base.y = pbad->base.y - pplayer_c->base.height - 1;
619
620               add_score(pbad->base.x - scroll_x, pbad->base.y,
621                         50 * score_multiplier);
622
623               play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
624             }
625           else if (pbad->kind == BAD_LAPTOP)
626             {
627
628               if (pbad->mode == NORMAL || pbad->mode == KICK)
629                 {
630                   /* Flatten! */
631
632                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
633                   pbad->mode = FLAT;
634                   pbad->base.xm = 4;
635
636                   timer_start(&pbad->timer,10000);
637
638                   physic_set_state(&pplayer_c->vphysic,PH_VT);
639                   physic_set_start_vy(&pplayer_c->vphysic,2.);
640                   pplayer_c->base.y = pbad->base.y - pplayer_c->base.height - 1;
641                 }
642               else if (pbad->mode == FLAT)
643                 {
644                   /* Kick! */
645                   play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
646
647                   if (pplayer_c->base.x < pbad->base.x + (pbad->base.width/2))
648                     pbad->dir = RIGHT;
649                   else
650                     pbad->dir = LEFT;
651
652                   pbad->base.xm = 5;
653                   pbad->mode = KICK;
654
655                   timer_start(&pbad->timer,5000);
656                 }
657                 
658               physic_set_state(&pplayer_c->vphysic,PH_VT);
659               physic_set_start_vy(&pplayer_c->vphysic,2.);
660               pplayer_c->base.y = pbad->base.y - pplayer_c->base.height - 1;
661               
662               add_score(pbad->base.x - scroll_x,
663                         pbad->base.y,
664                         25 * score_multiplier);
665
666               /* play_sound(sounds[SND_SQUISH]); */
667             }
668           score_multiplier++;
669         }
670       break;
671     }
672
673 }