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