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