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