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