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