- added 1up to tileset
[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 #include <math.h>
13
14 #include "globals.h"
15 #include "defines.h"
16 #include "badguy.h"
17 #include "scene.h"
18 #include "screen.h"
19 #include "world.h"
20 #include "tile.h"
21
22 Surface* img_bsod_squished_left[1];
23 Surface* img_bsod_squished_right[1];
24 Surface* img_bsod_falling_left[1];
25 Surface* img_bsod_falling_right[1];
26 Surface* img_laptop_flat_left[1];
27 Surface* img_laptop_flat_right[1];
28 Surface* img_laptop_falling_left[1];
29 Surface* img_laptop_falling_right[1];
30 Surface* img_bsod_left[4];
31 Surface* img_bsod_right[4];
32 Surface* img_laptop_left[4];
33 Surface* img_laptop_right[4];
34 Surface* img_money_left[2];
35 Surface* img_money_right[2];
36 Surface* img_mrbomb_left[4];
37 Surface* img_mrbomb_right[4];
38 Surface* img_mrbomb_ticking_left[1];
39 Surface* img_mrbomb_ticking_right[1];
40 Surface* img_mrbomb_explosion[1];
41 Surface* img_stalactite[1];
42 Surface* img_stalactite_broken[1];
43 Surface* img_flame[2];
44 Surface* img_fish[2];
45 Surface* img_fish_down[1];
46 Surface* img_bouncingsnowball_left[6];
47 Surface* img_bouncingsnowball_right[6];
48 Surface* img_bouncingsnowball_squished[1];
49 Surface* img_flyingsnowball[2];
50 Surface* img_flyingsnowball_squished[1];
51 Surface* img_spiky_left[3];
52 Surface* img_spiky_right[3];
53 Surface* img_snowball_left[4];
54 Surface* img_snowball_right[4];
55 Surface* img_snowball_squished_left[1];
56 Surface* img_snowball_squished_right[1];
57
58 BadGuyKind  badguykind_from_string(const std::string& str)
59 {
60   if (str == "money")
61     return BAD_MONEY;
62   else if (str == "laptop" || str == "mriceblock")
63     return BAD_LAPTOP;
64   else if (str == "bsod")
65     return BAD_BSOD;
66   else if (str == "mrbomb")
67     return BAD_MRBOMB;
68   else if (str == "stalactite")
69     return BAD_STALACTITE;
70   else if (str == "flame")
71     return BAD_FLAME;
72   else if (str == "fish")
73     return BAD_FISH;
74   else if (str == "bouncingsnowball")
75     return BAD_BOUNCINGSNOWBALL;
76   else if (str == "flyingsnowball")
77     return BAD_FLYINGSNOWBALL;
78   else if (str == "spiky")
79     return BAD_SPIKY;
80   else if (str == "snowball")
81     return BAD_SNOWBALL;
82   else
83     {
84       printf("Couldn't convert badguy: '%s'\n", str.c_str());
85       return BAD_BSOD;
86     }
87 }
88
89 std::string badguykind_to_string(BadGuyKind kind)
90 {
91   switch(kind)
92     {
93     case BAD_MONEY:
94       return "money";
95       break;
96     case BAD_LAPTOP:
97       return "laptop";
98       break;
99     case BAD_BSOD:
100       return "bsod";
101       break;
102     case BAD_MRBOMB:
103       return "mrbomb";
104       break;
105     case BAD_STALACTITE:
106       return "stalactite";
107       break;
108     case BAD_FLAME:
109       return "flame";
110       break;
111     case BAD_FISH:
112       return "fish";
113       break;
114     case BAD_BOUNCINGSNOWBALL:
115       return "bouncingsnowball";
116       break;
117     case BAD_FLYINGSNOWBALL:
118       return "flyingsnowball";
119       break;
120     case BAD_SPIKY:
121       return "spiky";
122       break;
123     case BAD_SNOWBALL:
124       return "snowball";
125       break;
126     default:
127       return "bsod";
128     }
129 }
130
131 void
132 BadGuy::init(float x, float y, BadGuyKind kind_)
133 {
134   base.x   = x;
135   base.y   = y;    
136   base.width  = 0;
137   base.height = 0;
138   base.xm  = 0;
139   base.ym  = 0;
140
141   mode     = NORMAL;
142   dying    = DYING_NOT;
143   kind     = kind_;
144   old_base = base;
145   dir      = LEFT;
146   seen     = false;
147   animation_speed = 1;
148   animation_length = 1;
149   animation_offset = 0;
150   texture_left = texture_right = 0;
151   physic.reset();
152   timer.init(true);
153
154   if(kind == BAD_BSOD) {
155     physic.set_velocity(-1.3, 0);
156     set_texture(img_bsod_left, img_bsod_right, 4);
157   } else if(kind == BAD_MRBOMB) {
158     physic.set_velocity(-1.3, 0);
159     set_texture(img_mrbomb_left, img_mrbomb_right, 4);
160   } else if (kind == BAD_LAPTOP) {
161     physic.set_velocity(-1.3, 0);
162     set_texture(img_laptop_left, img_laptop_right, 4, 5);
163   } else if(kind == BAD_MONEY) {
164     set_texture(img_money_left, img_money_right, 1);
165   } else if(kind == BAD_BOMB) {
166     set_texture(img_mrbomb_ticking_left, img_mrbomb_ticking_right, 1);
167     // hack so that the bomb doesn't hurt until it expldes...
168     dying = DYING_SQUISHED;
169   } else if(kind == BAD_FLAME) {
170     base.ym = 0; // we misuse base.ym as angle for the flame
171     physic.enable_gravity(false);
172     set_texture(img_flame, img_flame, 2, 0.5);
173   } else if(kind == BAD_BOUNCINGSNOWBALL) {
174     physic.set_velocity(-1.3, 0);
175     set_texture(img_bouncingsnowball_left, img_bouncingsnowball_right, 6);
176   } else if(kind == BAD_STALACTITE) {
177     physic.enable_gravity(false);
178     set_texture(img_stalactite, img_stalactite, 1);
179   } else if(kind == BAD_FISH) {
180     set_texture(img_fish, img_fish, 2, 1);
181     physic.enable_gravity(true);
182   } else if(kind == BAD_FLYINGSNOWBALL) {
183     set_texture(img_flyingsnowball, img_flyingsnowball, 2, 5);
184     physic.enable_gravity(false);
185   } else if(kind == BAD_SPIKY) {
186     physic.set_velocity(-1.3, 0);
187     set_texture(img_spiky_left, img_spiky_right, 3);
188   } else if(kind == BAD_SNOWBALL) {
189     physic.set_velocity(-1.3, 0);
190     set_texture(img_snowball_left, img_snowball_right, 4, 5);
191   }
192
193   // if we're in a solid tile at start correct that now
194   if(kind != BAD_FLAME && kind != BAD_FISH && collision_object_map(&base)) {
195     printf("Warning: badguy started in wall!.\n");
196     while(collision_object_map(&base))
197       --base.y;
198   }
199 }
200
201 void
202 BadGuy::action_bsod(float frame_ratio)
203 {
204   static const float BSODJUMP = 2;
205     
206   if (dying == DYING_NOT)
207     check_horizontal_bump();
208
209   fall();
210
211   // jump when we're about to fall
212   if (physic.get_velocity_y() == 0 && 
213           !issolid(base.x+base.width/2, base.y + base.height)) {
214     physic.enable_gravity(true);
215     physic.set_velocity(physic.get_velocity_x(), BSODJUMP);
216   }
217
218   // Handle dying timer:
219   if (dying == DYING_SQUISHED && !timer.check())
220     {
221       /* Remove it if time's up: */
222       remove_me();
223       return;
224     }
225
226   // move
227   physic.apply(frame_ratio, base.x, base.y);
228   if(dying != DYING_FALLING)
229     collision_swept_object_map(&old_base, &base);
230 }
231
232 void
233 BadGuy::action_laptop(float frame_ratio)
234 {
235   Player& tux = *World::current()->get_tux();
236
237   if(dying == DYING_NOT)
238     fall();
239   
240   /* Move left/right: */
241   if (mode == NORMAL || mode == KICK)
242     {
243       // move
244       physic.apply(frame_ratio, base.x, base.y);
245       if (dying != DYING_FALLING)
246         collision_swept_object_map(&old_base,&base);
247     }
248   else if (mode == HELD)
249     { /* FIXME: The pbad object shouldn't know about pplayer objects. */
250       /* If we're holding the laptop */
251       dir = tux.dir;
252       if(dir==RIGHT)
253         {
254           base.x = tux.base.x + 16;
255           base.y = tux.base.y + tux.base.height/1.5 - base.height;
256         }
257       else /* facing left */
258         {
259           base.x = tux.base.x - 16;
260           base.y = tux.base.y + tux.base.height/1.5 - base.height;
261         }
262       if(collision_object_map(&base))
263         {
264           base.x = tux.base.x;
265           base.y = tux.base.y + tux.base.height/1.5 - base.height;
266         }
267
268       if(tux.input.fire != DOWN) /* SHOOT! */
269         {
270           if(dir == LEFT)
271             base.x -= 24;
272           else
273             base.x += 24;
274           old_base = base;
275
276           mode=KICK;
277           set_texture(img_laptop_flat_left, img_laptop_flat_right, 1);
278           physic.set_velocity((dir == LEFT) ? -8 : 8, -8);
279           play_sound(sounds[SND_KICK],SOUND_CENTER_SPEAKER);
280         }
281     }
282
283   if (!dying)
284     {
285       int changed = dir;
286       check_horizontal_bump();
287       if(mode == KICK && changed != dir)
288         {
289           /* handle stereo sound (number 10 should be tweaked...)*/
290           if (base.x < scroll_x + screen->w/2 - 10)
291             play_sound(sounds[SND_RICOCHET], SOUND_LEFT_SPEAKER);
292           else if (base.x > scroll_x + screen->w/2 + 10)
293             play_sound(sounds[SND_RICOCHET], SOUND_RIGHT_SPEAKER);
294           else
295             play_sound(sounds[SND_RICOCHET], SOUND_CENTER_SPEAKER);
296         }
297     }
298
299   /* Handle mode timer: */
300   if (mode == FLAT)
301     {
302       if(!timer.check())
303         {
304           mode = NORMAL;
305           set_texture(img_laptop_left, img_laptop_right, 4, 5);
306           physic.set_velocity( (dir == LEFT) ? -1.3 : 1.3, 0);
307         }
308     }
309 }
310
311 void
312 BadGuy::check_horizontal_bump(bool checkcliff)
313 {
314     float halfheight = base.height / 2;
315     if (dir == LEFT && issolid( base.x, (int) base.y + halfheight))
316     {
317         dir = RIGHT;
318         physic.set_velocity(-physic.get_velocity_x(), physic.get_velocity_y());
319         return;
320     }
321     if (dir == RIGHT && issolid( base.x + base.width, (int)base.y + halfheight))
322     {
323         dir = LEFT;
324         physic.set_velocity(-physic.get_velocity_x(), physic.get_velocity_y());
325         return;
326     }
327
328     // don't check for cliffs when we're falling
329     if(!checkcliff)
330         return;
331     if(!issolid(base.x + base.width/2, base.y + base.height))
332         return;
333     
334     if(dir == LEFT && !issolid(base.x, (int) base.y + base.height + halfheight))
335     {
336         dir = RIGHT;
337         physic.set_velocity(-physic.get_velocity_x(), physic.get_velocity_y());
338         return;
339     }
340     if(dir == RIGHT && !issolid(base.x + base.width,
341                 (int) base.y + base.height + halfheight))
342     {
343         dir = LEFT;
344         physic.set_velocity(-physic.get_velocity_x(), physic.get_velocity_y());
345         return;
346     }
347 }
348
349 void
350 BadGuy::fall()
351 {
352   /* Fall if we get off the ground: */
353   if (dying != DYING_FALLING)
354     {
355       if (!issolid(base.x+base.width/2, base.y + base.height))
356         {
357           // not solid below us? enable gravity
358           physic.enable_gravity(true);
359         }
360       else
361         {
362           /* Land: */
363           if (physic.get_velocity_y() < 0)
364             {
365               base.y = int((base.y + base.height)/32) * 32 - base.height;
366               physic.set_velocity(physic.get_velocity_x(), 0);
367             }
368           // no gravity anymore please
369           physic.enable_gravity(false);
370         }
371     }
372   else
373     {
374       physic.enable_gravity(true);
375     }
376 }
377
378 void
379 BadGuy::remove_me()
380 {
381   for(std::vector<BadGuy>::iterator i = World::current()->bad_guys.begin(); 
382       i != World::current()->bad_guys.end(); ++i) 
383     {
384       if( & (*i) == this) {
385         World::current()->bad_guys.erase(i);
386         return;
387       }
388     }
389 }
390
391 void
392 BadGuy::action_money(float frame_ratio)
393 {
394   Player& tux = *World::current()->get_tux();
395
396   static const float JUMPV = 6;
397     
398   fall();
399   // jump when on ground
400   if(dying == DYING_NOT && issolid(base.x, base.y+32))
401     {
402       physic.set_velocity(physic.get_velocity_x(), JUMPV);
403       physic.enable_gravity(true);
404       set_texture(&img_money_left[1], &img_money_right[1], 1);
405       mode = MONEY_JUMP;
406     }
407   else if(mode == MONEY_JUMP)
408     {
409       set_texture(&img_money_left[0], &img_money_right[0], 1);
410       mode = NORMAL;
411     }
412
413   // set direction based on tux
414   if(tux.base.x > base.x)
415     dir = RIGHT;
416   else
417     dir = LEFT;
418
419   // move
420   physic.apply(frame_ratio, base.x, base.y);
421   if(dying == DYING_NOT)
422     collision_swept_object_map(&old_base, &base);
423 }
424
425 void
426 BadGuy::action_mrbomb(float frame_ratio)
427 {
428   if (dying == DYING_NOT)
429     check_horizontal_bump(true);
430
431   fall();
432
433   physic.apply(frame_ratio, base.x, base.y);
434   if (dying != DYING_FALLING)
435     collision_swept_object_map(&old_base,&base); 
436 }
437
438 void
439 BadGuy::action_bomb(float frame_ratio)
440 {
441   static const int TICKINGTIME = 1000;
442   static const int EXPLODETIME = 1000;
443     
444   fall();
445
446   if(mode == NORMAL) {
447     mode = BOMB_TICKING;
448     timer.start(TICKINGTIME);
449   } else if(!timer.check()) {
450     if(mode == BOMB_TICKING) {
451       mode = BOMB_EXPLODE;
452       set_texture(img_mrbomb_explosion, img_mrbomb_explosion, 1);
453       dying = DYING_NOT; // now the bomb hurts
454       timer.start(EXPLODETIME);
455     } else if(mode == BOMB_EXPLODE) {
456       remove_me();
457       return;
458     }
459   }
460
461   // move
462   physic.apply(frame_ratio, base.x, base.y);                 
463   collision_swept_object_map(&old_base,&base);
464 }
465
466 void
467 BadGuy::action_stalactite(float frame_ratio)
468 {
469   Player& tux = *World::current()->get_tux();
470
471   static const int SHAKETIME = 800;
472   static const int RANGE = 40;
473     
474   if(mode == NORMAL) {
475     // start shaking when tux is below the stalactite and at least 40 pixels
476     // near
477     if(tux.base.x + 32 > base.x - RANGE && tux.base.x < base.x + 32 + RANGE
478             && tux.base.y + tux.base.height > base.y) {
479       timer.start(SHAKETIME);
480       mode = STALACTITE_SHAKING;
481     }
482   } if(mode == STALACTITE_SHAKING) {
483     base.x = old_base.x + (rand() % 6) - 3; // TODO this could be done nicer...
484     if(!timer.check()) {
485       mode = STALACTITE_FALL;
486     }
487   } else if(mode == STALACTITE_FALL) {
488     fall();
489     /* Destroy if we collides with land */
490     if(issolid(base.x+base.width/2, base.y+base.height))
491     {
492       timer.start(2000);
493       dying = DYING_SQUISHED;
494       mode = FLAT;
495       set_texture(img_stalactite_broken, img_stalactite_broken, 1);
496     }
497   } else if(mode == FLAT) {
498     fall();
499   }
500
501   // move
502   physic.apply(frame_ratio, base.x, base.y);
503
504   if(dying == DYING_SQUISHED && !timer.check())
505     remove_me();
506 }
507
508 void
509 BadGuy::action_flame(float frame_ratio)
510 {
511     static const float radius = 100;
512     static const float speed = 0.02;
513     base.x = old_base.x + cos(base.ym) * radius;
514     base.y = old_base.y + sin(base.ym) * radius;
515
516     base.ym = fmodf(base.ym + frame_ratio * speed, 2*M_PI);
517 }
518
519 void
520 BadGuy::action_fish(float frame_ratio)
521 {
522   static const float JUMPV = 6;
523   static const int WAITTIME = 1000;
524     
525   // go in wait mode when back in water
526   if(dying == DYING_NOT && gettile(base.x, base.y+ base.height)->water
527         && physic.get_velocity_y() <= 0 && mode == NORMAL)
528     {
529       mode = FISH_WAIT;
530       set_texture(0, 0);
531       physic.set_velocity(0, 0);
532       physic.enable_gravity(false);
533       timer.start(WAITTIME);
534     }
535   else if(mode == FISH_WAIT && !timer.check())
536     {
537       // jump again
538       set_texture(img_fish, img_fish, 2, 2);
539       animation_offset = global_frame_counter; // restart animation
540       mode = NORMAL;
541       physic.set_velocity(0, JUMPV);
542       physic.enable_gravity(true);
543     }
544
545   physic.apply(frame_ratio, base.x, base.y);
546   if(dying == DYING_NOT)
547     collision_swept_object_map(&old_base, &base);
548
549   if(physic.get_velocity_y() < 0)
550     set_texture(img_fish_down, img_fish_down);
551 }
552
553 void
554 BadGuy::action_bouncingsnowball(float frame_ratio)
555 {
556   static const float JUMPV = 4.5;
557     
558   fall();
559
560   // jump when on ground
561   if(dying == DYING_NOT && issolid(base.x, base.y+32))
562     {
563       physic.set_velocity(physic.get_velocity_x(), JUMPV);
564       physic.enable_gravity(true);
565     }                                                     
566   else
567     {
568       mode = NORMAL;
569     }
570
571   // check for right/left collisions
572   check_horizontal_bump();
573
574   physic.apply(frame_ratio, base.x, base.y);
575   if(dying == DYING_NOT)
576     collision_swept_object_map(&old_base, &base);
577
578   // Handle dying timer:
579   if (dying == DYING_SQUISHED && !timer.check())
580     {
581       /* Remove it if time's up: */
582       remove_me();
583       return;
584     }
585 }
586
587 void
588 BadGuy::action_flyingsnowball(float frame_ratio)
589 {
590   static const float FLYINGSPEED = 1;
591   static const int DIRCHANGETIME = 1000;
592     
593   // go into flyup mode if none specified yet
594   if(dying == DYING_NOT && mode == NORMAL) {
595     mode = FLY_UP;
596     physic.set_velocity(physic.get_velocity_x(), FLYINGSPEED);
597     timer.start(DIRCHANGETIME/2);
598   }
599
600   if(dying == DYING_NOT && !timer.check()) {
601     if(mode == FLY_UP) {
602       mode = FLY_DOWN;
603       physic.set_velocity(physic.get_velocity_x(), -FLYINGSPEED);
604     } else if(mode == FLY_DOWN) {
605       mode = FLY_UP;
606       physic.set_velocity(physic.get_velocity_x(), FLYINGSPEED);
607     }
608     timer.start(DIRCHANGETIME);
609   }
610
611   if(dying != DYING_NOT)
612     physic.enable_gravity(true);
613
614   physic.apply(frame_ratio, base.x, base.y);
615   if(dying == DYING_NOT || dying == DYING_SQUISHED)
616     collision_swept_object_map(&old_base, &base);
617
618   // Handle dying timer:
619   if (dying == DYING_SQUISHED && !timer.check())
620     {
621       /* Remove it if time's up: */
622       remove_me();
623       return;
624     }                                                          
625 }
626
627 void
628 BadGuy::action_spiky(float frame_ratio)
629 {
630   if (dying == DYING_NOT)
631     check_horizontal_bump();
632
633   fall();
634 #if 0
635   // jump when we're about to fall
636   if (physic.get_velocity_y() == 0 && 
637           !issolid(base.x+base.width/2, base.y + base.height)) {
638     physic.enable_gravity(true);
639     physic.set_velocity(physic.get_velocity_x(), 2);
640   }
641 #endif
642
643   physic.apply(frame_ratio, base.x, base.y);
644   if (dying != DYING_FALLING)
645     collision_swept_object_map(&old_base,&base);   
646 }
647
648 void
649 BadGuy::action_snowball(float frame_ratio)
650 {
651   if (dying == DYING_NOT)
652     check_horizontal_bump();
653
654   fall();
655
656   physic.apply(frame_ratio, base.x, base.y);
657   if (dying != DYING_FALLING)
658     collision_swept_object_map(&old_base,&base);
659 }
660
661 void
662 BadGuy::action(float frame_ratio)
663 {
664   // Remove if it's far off the screen:
665   if (base.x < scroll_x - OFFSCREEN_DISTANCE)
666     {
667       remove_me();                                                
668       return;
669     }
670
671   // BadGuy fall below the ground
672   if (base.y > screen->h) {
673     remove_me();
674     return;
675   }
676
677   // Once it's on screen, it's activated!
678   if (base.x <= scroll_x + screen->w + OFFSCREEN_DISTANCE)
679     seen = true;
680
681   if(!seen)
682     return;
683
684   switch (kind)
685     {
686     case BAD_BSOD:
687       action_bsod(frame_ratio);
688       break;
689
690     case BAD_LAPTOP:
691       action_laptop(frame_ratio);
692       break;
693   
694     case BAD_MONEY:
695       action_money(frame_ratio);
696       break;
697
698     case BAD_MRBOMB:
699       action_mrbomb(frame_ratio);
700       break;
701     
702     case BAD_BOMB:
703       action_bomb(frame_ratio);
704       break;
705
706     case BAD_STALACTITE:
707       action_stalactite(frame_ratio);
708       break;
709
710     case BAD_FLAME:
711       action_flame(frame_ratio);
712       break;
713
714     case BAD_FISH:
715       action_fish(frame_ratio);
716       break;
717
718     case BAD_BOUNCINGSNOWBALL:
719       action_bouncingsnowball(frame_ratio);
720       break;
721
722     case BAD_FLYINGSNOWBALL:
723       action_flyingsnowball(frame_ratio);
724       break;
725
726     case BAD_SPIKY:
727       action_spiky(frame_ratio);
728       break;
729
730     case BAD_SNOWBALL:
731       action_snowball(frame_ratio);
732       break;
733     }
734 }
735
736 void
737 BadGuy::draw()
738 {
739   // Don't try to draw stuff that is outside of the screen
740   if(base.x <= scroll_x - base.width || base.x >= scroll_x + screen->w)
741     return;
742   if(texture_left == 0 || texture_right == 0)
743     return;
744
745   float global_frame = (float(global_frame_counter - animation_offset) / 10);
746   global_frame *= animation_speed;
747   size_t frame = size_t(global_frame) % animation_length;
748   Surface* texture = 
749       (dir == LEFT) ? texture_left[frame] : texture_right[frame];
750   texture->draw(base.x - scroll_x, base.y);
751
752   if (debug_mode)
753     fillrect(base.x - scroll_x, base.y, 32, 32, 75,0,75, 150);
754 }
755
756 void
757 BadGuy::set_texture(Surface** left, Surface** right,
758     int nanimlength, float nanimspeed)
759 {
760   if(left != 0) {
761     if(base.width == 0 && base.height == 0) {
762       base.width = left[0]->w;
763       base.height = left[0]->h;
764     } else if(base.width != left[0]->w || base.height != left[0]->h) {
765       base.x -= (left[0]->w - base.width) / 2;
766       base.y -= left[0]->h - base.height;
767       base.width = left[0]->w;
768       base.height = left[0]->h;
769       old_base = base;
770     }
771   } else {
772     base.width = base.height = 0;
773   }
774
775   animation_length = nanimlength;
776   animation_speed = nanimspeed;
777   animation_offset = 0;
778   texture_left = left;
779   texture_right = right;
780 }
781
782 void
783 BadGuy::bump()
784 {
785   if(kind == BAD_BSOD || kind == BAD_LAPTOP || kind == BAD_MRBOMB
786       || kind == BAD_BOUNCINGSNOWBALL) {
787     kill_me();
788   }
789 }
790
791 void
792 BadGuy::make_player_jump(Player* player)
793 {
794   player->physic.set_velocity(player->physic.get_velocity_x(), 2);
795   player->base.y = base.y - player->base.height - 2;
796 }
797
798 void
799 BadGuy::squish_me(Player* player)
800 {
801   make_player_jump(player);
802     
803   World::current()->add_score(base.x - scroll_x,
804                               base.y, 50 * player_status.score_multiplier);
805   play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
806   player_status.score_multiplier++;
807
808   dying = DYING_SQUISHED;
809   timer.start(2000);
810   physic.set_velocity(0, 0);
811 }
812
813 void
814 BadGuy::squish(Player* player)
815 {
816   if(kind == BAD_MRBOMB) {
817     // mrbomb transforms into a bomb now
818     World::current()->add_bad_guy(base.x, base.y, BAD_BOMB);
819     
820     make_player_jump(player);
821     World::current()->add_score(base.x - scroll_x, base.y, 50 * player_status.score_multiplier);
822     play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
823     player_status.score_multiplier++;
824       
825     remove_me();
826     return;
827
828   } else if(kind == BAD_BSOD) {
829     squish_me(player);
830     set_texture(img_bsod_squished_left, img_bsod_squished_right, 1);
831     physic.set_velocity(0, physic.get_velocity_y());
832     return;
833       
834   } else if (kind == BAD_LAPTOP) {
835     if (mode == NORMAL || mode == KICK)
836       {
837         /* Flatten! */
838         play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
839         mode = FLAT;
840         set_texture(img_laptop_flat_left, img_laptop_flat_right, 1);
841         physic.set_velocity(0, physic.get_velocity_y());
842
843         timer.start(4000);
844       } else if (mode == FLAT) {
845         /* Kick! */
846         play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
847
848         if (player->base.x < base.x + (base.width/2)) {
849           physic.set_velocity(5, physic.get_velocity_y());
850           dir = RIGHT;
851         } else {
852           physic.set_velocity(-5, physic.get_velocity_y());
853           dir = LEFT;
854         }
855
856         mode = KICK;
857         set_texture(img_laptop_flat_left, img_laptop_flat_right, 1);
858       }
859
860     make_player_jump(player);
861               
862     World::current()->add_score(base.x - scroll_x, base.y, 25 * player_status.score_multiplier);
863     player_status.score_multiplier++;
864     return;
865   } else if(kind == BAD_FISH) {
866     // fish can only be killed when falling down
867     if(physic.get_velocity_y() >= 0)
868       return;
869       
870     make_player_jump(player);
871               
872     World::current()->add_score(base.x - scroll_x, base.y, 25 * player_status.score_multiplier);
873     player_status.score_multiplier++;
874      
875     // simply remove the fish...
876     remove_me();
877     return;
878   } else if(kind == BAD_BOUNCINGSNOWBALL) {
879     squish_me(player);
880     set_texture(img_bouncingsnowball_squished,img_bouncingsnowball_squished,1);
881     return;
882   } else if(kind == BAD_FLYINGSNOWBALL) {
883     squish_me(player);
884     set_texture(img_flyingsnowball_squished,img_flyingsnowball_squished,1);
885     return;
886   } else if(kind == BAD_SNOWBALL) {
887     squish_me(player);
888     set_texture(img_snowball_squished_left, img_snowball_squished_right, 1);
889     return;
890   }
891 }
892
893 void
894 BadGuy::kill_me()
895 {
896   if(kind == BAD_BOMB || kind == BAD_STALACTITE || kind == BAD_FLAME)
897     return;
898
899   dying = DYING_FALLING;
900   if(kind == BAD_LAPTOP)
901     set_texture(img_laptop_falling_left, img_laptop_falling_right, 1);
902   else if(kind == BAD_BSOD)
903     set_texture(img_bsod_falling_left, img_bsod_falling_right, 1);
904   
905   physic.enable_gravity(true);
906   physic.set_velocity(physic.get_velocity_x(), 0);
907
908   /* Gain some points: */
909   if (kind == BAD_BSOD)
910     World::current()->add_score(base.x - scroll_x, base.y,
911                     50 * player_status.score_multiplier);
912   else 
913     World::current()->add_score(base.x - scroll_x, base.y,                                 
914                     25 * player_status.score_multiplier);
915
916   /* Play death sound: */
917   play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
918 }
919
920 void
921 BadGuy::collision(void *p_c_object, int c_object, CollisionType type)
922 {
923   BadGuy* pbad_c    = NULL;
924
925   if(type == COLLISION_BUMP) {
926     bump();
927     return;
928   }
929   if(type == COLLISION_SQUISH) {
930     Player* player = static_cast<Player*>(p_c_object);
931     squish(player);
932     return;
933   }
934
935   switch (c_object)
936     {
937     case CO_BULLET:
938       kill_me();
939       break;
940
941     case CO_BADGUY:
942       pbad_c = (BadGuy*) p_c_object;
943       if(kind == BAD_LAPTOP && mode == KICK &&
944             pbad_c->kind != BAD_FLAME && pbad_c->kind != BAD_BOMB)
945         {
946           /* We're in kick mode, kill the other guy
947              and yourself(wuahaha) : */
948           pbad_c->kill_me();
949           kill_me();
950         }
951       break;
952     }
953 }
954
955 //---------------------------------------------------------------------------
956
957 void load_badguy_gfx()
958 {
959   /* (BSOD) */
960   img_bsod_left[0] = new Surface(datadir + "/images/shared/bsod-left-0.png", USE_ALPHA);
961
962   img_bsod_left[1] = new Surface(datadir +
963                "/images/shared/bsod-left-1.png",
964                USE_ALPHA);
965
966   img_bsod_left[2] = new Surface(datadir +
967                "/images/shared/bsod-left-2.png",
968                USE_ALPHA);
969
970   img_bsod_left[3] = new Surface(datadir +
971                "/images/shared/bsod-left-3.png",
972                USE_ALPHA);
973
974   img_bsod_right[0] = new Surface(datadir +
975                "/images/shared/bsod-right-0.png",
976                USE_ALPHA);
977
978   img_bsod_right[1] = new Surface(datadir +
979                "/images/shared/bsod-right-1.png",
980                USE_ALPHA);
981
982   img_bsod_right[2] = new Surface(datadir +
983                "/images/shared/bsod-right-2.png",
984                USE_ALPHA);
985
986   img_bsod_right[3] = new Surface(datadir +
987                "/images/shared/bsod-right-3.png",
988                USE_ALPHA);
989
990   img_bsod_squished_left[0] = new Surface(datadir +
991                "/images/shared/bsod-squished-left.png",
992                USE_ALPHA);
993
994   img_bsod_squished_right[0] = new Surface(datadir +
995                "/images/shared/bsod-squished-right.png",
996                USE_ALPHA);
997
998   img_bsod_falling_left[0] = new Surface(datadir +
999                "/images/shared/bsod-falling-left.png",
1000                USE_ALPHA);
1001
1002   img_bsod_falling_right[0] = new Surface(datadir +
1003                "/images/shared/bsod-falling-right.png",
1004                USE_ALPHA);
1005
1006
1007   /* (Laptop) */
1008
1009   img_laptop_left[0] = new Surface(datadir + "/images/shared/mriceblock-left-0.png", USE_ALPHA);
1010   img_laptop_left[1] = new Surface(datadir + "/images/shared/mriceblock-left-1.png", USE_ALPHA);
1011   img_laptop_left[2] = new Surface(datadir + "/images/shared/mriceblock-left-2.png", USE_ALPHA);
1012   img_laptop_left[3] = new Surface(datadir + "/images/shared/mriceblock-left-1.png", USE_ALPHA);
1013
1014   img_laptop_right[0] = new Surface(datadir + "/images/shared/mriceblock-right-0.png", USE_ALPHA);
1015   img_laptop_right[1] = new Surface(datadir + "/images/shared/mriceblock-right-1.png", USE_ALPHA);
1016   img_laptop_right[2] = new Surface(datadir + "/images/shared/mriceblock-right-2.png", USE_ALPHA);
1017   img_laptop_right[3] = new Surface(datadir + "/images/shared/mriceblock-right-1.png", USE_ALPHA);
1018   
1019   img_laptop_flat_left[0] = new Surface(
1020                datadir + "/images/shared/laptop-flat-left.png",
1021                USE_ALPHA);
1022
1023   img_laptop_flat_right[0] = new Surface(datadir +
1024                "/images/shared/laptop-flat-right.png",
1025                USE_ALPHA);
1026
1027   img_laptop_falling_left[0] = new Surface(datadir +
1028                "/images/shared/laptop-falling-left.png",
1029                USE_ALPHA);
1030
1031   img_laptop_falling_right[0] = new Surface(datadir +
1032                "/images/shared/laptop-falling-right.png",
1033                USE_ALPHA);
1034
1035
1036   /* (Money) */
1037
1038   img_money_left[0] = new Surface(datadir +
1039                "/images/shared/bag-left-0.png",
1040                USE_ALPHA);
1041
1042   img_money_left[1] = new Surface(datadir +
1043                "/images/shared/bag-left-1.png",
1044                USE_ALPHA);
1045
1046   img_money_right[0] = new Surface(datadir +
1047                "/images/shared/bag-right-0.png",
1048                USE_ALPHA);
1049
1050   img_money_right[1] = new Surface(datadir +
1051                "/images/shared/bag-right-1.png",
1052                USE_ALPHA);
1053
1054   /* Mr. Bomb */
1055   for(int i=0; i<4; ++i) {
1056       char num[4];
1057       snprintf(num, 4, "%d", i);
1058       img_mrbomb_left[i] = new Surface(
1059               datadir + "/images/shared/mrbomb-left-" + num + ".png", USE_ALPHA);
1060       img_mrbomb_right[i] = new Surface(
1061               datadir + "/images/shared/mrbomb-right-" + num + ".png", USE_ALPHA);
1062   }
1063   img_mrbomb_ticking_left[0] = new Surface(
1064           datadir + "/images/shared/mrbombx-left-0.png", USE_ALPHA);
1065   img_mrbomb_ticking_right[0] = new Surface(
1066           datadir + "/images/shared/mrbombx-right-0.png", USE_ALPHA);
1067   img_mrbomb_explosion[0] = new Surface(
1068           datadir + "/images/shared/mrbomb-explosion.png", USE_ALPHA);
1069
1070   /* stalactite */
1071   img_stalactite[0] = new Surface(
1072           datadir + "/images/shared/stalactite.png", USE_ALPHA);
1073   img_stalactite_broken[0] = new Surface(
1074           datadir + "/images/shared/stalactite-broken.png", USE_ALPHA);
1075
1076   /* flame */
1077   img_flame[0] = new Surface(
1078           datadir + "/images/shared/flame-0.png", USE_ALPHA);
1079   img_flame[1] = new Surface(
1080           datadir + "/images/shared/flame-1.png", USE_ALPHA);  
1081
1082   /* fish */
1083   img_fish[0] = new Surface(
1084           datadir + "/images/shared/fish-left-0.png", USE_ALPHA);
1085   img_fish[1] = new Surface(
1086           datadir + "/images/shared/fish-left-1.png", USE_ALPHA);
1087   img_fish_down[0] = new Surface(
1088           datadir + "/images/shared/fish-down-0.png", USE_ALPHA);
1089
1090   /* bouncing snowball */
1091   for(int i=0; i<6; ++i) {
1092       char num[4];
1093       snprintf(num, 4, "%d", i);
1094       img_bouncingsnowball_left[i] = new Surface(
1095               datadir + "/images/shared/bouncingsnowball-left-" + num + ".png",
1096               USE_ALPHA);
1097       img_bouncingsnowball_right[i] = new Surface(
1098               datadir + "/images/shared/bouncingsnowball-right-" + num + ".png",
1099               USE_ALPHA);
1100   } 
1101   img_bouncingsnowball_squished[0] = new Surface(
1102           datadir + "/images/shared/bsod-squished-left.png", USE_ALPHA);
1103
1104   /* flying snowball */
1105   img_flyingsnowball[0] = new Surface(
1106           datadir + "/images/shared/flyingsnowball-left-0.png", USE_ALPHA);
1107   img_flyingsnowball[1] = new Surface(
1108           datadir + "/images/shared/flyingsnowball-left-1.png", USE_ALPHA);  
1109   img_flyingsnowball_squished[0] = new Surface(
1110           datadir + "/images/shared/bsod-squished-left.png", USE_ALPHA);
1111
1112   /* spiky */
1113   for(int i = 0; i < 3; ++i) {
1114         char num[4];
1115         snprintf(num, 4, "%d", i);
1116         img_spiky_left[i] = new Surface(                                
1117                 datadir + "/images/shared/spiky-left-" + num + ".png",   
1118                 USE_ALPHA);
1119         img_spiky_right[i] = new Surface(
1120                 datadir + "/images/shared/spiky-right-" + num + ".png",
1121                 USE_ALPHA);
1122   }
1123
1124   /** snowball */
1125   img_snowball_left[0] = new Surface(datadir + "/images/shared/snowball-left-0.png", USE_ALPHA);
1126   img_snowball_left[1] = new Surface(datadir + "/images/shared/snowball-left-1.png", USE_ALPHA);
1127   img_snowball_left[2] = new Surface(datadir + "/images/shared/snowball-left-2.png", USE_ALPHA);
1128   img_snowball_left[3] = new Surface(datadir + "/images/shared/snowball-left-1.png", USE_ALPHA);
1129
1130   img_snowball_right[0] = new Surface(datadir + "/images/shared/snowball-right-0.png", USE_ALPHA);
1131   img_snowball_right[1] = new Surface(datadir + "/images/shared/snowball-right-1.png", USE_ALPHA);
1132   img_snowball_right[2] = new Surface(datadir + "/images/shared/snowball-right-2.png", USE_ALPHA);
1133   img_snowball_right[3] = new Surface(datadir + "/images/shared/snowball-right-1.png", USE_ALPHA);
1134
1135   img_snowball_squished_left[0] = new Surface(
1136           datadir + "/images/shared/bsod-squished-left.png", USE_ALPHA);
1137   img_snowball_squished_right[0] = new Surface(
1138           datadir + "/images/shared/bsod-squished-right.png", USE_ALPHA);  
1139 }
1140
1141 void free_badguy_gfx()
1142 {
1143   for (int i = 0; i < 4; i++)
1144     {
1145       delete img_bsod_left[i];
1146       delete img_bsod_right[i];
1147     }
1148
1149   delete img_bsod_squished_left[0];
1150   delete img_bsod_squished_right[0];
1151
1152   delete img_bsod_falling_left[0];
1153   delete img_bsod_falling_right[0];
1154
1155   for (int i = 0; i < 4; i++)
1156     {
1157       delete img_laptop_left[i];
1158       delete img_laptop_right[i];
1159     }
1160
1161   delete img_laptop_flat_left[0];
1162   delete img_laptop_flat_right[0];
1163
1164   delete img_laptop_falling_left[0];
1165   delete img_laptop_falling_right[0];
1166
1167   for (int i = 0; i < 2; i++)
1168     {
1169       delete img_money_left[i];
1170       delete img_money_right[i];
1171     }
1172
1173   for(int i = 0; i < 4; i++) {
1174       delete img_mrbomb_left[i];
1175       delete img_mrbomb_right[i];
1176   }
1177
1178   delete img_mrbomb_ticking_left[0];
1179   delete img_mrbomb_ticking_right[0];
1180   delete img_mrbomb_explosion[0];
1181
1182   delete img_stalactite[0];
1183   delete img_stalactite_broken[0];
1184
1185   delete img_flame[0];
1186   delete img_flame[1];
1187
1188   delete img_fish[0];
1189   delete img_fish[1];
1190   delete img_fish_down[0];
1191
1192   for(int i=0; i<6; ++i) {
1193     delete img_bouncingsnowball_left[i];
1194     delete img_bouncingsnowball_right[i];
1195   }
1196   delete img_bouncingsnowball_squished[0];
1197
1198   delete img_flyingsnowball[0];
1199   delete img_flyingsnowball[1];
1200   delete img_flyingsnowball_squished[0];
1201
1202   for(int i = 0; i<3; ++i) {
1203     delete img_spiky_left[i];
1204     delete img_spiky_right[i];
1205   }
1206   for(int i = 0; i<4; ++i) {
1207     delete img_snowball_left[i];
1208     delete img_snowball_right[i];
1209   }
1210   delete img_snowball_squished_left[0];
1211   delete img_snowball_squished_right[0]; 
1212 }
1213
1214 // EOF //