- fixed snowball anim
[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[3];
32 texture_type img_laptop_right[3];
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")
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, 3);
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, 3);
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   std::vector<BadGuy>::iterator i;
376   for(i = bad_guys.begin(); i != bad_guys.end(); ++i) {
377     if( & (*i) == this) {
378       bad_guys.erase(i);
379       return;
380     }
381   }
382 }
383
384 void
385 BadGuy::action_money()
386 {
387   static const float JUMPV = 6;
388     
389   fall();
390   // jump when on ground
391   if(dying == DYING_NOT && issolid(base.x, base.y+32))
392     {
393       physic.set_velocity(physic.get_velocity_x(), JUMPV);
394       physic.enable_gravity(true);
395       set_texture(&img_money_left[1], &img_money_right[1], 1);
396       mode = MONEY_JUMP;
397     }
398   else if(mode == MONEY_JUMP)
399     {
400       set_texture(&img_money_left[0], &img_money_right[0], 1);
401       mode = NORMAL;
402     }
403
404   // set direction based on tux
405   if(tux.base.x > base.x)
406     dir = RIGHT;
407   else
408     dir = LEFT;
409
410   // move
411   physic.apply(base.x, base.y);
412   if(dying == DYING_NOT)
413     collision_swept_object_map(&old_base, &base);
414 }
415
416 void
417 BadGuy::action_mrbomb()
418 {
419   if (dying == DYING_NOT)
420     check_horizontal_bump(true);
421
422   fall();
423
424   physic.apply(base.x, base.y);
425   if (dying != DYING_FALLING)
426     collision_swept_object_map(&old_base,&base); 
427 }
428
429 void
430 BadGuy::action_bomb()
431 {
432   static const int TICKINGTIME = 1000;
433   static const int EXPLODETIME = 1000;
434     
435   fall();
436
437   if(mode == NORMAL) {
438     mode = BOMB_TICKING;
439     timer_start(&timer, TICKINGTIME);
440   } else if(!timer_check(&timer)) {
441     if(mode == BOMB_TICKING) {
442       mode = BOMB_EXPLODE;
443       set_texture(img_mrbomb_explosion, img_mrbomb_explosion, 1);
444       dying = DYING_NOT; // now the bomb hurts
445       timer_start(&timer, EXPLODETIME);
446     } else if(mode == BOMB_EXPLODE) {
447       remove_me();
448       return;
449     }
450   }
451
452   // move
453   physic.apply(base.x, base.y);                 
454   collision_swept_object_map(&old_base,&base);
455 }
456
457 void
458 BadGuy::action_stalactite()
459 {
460   static const int SHAKETIME = 800;
461   static const int RANGE = 40;
462     
463   if(mode == NORMAL) {
464     // start shaking when tux is below the stalactite and at least 40 pixels
465     // near
466     if(tux.base.x + 32 > base.x - RANGE && tux.base.x < base.x + 32 + RANGE
467             && tux.base.y + tux.base.height > base.y) {
468       timer_start(&timer, SHAKETIME);
469       mode = STALACTITE_SHAKING;
470     }
471   } if(mode == STALACTITE_SHAKING) {
472     base.x = old_base.x + (rand() % 6) - 3; // TODO this could be done nicer...
473     if(!timer_check(&timer)) {
474       mode = STALACTITE_FALL;
475     }
476   } else if(mode == STALACTITE_FALL) {
477     fall();
478     /* Destroy if we collides with land */
479     if(issolid(base.x+base.width/2, base.y+base.height))
480     {
481       timer_start(&timer, 2000);
482       dying = DYING_SQUISHED;
483       mode = FLAT;
484       set_texture(img_stalactite_broken, img_stalactite_broken, 1);
485     }
486   } else if(mode == FLAT) {
487     fall();
488   }
489
490   // move
491   physic.apply(base.x, base.y);
492
493   if(dying == DYING_SQUISHED && !timer_check(&timer))
494     remove_me();
495 }
496
497 void
498 BadGuy::action_flame()
499 {
500     static const float radius = 100;
501     static const float speed = 0.02;
502     base.x = old_base.x + cos(base.ym) * radius;
503     base.y = old_base.y + sin(base.ym) * radius;
504
505     base.ym = fmodf(base.ym + frame_ratio * speed, 2*M_PI);
506 }
507
508 void
509 BadGuy::action_fish()
510 {
511   static const float JUMPV = 6;
512   static const int WAITTIME = 1000;
513     
514   // go in wait mode when back in water
515   if(dying == DYING_NOT && gettile(base.x, base.y+ base.height)->water
516         && physic.get_velocity_y() <= 0 && mode == NORMAL)
517     {
518       mode = FISH_WAIT;
519       set_texture(0, 0);
520       physic.set_velocity(0, 0);
521       physic.enable_gravity(false);
522       timer_start(&timer, WAITTIME);
523     }
524   else if(mode == FISH_WAIT && !timer_check(&timer))
525     {
526       // jump again
527       set_texture(img_fish, img_fish, 2, 1.5);
528       animation_offset = global_frame_counter; // restart animation
529       mode = NORMAL;
530       physic.set_velocity(0, JUMPV);
531       physic.enable_gravity(true);
532     }
533
534   physic.apply(base.x, base.y);
535   if(dying == DYING_NOT)
536     collision_swept_object_map(&old_base, &base);
537 }
538
539 void
540 BadGuy::action_bouncingsnowball()
541 {
542   static const float JUMPV = 4.5;
543     
544   fall();
545
546   // jump when on ground
547   if(dying == DYING_NOT && issolid(base.x, base.y+32))
548     {
549       physic.set_velocity(physic.get_velocity_x(), JUMPV);
550       physic.enable_gravity(true);
551     }                                                     
552   else
553     {
554       mode = NORMAL;
555     }
556
557   // check for right/left collisions
558   check_horizontal_bump();
559
560   physic.apply(base.x, base.y);
561   if(dying == DYING_NOT)
562     collision_swept_object_map(&old_base, &base);
563
564   // Handle dying timer:
565   if (dying == DYING_SQUISHED && !timer_check(&timer))       
566     {
567       /* Remove it if time's up: */
568       remove_me();
569       return;
570     }
571 }
572
573 void
574 BadGuy::action_flyingsnowball()
575 {
576   static const float FLYINGSPEED = 1;
577   static const int DIRCHANGETIME = 1000;
578     
579   // go into flyup mode if none specified yet
580   if(dying == DYING_NOT && mode == NORMAL) {
581     mode = FLY_UP;
582     physic.set_velocity(physic.get_velocity_x(), FLYINGSPEED);
583     timer_start(&timer, DIRCHANGETIME/2);
584   }
585
586   if(dying == DYING_NOT && !timer_check(&timer)) {
587     if(mode == FLY_UP) {
588       mode = FLY_DOWN;
589       physic.set_velocity(physic.get_velocity_x(), -FLYINGSPEED);
590     } else if(mode == FLY_DOWN) {
591       mode = FLY_UP;
592       physic.set_velocity(physic.get_velocity_x(), FLYINGSPEED);
593     }
594     timer_start(&timer, DIRCHANGETIME);
595   }
596
597   if(dying != DYING_NOT)
598     physic.enable_gravity(true);
599
600   physic.apply(base.x, base.y);
601   if(dying == DYING_NOT || dying == DYING_SQUISHED)
602     collision_swept_object_map(&old_base, &base);
603
604   // Handle dying timer:
605   if (dying == DYING_SQUISHED && !timer_check(&timer))       
606     {
607       /* Remove it if time's up: */
608       remove_me();
609       return;
610     }                                                          
611 }
612
613 void
614 BadGuy::action_spiky()
615 {
616   if (dying == DYING_NOT)
617     check_horizontal_bump();
618
619   fall();
620 #if 0
621   // jump when we're about to fall
622   if (physic.get_velocity_y() == 0 && 
623           !issolid(base.x+base.width/2, base.y + base.height)) {
624     physic.enable_gravity(true);
625     physic.set_velocity(physic.get_velocity_x(), 2);
626   }
627 #endif
628
629   physic.apply(base.x, base.y);
630   if (dying != DYING_FALLING)
631     collision_swept_object_map(&old_base,&base);   
632 }
633
634 void
635 BadGuy::action_snowball()
636 {
637   if (dying == DYING_NOT)
638     check_horizontal_bump();
639
640   fall();
641
642   physic.apply(base.x, base.y);
643   if (dying != DYING_FALLING)
644     collision_swept_object_map(&old_base,&base);
645 }
646
647 void
648 BadGuy::action()
649 {
650   // Remove if it's far off the screen:
651   if (base.x < scroll_x - OFFSCREEN_DISTANCE)
652     {
653       remove_me();                                                
654       return;
655     }
656
657   // BadGuy fall below the ground
658   if (base.y > screen->h) {
659     remove_me();
660     return;
661   }
662
663   // Once it's on screen, it's activated!
664   if (base.x <= scroll_x + screen->w + OFFSCREEN_DISTANCE)
665     seen = true;
666
667   if(!seen)
668     return;
669
670   switch (kind)
671     {
672     case BAD_BSOD:
673       action_bsod();
674       break;
675
676     case BAD_LAPTOP:
677       action_laptop();
678       break;
679   
680     case BAD_MONEY:
681       action_money();
682       break;
683
684     case BAD_MRBOMB:
685       action_mrbomb();
686       break;
687     
688     case BAD_BOMB:
689       action_bomb();
690       break;
691
692     case BAD_STALACTITE:
693       action_stalactite();
694       break;
695
696     case BAD_FLAME:
697       action_flame();
698       break;
699
700     case BAD_FISH:
701       action_fish();
702       break;
703
704     case BAD_BOUNCINGSNOWBALL:
705       action_bouncingsnowball();
706       break;
707
708     case BAD_FLYINGSNOWBALL:
709       action_flyingsnowball();
710       break;
711
712     case BAD_SPIKY:
713       action_spiky();
714       break;
715
716     case BAD_SNOWBALL:
717       action_snowball();
718       break;
719     }
720 }
721
722 void
723 BadGuy::draw()
724 {
725   // Don't try to draw stuff that is outside of the screen
726   if(base.x <= scroll_x - base.width || base.x >= scroll_x + screen->w)
727     return;
728   if(texture_left == 0 || texture_right == 0)
729     return;
730
731   float global_frame = (float(global_frame_counter - animation_offset) / 10);
732   global_frame *= animation_speed;
733   size_t frame = size_t(global_frame) % animation_length;
734   texture_type* texture = 
735       (dir == LEFT) ? &texture_left[frame] : &texture_right[frame];
736   texture_draw(texture, base.x - scroll_x, base.y);
737 }
738
739 void
740 BadGuy::set_texture(texture_type* left, texture_type* right,
741     int nanimlength, float nanimspeed)
742 {
743   if(left != 0) {
744     if(base.width == 0 && base.height == 0) {
745       base.width = left->w;
746       base.height = left->h;
747     } else if(base.width != left->w || base.height != left->h) {
748       base.x -= (left->w - base.width) / 2;
749       base.y -= left->h - base.height;
750       base.width = left->w;
751       base.height = left->h;
752       old_base = base;
753     }
754   } else {
755     base.width = base.height = 0;
756   }
757
758   animation_length = nanimlength;
759   animation_speed = nanimspeed;
760   animation_offset = 0;
761   texture_left = left;
762   texture_right = right;
763 }
764
765 void
766 BadGuy::bump()
767 {
768   if(kind == BAD_BSOD || kind == BAD_LAPTOP || kind == BAD_MRBOMB
769       || kind == BAD_BOUNCINGSNOWBALL) {
770     kill_me();
771   }
772 }
773
774 void
775 BadGuy::make_player_jump(Player* player)
776 {
777   player->physic.set_velocity(player->physic.get_velocity_x(), 2);
778   player->base.y = base.y - player->base.height - 2;
779 }
780
781 void
782 BadGuy::squish_me(Player* player)
783 {
784   make_player_jump(player);
785     
786   add_score(base.x - scroll_x, base.y, 50 * score_multiplier);
787   play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
788   score_multiplier++;
789
790   dying = DYING_SQUISHED;
791   timer_start(&timer, 2000);
792   physic.set_velocity(0, 0);
793 }
794
795 void
796 BadGuy::squish(Player* player)
797 {
798   if(kind == BAD_MRBOMB) {
799       // mrbomb transforms into a bomb now
800       add_bad_guy(base.x, base.y, BAD_BOMB);
801       
802       make_player_jump(player);
803       add_score(base.x - scroll_x, base.y, 50 * score_multiplier);
804       play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
805       score_multiplier++;
806       
807       remove_me();
808       return;
809
810   } else if(kind == BAD_BSOD) {
811       squish_me(player);
812       set_texture(img_bsod_squished_left, img_bsod_squished_right, 1);
813       physic.set_velocity(0, physic.get_velocity_y());
814       return;
815       
816   } else if (kind == BAD_LAPTOP) {
817       if (mode == NORMAL || mode == KICK)
818       {
819           /* Flatten! */
820           play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
821           mode = FLAT;
822           set_texture(img_laptop_flat_left, img_laptop_flat_right, 1);
823           physic.set_velocity(0, physic.get_velocity_y());
824
825           timer_start(&timer, 4000);
826       } else if (mode == FLAT) {
827           /* Kick! */
828           play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
829
830           if (player->base.x < base.x + (base.width/2)) {
831               physic.set_velocity(5, physic.get_velocity_y());
832               dir = RIGHT;
833           } else {
834               physic.set_velocity(-5, physic.get_velocity_y());
835               dir = LEFT;
836           }
837
838           mode = KICK;
839           set_texture(img_laptop_flat_left, img_laptop_flat_right, 1);
840       }
841
842       make_player_jump(player);
843               
844       add_score(base.x - scroll_x, base.y, 25 * score_multiplier);
845       score_multiplier++;
846       return;
847   } else if(kind == BAD_FISH) {
848     make_player_jump(player);
849               
850     add_score(base.x - scroll_x, base.y, 25 * score_multiplier);
851     score_multiplier++;
852      
853     // simply remove the fish...
854     remove_me();
855     return;
856   } else if(kind == BAD_BOUNCINGSNOWBALL) {
857     squish_me(player);
858     set_texture(img_bouncingsnowball_squished,img_bouncingsnowball_squished,1);
859     return;
860   } else if(kind == BAD_FLYINGSNOWBALL) {
861     squish_me(player);
862     set_texture(img_flyingsnowball_squished,img_flyingsnowball_squished,1);
863     return;
864   } else if(kind == BAD_SNOWBALL) {
865     squish_me(player);
866     set_texture(img_snowball_squished_left, img_snowball_squished_right, 1);
867     return;
868   }
869 }
870
871 void
872 BadGuy::kill_me()
873 {
874   if(kind == BAD_BOMB || kind == BAD_STALACTITE || kind == BAD_FLAME)
875     return;
876
877   dying = DYING_FALLING;
878   if(kind == BAD_LAPTOP)
879     set_texture(img_laptop_falling_left, img_laptop_falling_right, 1);
880   else if(kind == BAD_BSOD)
881     set_texture(img_bsod_falling_left, img_bsod_falling_right, 1);
882   
883   physic.enable_gravity(true);
884   physic.set_velocity(physic.get_velocity_x(), 0);
885
886   /* Gain some points: */
887   if (kind == BAD_BSOD)
888     add_score(base.x - scroll_x, base.y,
889               50 * score_multiplier);
890   else 
891     add_score(base.x - scroll_x, base.y,                                 
892               25 * score_multiplier);
893
894   /* Play death sound: */
895   play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
896 }
897
898 void
899 BadGuy::collision(void *p_c_object, int c_object, CollisionType type)
900 {
901   BadGuy* pbad_c    = NULL;
902
903   if(type == COLLISION_BUMP) {
904     bump();
905     return;
906   }
907   if(type == COLLISION_SQUISH) {
908     Player* player = static_cast<Player*>(p_c_object);
909     squish(player);
910     return;
911   }
912
913   switch (c_object)
914     {
915     case CO_BULLET:
916       kill_me();
917       break;
918
919     case CO_BADGUY:
920       pbad_c = (BadGuy*) p_c_object;
921       if(kind == BAD_LAPTOP && mode == KICK &&
922             pbad_c->kind != BAD_FLAME && pbad_c->kind != BAD_BOMB)
923         {
924           /* We're in kick mode, kill the other guy
925              and yourself(wuahaha) : */
926           pbad_c->kill_me();
927           kill_me();
928         }
929       break;
930     }
931 }
932
933 //---------------------------------------------------------------------------
934
935 void load_badguy_gfx()
936 {
937   /* (BSOD) */
938   texture_load(&img_bsod_left[0], datadir +
939                "/images/shared/bsod-left-0.png",
940                USE_ALPHA);
941
942   texture_load(&img_bsod_left[1], datadir +
943                "/images/shared/bsod-left-1.png",
944                USE_ALPHA);
945
946   texture_load(&img_bsod_left[2], datadir +
947                "/images/shared/bsod-left-2.png",
948                USE_ALPHA);
949
950   texture_load(&img_bsod_left[3], datadir +
951                "/images/shared/bsod-left-3.png",
952                USE_ALPHA);
953
954   texture_load(&img_bsod_right[0], datadir +
955                "/images/shared/bsod-right-0.png",
956                USE_ALPHA);
957
958   texture_load(&img_bsod_right[1], datadir +
959                "/images/shared/bsod-right-1.png",
960                USE_ALPHA);
961
962   texture_load(&img_bsod_right[2], datadir +
963                "/images/shared/bsod-right-2.png",
964                USE_ALPHA);
965
966   texture_load(&img_bsod_right[3], datadir +
967                "/images/shared/bsod-right-3.png",
968                USE_ALPHA);
969
970   texture_load(&img_bsod_squished_left[0], datadir +
971                "/images/shared/bsod-squished-left.png",
972                USE_ALPHA);
973
974   texture_load(&img_bsod_squished_right[0], datadir +
975                "/images/shared/bsod-squished-right.png",
976                USE_ALPHA);
977
978   texture_load(&img_bsod_falling_left[0], datadir +
979                "/images/shared/bsod-falling-left.png",
980                USE_ALPHA);
981
982   texture_load(&img_bsod_falling_right[0], datadir +
983                "/images/shared/bsod-falling-right.png",
984                USE_ALPHA);
985
986
987   /* (Laptop) */
988
989   texture_load(&img_laptop_left[0], datadir +
990                "/images/shared/laptop-left-0.png",
991                USE_ALPHA);
992
993   texture_load(&img_laptop_left[1], datadir +
994                "/images/shared/laptop-left-1.png",
995                USE_ALPHA);
996
997   texture_load(&img_laptop_left[2], datadir +
998                "/images/shared/laptop-left-2.png",
999                USE_ALPHA);
1000
1001   texture_load(&img_laptop_right[0], datadir +
1002                "/images/shared/laptop-right-0.png",
1003                USE_ALPHA);
1004
1005   texture_load(&img_laptop_right[1], datadir +
1006                "/images/shared/laptop-right-1.png",
1007                USE_ALPHA);
1008
1009   texture_load(&img_laptop_right[2], datadir +
1010                "/images/shared/laptop-right-2.png",
1011                USE_ALPHA);
1012
1013   texture_load(&img_laptop_flat_left[0], datadir +
1014                "/images/shared/laptop-flat-left.png",
1015                USE_ALPHA);
1016
1017   texture_load(&img_laptop_flat_right[0], datadir +
1018                "/images/shared/laptop-flat-right.png",
1019                USE_ALPHA);
1020
1021   texture_load(&img_laptop_falling_left[0], datadir +
1022                "/images/shared/laptop-falling-left.png",
1023                USE_ALPHA);
1024
1025   texture_load(&img_laptop_falling_right[0], datadir +
1026                "/images/shared/laptop-falling-right.png",
1027                USE_ALPHA);
1028
1029
1030   /* (Money) */
1031
1032   texture_load(&img_money_left[0], datadir +
1033                "/images/shared/bag-left-0.png",
1034                USE_ALPHA);
1035
1036   texture_load(&img_money_left[1], datadir +
1037                "/images/shared/bag-left-1.png",
1038                USE_ALPHA);
1039
1040   texture_load(&img_money_right[0], datadir +
1041                "/images/shared/bag-right-0.png",
1042                USE_ALPHA);
1043
1044   texture_load(&img_money_right[1], datadir +
1045                "/images/shared/bag-right-1.png",
1046                USE_ALPHA);
1047
1048   /* Mr. Bomb */
1049   for(int i=0; i<4; ++i) {
1050       char num[4];
1051       snprintf(num, 4, "%d", i);
1052       texture_load(&img_mrbomb_left[i],
1053               datadir + "/images/shared/mrbomb-left-" + num + ".png", USE_ALPHA);
1054       texture_load(&img_mrbomb_right[i],
1055               datadir + "/images/shared/mrbomb-right-" + num + ".png", USE_ALPHA);
1056   }
1057   texture_load(&img_mrbomb_ticking_left[0],
1058           datadir + "/images/shared/mrbombx-left-0.png", USE_ALPHA);
1059   texture_load(&img_mrbomb_ticking_right[0],
1060           datadir + "/images/shared/mrbombx-right-0.png", USE_ALPHA);
1061   texture_load(&img_mrbomb_explosion[0],
1062           datadir + "/images/shared/mrbomb-explosion.png", USE_ALPHA);
1063
1064   /* stalactite */
1065   texture_load(&img_stalactite[0], 
1066           datadir + "/images/shared/stalactite.png", USE_ALPHA);
1067   texture_load(&img_stalactite_broken[0],
1068           datadir + "/images/shared/stalactite-broken.png", USE_ALPHA);
1069
1070   /* flame */
1071   texture_load(&img_flame[0],
1072           datadir + "/images/shared/flame-0.png", USE_ALPHA);
1073   texture_load(&img_flame[1],
1074           datadir + "/images/shared/flame-1.png", USE_ALPHA);  
1075
1076   /* fish */
1077   texture_load(&img_fish[0],
1078           datadir + "/images/shared/fish-left-0.png", USE_ALPHA);
1079   texture_load(&img_fish[1],
1080           datadir + "/images/shared/fish-left-1.png", USE_ALPHA);
1081
1082   /* bouncing snowball */
1083   for(int i=0; i<6; ++i) {
1084       char num[4];
1085       snprintf(num, 4, "%d", i);
1086       texture_load(&img_bouncingsnowball_left[i],
1087               datadir + "/images/shared/bouncingsnowball-left-" + num + ".png",
1088               USE_ALPHA);
1089       texture_load(&img_bouncingsnowball_right[i],
1090               datadir + "/images/shared/bouncingsnowball-right-" + num + ".png",
1091               USE_ALPHA);
1092   } 
1093   texture_load(&img_bouncingsnowball_squished[0],
1094           datadir + "/images/shared/bsod-squished-left.png", USE_ALPHA);
1095
1096   /* flying snowball */
1097   texture_load(&img_flyingsnowball[0],
1098           datadir + "/images/shared/flyingsnowball-left-0.png", USE_ALPHA);
1099   texture_load(&img_flyingsnowball[1],
1100           datadir + "/images/shared/flyingsnowball-left-1.png", USE_ALPHA);  
1101   texture_load(&img_flyingsnowball_squished[0],
1102           datadir + "/images/shared/bsod-squished-left.png", USE_ALPHA);
1103
1104   /* spiky */
1105   for(int i = 0; i < 3; ++i) {
1106         char num[4];
1107         snprintf(num, 4, "%d", i);
1108         texture_load(&img_spiky_left[i],                                 
1109                 datadir + "/images/shared/spiky-left-" + num + ".png",   
1110                 USE_ALPHA);
1111         texture_load(&img_spiky_right[i],
1112                 datadir + "/images/shared/spiky-right-" + num + ".png",
1113                 USE_ALPHA);
1114   }
1115
1116   /** snowball */
1117   texture_load(&img_snowball_left[0], datadir + "/images/shared/snowball-left-0.png", USE_ALPHA);
1118   texture_load(&img_snowball_left[1], datadir + "/images/shared/snowball-left-1.png", USE_ALPHA);
1119   texture_load(&img_snowball_left[2], datadir + "/images/shared/snowball-left-2.png", USE_ALPHA);
1120   texture_load(&img_snowball_left[3], datadir + "/images/shared/snowball-left-1.png", USE_ALPHA);
1121
1122   texture_load(&img_snowball_right[0], datadir + "/images/shared/snowball-right-0.png", USE_ALPHA);
1123   texture_load(&img_snowball_right[1], datadir + "/images/shared/snowball-right-1.png", USE_ALPHA);
1124   texture_load(&img_snowball_right[2], datadir + "/images/shared/snowball-right-2.png", USE_ALPHA);
1125   texture_load(&img_snowball_right[3], datadir + "/images/shared/snowball-right-1.png", USE_ALPHA);
1126
1127   texture_load(&img_snowball_squished_left[0],
1128           datadir + "/images/shared/bsod-squished-left.png", USE_ALPHA);
1129   texture_load(&img_snowball_squished_right[0],
1130           datadir + "/images/shared/bsod-squished-right.png", USE_ALPHA);  
1131 }
1132
1133 void free_badguy_gfx()
1134 {
1135   for (int i = 0; i < 4; i++)
1136     {
1137       texture_free(&img_bsod_left[i]);
1138       texture_free(&img_bsod_right[i]);
1139     }
1140
1141   texture_free(&img_bsod_squished_left[0]);
1142   texture_free(&img_bsod_squished_right[0]);
1143
1144   texture_free(&img_bsod_falling_left[0]);
1145   texture_free(&img_bsod_falling_right[0]);
1146
1147   for (int i = 0; i < 3; i++)
1148     {
1149       texture_free(&img_laptop_left[i]);
1150       texture_free(&img_laptop_right[i]);
1151     }
1152
1153   texture_free(&img_laptop_flat_left[0]);
1154   texture_free(&img_laptop_flat_right[0]);
1155
1156   texture_free(&img_laptop_falling_left[0]);
1157   texture_free(&img_laptop_falling_right[0]);
1158
1159   for (int i = 0; i < 2; i++)
1160     {
1161       texture_free(&img_money_left[i]);
1162       texture_free(&img_money_right[i]);
1163     }
1164
1165   for(int i = 0; i < 4; i++) {
1166       texture_free(&img_mrbomb_left[i]);
1167       texture_free(&img_mrbomb_right[i]);
1168   }
1169
1170   texture_free(&img_mrbomb_ticking_left[0]);
1171   texture_free(&img_mrbomb_ticking_right[0]);
1172   texture_free(&img_mrbomb_explosion[0]);
1173
1174   texture_free(&img_stalactite[0]);
1175   texture_free(&img_stalactite_broken[0]);
1176
1177   texture_free(&img_flame[0]);
1178   texture_free(&img_flame[1]);
1179
1180   texture_free(&img_fish[0]);
1181   texture_free(&img_fish[1]);
1182
1183   for(int i=0; i<6; ++i) {
1184     texture_free(&img_bouncingsnowball_left[i]);
1185     texture_free(&img_bouncingsnowball_right[i]);
1186   }
1187   texture_free(&img_bouncingsnowball_squished[0]);
1188
1189   texture_free(&img_flyingsnowball[0]);
1190   texture_free(&img_flyingsnowball[1]);
1191   texture_free(&img_flyingsnowball_squished[0]);
1192
1193   for(int i = 0; i<3; ++i) {
1194     texture_free(&img_spiky_left[i]);
1195     texture_free(&img_spiky_right[i]);
1196   }
1197   for(int i = 0; i<4; ++i) {
1198     texture_free(&img_snowball_left[i]);
1199     texture_free(&img_snowball_right[i]);
1200   }
1201   texture_free(&img_snowball_squished_left[0]);
1202   texture_free(&img_snowball_squished_right[0]); 
1203 }
1204
1205 // EOF //