fixed some "solids" to be non-solid
[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
13 #include "globals.h"
14 #include "defines.h"
15 #include "badguy.h"
16 #include "scene.h"
17 #include "screen.h"
18
19 texture_type img_bsod_squished_left;
20 texture_type img_bsod_squished_right;
21 texture_type img_bsod_falling_left;
22 texture_type img_bsod_falling_right;
23 texture_type img_laptop_flat_left;
24 texture_type img_laptop_flat_right;
25 texture_type img_laptop_falling_left;
26 texture_type img_laptop_falling_right;
27 texture_type img_bsod_left[4];
28 texture_type img_bsod_right[4];
29 texture_type img_laptop_left[3];
30 texture_type img_laptop_right[3];
31 texture_type img_money_left[2];
32 texture_type img_money_right[2];
33
34 BadGuyKind  badguykind_from_string(const std::string& str)
35 {
36   if (str == "money")
37     return BAD_MONEY;
38   else if (str == "laptop")
39     return BAD_LAPTOP;
40   else if (str == "bsod")
41     return BAD_BSOD;
42   else
43     {
44       printf("Couldn't convert badguy: %s\n", str.c_str());
45       return BAD_BSOD;
46     }
47 }
48
49 std::string badguykind_to_string(BadGuyKind kind)
50 {
51   switch(kind)
52     {
53     case BAD_MONEY:
54       return "money";
55       break;
56     case BAD_LAPTOP:
57       return "laptop";
58       break;
59     case BAD_BSOD:
60       return "bsod";
61       break;
62     default:
63       return "bsod";
64     }
65 }
66
67 void
68 BadGuy::init(float x, float y, BadGuyKind kind_)
69 {
70   base.width  = 32;
71   base.height = 32;
72   mode     = NORMAL;
73   dying    = DYING_NOT;
74   kind     = kind_;
75   base.x   = x;
76   base.y   = y;
77   base.xm  = 1.3;
78   base.ym  = 4.8;
79   old_base = base;
80   dir      = LEFT;
81   seen     = false;
82   timer_init(&timer, true);
83   physic_init(&physic);
84 }
85
86 void BadGuy::action_bsod()
87 {
88   /* --- BLUE SCREEN OF DEATH MONSTER: --- */
89
90   /* Move left/right: */
91   if (dying == DYING_NOT ||
92       dying == DYING_FALLING)
93     {
94       if (dir == RIGHT)
95         base.x = base.x + base.xm * frame_ratio;
96       else if (dir == LEFT)
97         base.x = base.x - base.xm * frame_ratio;
98     }
99
100   /* Move vertically: */
101   base.y = base.y + base.ym * frame_ratio;
102
103   if (dying != DYING_FALLING)
104     collision_swept_object_map(&old_base,&base);
105   if (base.y > screen->h)
106     bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(this));
107                 
108   /* Bump into things horizontally: */
109
110   if (!dying)
111     {
112       if (issolid( base.x, (int) base.y + 16))
113         {
114           dir = RIGHT;
115         }
116       else if (issolid( base.x + base.width, (int) base.y + 16))
117         {
118           dir = LEFT;
119         }
120     }
121
122   /* Fall if we get off the ground: */
123   if (dying != DYING_FALLING)
124     {
125       if (!issolid(base.x+16, base.y + 32))
126         {
127           if(!physic_is_set(&physic))
128             {
129               physic_set_state(&physic,PH_VT);
130               physic_set_start_vy(&physic,2.);
131             }
132
133           base.ym = physic_get_velocity(&physic);
134         }
135       else
136         {
137           /* Land: */
138
139           if (base.ym > 0)
140             {
141               base.y = (int)(base.y / 32) * 32;
142               base.ym = 0;
143             }
144           physic_init(&physic);
145         }
146     }
147   else
148     {
149       if(!physic_is_set(&physic))
150         {
151           physic_set_state(&physic,PH_VT);
152           physic_set_start_vy(&physic,2.);
153         }
154       base.ym = physic_get_velocity(&physic);
155     }
156
157   // BadGuy fall below the ground
158   if (base.y > screen->h)
159     bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(this));
160 }
161
162 void BadGuy::action_laptop()
163 {
164   /* Move left/right: */
165   if (mode == NORMAL || mode == KICK)
166     {
167       if (dying == DYING_NOT ||
168           dying == DYING_FALLING)
169         {
170           if (dir == RIGHT)
171             base.x = base.x + base.xm * frame_ratio;
172           else if (dir == LEFT)
173             base.x = base.x - base.xm * frame_ratio;
174         }
175     }
176   else if (mode == HELD)
177     { /* FIXME: The pbad object shouldn't know about pplayer objects. */
178       /* If we're holding the laptop */
179       dir=tux.dir;
180       if(dir==RIGHT)
181         {
182           base.x = tux.base.x + 16;
183           base.y = tux.base.y + tux.base.height/1.5 - base.height;
184         }
185       else /* facing left */
186         {
187           base.x = tux.base.x - 16;
188           base.y = tux.base.y + tux.base.height/1.5 - base.height;
189         }
190       if(collision_object_map(&base))
191         {
192           base.x = tux.base.x;
193           base.y = tux.base.y + tux.base.height/1.5 - base.height;
194         }
195
196       if(tux.input.fire != DOWN) /* SHOOT! */
197         {
198           if(dir == LEFT)
199             base.x -= 24;
200           else
201             base.x += 24;
202
203           mode=KICK;
204           base.xm = 8;
205           base.ym = 8;
206           play_sound(sounds[SND_KICK],SOUND_CENTER_SPEAKER);
207         }
208     }
209
210
211   /* Move vertically: */
212   if(mode != HELD)
213     base.y = base.y + base.ym * frame_ratio;
214
215   if (dying != DYING_FALLING)
216     collision_swept_object_map(&old_base,&base);
217   if (base.y > screen->h)
218     bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(this));
219   /* Bump into things horizontally: */
220
221   /* Bump into things horizontally: */
222
223   if (!dying)
224     {
225       int changed = dir;
226       if (issolid( base.x, (int) base.y + 16))
227         {
228           dir = RIGHT;
229         }
230       else if (issolid( base.x + base.width, (int) base.y + 16))
231         {
232           dir = LEFT;
233         }
234       if(mode == KICK && changed != dir)
235         {
236           /* handle stereo sound */
237           /* FIXME: In theory a badguy object doesn't know anything about player objects */
238           if (tux.base.x  > base.x)
239             play_sound(sounds[SND_RICOCHET], SOUND_LEFT_SPEAKER);
240           else if (tux.base.x  < base.x)
241             play_sound(sounds[SND_RICOCHET], SOUND_RIGHT_SPEAKER);
242           else
243             play_sound(sounds[SND_RICOCHET], SOUND_CENTER_SPEAKER);
244         }
245
246     }
247
248   /* Fall if we get off the ground: */
249   if (dying != DYING_FALLING)
250     {
251       if (!issolid(base.x+16, base.y + 32))
252         {
253           if(!physic_is_set(&physic))
254             {
255               physic_set_state(&physic,PH_VT);
256               physic_set_start_vy(&physic,0.);
257             }
258
259           if(mode != HELD)
260             {
261               base.ym = physic_get_velocity(&physic);
262             }
263         }
264       else
265         {
266           /* Land: */
267
268           if (base.ym > 0)
269             {
270               base.y = (int)(base.y / 32) * 32;
271               base.ym = 0;
272             }
273           physic_init(&physic);
274         }
275     }
276   else
277     {
278       if(!physic_is_set(&physic))
279         {
280           physic_set_state(&physic,PH_VT);
281           physic_set_start_vy(&physic,0.);
282         }
283       base.ym = physic_get_velocity(&physic);
284     }
285 }
286
287 void BadGuy::action_money()
288 {
289   /* Move vertically: */
290   base.y = base.y + base.ym * frame_ratio;
291
292   if (dying != DYING_FALLING)
293     collision_swept_object_map(&old_base,&base);
294
295   if (base.y > screen->h)
296     bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(this));
297
298   if(physic_get_state(&physic) == -1)
299     {
300       physic_set_state(&physic,PH_VT);
301       physic_set_start_vy(&physic,0.);
302     }
303
304   if (dying != DYING_FALLING)
305     {
306       if(issolid(base.x, base.y + 32))
307         {
308           physic_set_state(&physic,PH_VT);
309           physic_set_start_vy(&physic,6.);
310           base.ym = physic_get_velocity(&physic);
311         }
312       else if(issolid(base.x, base.y))
313         { /* This works, but isn't the best solution imagineable */
314           physic_set_state(&physic,PH_VT);
315           physic_set_start_vy(&physic,0.);
316           base.ym = physic_get_velocity(&physic);
317           ++base.y;
318         }
319       else
320         {
321           base.ym = physic_get_velocity(&physic);
322         }
323     }
324   else
325     {
326       if(!physic_is_set(&physic))
327         {
328           physic_set_state(&physic,PH_VT);
329           physic_set_start_vy(&physic,0.);
330         }
331       base.ym = physic_get_velocity(&physic);
332     } 
333 }
334
335 void
336 BadGuy::action()
337
338   if (seen)
339     {
340       switch (kind)
341         {
342         case BAD_BSOD:
343           action_bsod();
344           break;
345     
346         case BAD_LAPTOP:
347           action_bsod();
348           break;
349       
350         case BAD_MONEY:
351           action_money();
352           break;
353         }
354     }
355
356   /* Handle mode timer: */
357   if (mode == FLAT && mode != HELD)
358     {
359       if(!timer_check(&timer))
360         {
361           mode = NORMAL;
362           base.xm = 4;
363         }
364     }
365   else if (mode == KICK)
366     {
367       timer_check(&timer);
368     }
369
370   // Handle dying timer:
371   if (dying == DYING_SQUISHED)
372     {
373       /* Remove it if time's up: */
374       if(!timer_check(&timer))
375         bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(this));
376     }
377
378   // Remove if it's far off the screen:
379   if (base.x < scroll_x - OFFSCREEN_DISTANCE)
380     {
381       bad_guys.erase(static_cast<std::vector<BadGuy>::iterator>(this));
382       return;
383     }
384   else /* !seen */
385     {
386       // Once it's on screen, it's activated!
387       if (base.x <= scroll_x + screen->w + OFFSCREEN_DISTANCE)
388         seen = true;
389     }
390 }
391
392 void
393 BadGuy::draw_bsod()
394 {
395   /* --- BLUE SCREEN OF DEATH MONSTER: --- */
396   if (dying == DYING_NOT)
397     {
398       /* Alive: */
399       if (dir == LEFT)
400         {
401           texture_draw(&img_bsod_left[(global_frame_counter / 5) % 4],
402                        base.x - scroll_x,
403                        base.y);
404         }
405       else
406         {
407           texture_draw(&img_bsod_right[(global_frame_counter / 5) % 4],
408                        base.x - scroll_x,
409                        base.y);
410         }
411     }
412   else if (dying == DYING_FALLING)
413     {
414       /* Falling: */
415
416       if (dir == LEFT)
417         {
418           texture_draw(&img_bsod_falling_left,
419                        base.x - scroll_x,
420                        base.y);
421         }
422       else
423         {
424           texture_draw(&img_bsod_falling_right,
425                        base.x - scroll_x,
426                        base.y);
427         }
428     }
429   else if (dying == DYING_SQUISHED)
430     {
431       /* Dying - Squished: */
432
433       if (dir == LEFT)
434         {
435           texture_draw(&img_bsod_squished_left,
436                        base.x - scroll_x,
437                        base.y + 24);
438         }
439       else
440         {
441           texture_draw(&img_bsod_squished_right,
442                        base.x - scroll_x,
443                        base.y + 24);
444         }
445     }
446 }
447
448 void BadGuy::draw_laptop()
449 {
450   /* --- LAPTOP MONSTER: --- */
451   if (dying == DYING_NOT)
452     {
453       /* Alive: */
454
455       if (mode == NORMAL)
456         {
457           /* Not flat: */
458           if (dir == LEFT)
459             {
460               texture_draw(&img_laptop_left[(global_frame_counter / 5) % 3],
461                            base.x - scroll_x,
462                            base.y);
463             }
464           else
465             {
466               texture_draw(&img_laptop_right[(global_frame_counter / 5) % 3],
467                            base.x - scroll_x,
468                            base.y);
469             }
470         }
471       else
472         {
473           /* Flat: */
474
475           if (dir == LEFT)
476             {
477               texture_draw(&img_laptop_flat_left,
478                            base.x - scroll_x,
479                            base.y);
480             }
481           else
482             {
483               texture_draw(&img_laptop_flat_right,
484                            base.x - scroll_x,
485                            base.y);
486             }
487         }
488     }
489   else if (dying == DYING_FALLING)
490     {
491       /* Falling: */
492
493       if (dir == LEFT)
494         {
495           texture_draw(&img_laptop_falling_left,
496                        base.x - scroll_x,
497                        base.y);
498         }
499       else
500         {
501           texture_draw(&img_laptop_falling_right,
502                        base.x - scroll_x,
503                        base.y);
504         }
505     }
506 }
507
508 void BadGuy::draw_money()
509 {
510   if (base.ym != 300 /* > -16*/)
511     {
512       if (dir == LEFT)
513         {
514           texture_draw(&img_money_left[0],
515                        base.x - scroll_x,
516                        base.y);
517         }
518       else
519         {
520           texture_draw(&img_money_right[0],
521                        base.x - scroll_x,
522                        base.y);
523         }
524     }
525   else
526     {
527       if (dir == LEFT)
528         {
529           texture_draw(&img_money_left[1],
530                        base.x - scroll_x,
531                        base.y);
532         }
533       else
534         {
535           texture_draw(&img_money_right[1],
536                        base.x - scroll_x,
537                        base.y);
538         }
539     }
540 }
541
542 void BadGuy::draw()
543 {
544   // Don't try to draw stuff that is outside of the screen
545   if (base.x > scroll_x - 32 &&
546       base.x < scroll_x + screen->w)
547     {
548       switch (kind)
549         {
550         case BAD_BSOD:
551           draw_bsod();
552           break;
553     
554         case BAD_LAPTOP:
555           draw_laptop();
556           break;
557     
558         case BAD_MONEY:
559           draw_money();
560           break;
561
562         default:
563           puts("Unknown badguy type");
564           break;
565         }
566     }
567 }
568
569 void
570 BadGuy::collision(void *p_c_object, int c_object)
571 {
572   BadGuy* pbad_c    = NULL;
573   Player* pplayer_c = NULL;
574
575   switch (c_object)
576     {
577     case CO_BULLET:
578       dying = DYING_FALLING;
579       base.ym = -8;
580
581       /* Gain some points: */
582       if (kind == BAD_BSOD)
583         add_score(base.x - scroll_x, base.y,
584                   50 * score_multiplier);
585       else if (kind == BAD_LAPTOP)
586         add_score(base.x - scroll_x, base.y,
587                   25 * score_multiplier);
588       else if (kind == BAD_MONEY)
589         add_score(base.x - scroll_x, base.y,
590                   50 * score_multiplier);
591
592       /* Play death sound: */
593       play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
594       break;
595
596     case CO_BADGUY:
597       pbad_c = (BadGuy*) p_c_object;
598       if (mode == NORMAL)
599       {
600       /* do nothing */
601       }
602       else if(mode == KICK)
603         {
604           /* We're in kick mode, kill the other guy
605              and yourself(wuahaha) : */
606
607           pbad_c->dying = DYING_FALLING;
608           pbad_c->base.ym = -8;
609           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
610
611           add_score(base.x - scroll_x,
612                     base.y, 100);
613                   pbad_c->dying = DYING_FALLING;
614                   
615           dying = DYING_FALLING;
616           base.ym = -8;
617
618           add_score(pbad_c->base.x - scroll_x,
619                     pbad_c->base.y, 100);
620         }
621       break;
622
623     case CO_PLAYER:
624       pplayer_c = static_cast<Player*>(p_c_object);
625       if(kind != BAD_MONEY)
626         {
627           if (kind == BAD_BSOD)
628             {
629               dying = DYING_SQUISHED;
630               timer_start(&timer,4000);
631               physic_set_state(&pplayer_c->vphysic,PH_VT);
632               physic_set_start_vy(&pplayer_c->vphysic,2.);
633               pplayer_c->base.y = base.y - pplayer_c->base.height - 1;
634
635               add_score(base.x - scroll_x, base.y,
636                         50 * score_multiplier);
637
638               play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
639             }
640           else if (kind == BAD_LAPTOP)
641             {
642
643               if (mode == NORMAL || mode == KICK)
644                 {
645                   /* Flatten! */
646
647                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
648                   mode = FLAT;
649                   base.xm = 4;
650
651                   timer_start(&timer,10000);
652
653                   physic_set_state(&pplayer_c->vphysic,PH_VT);
654                   physic_set_start_vy(&pplayer_c->vphysic,2.);
655                   pplayer_c->base.y = base.y - pplayer_c->base.height - 1;
656                 }
657               else if (mode == FLAT)
658                 {
659                   /* Kick! */
660                   play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
661
662                   if (pplayer_c->base.x < base.x + (base.width/2))
663                     dir = RIGHT;
664                   else
665                     dir = LEFT;
666
667                   base.xm = 5;
668                   mode = KICK;
669
670                   timer_start(&timer,5000);
671                 }
672                 
673               physic_set_state(&pplayer_c->vphysic,PH_VT);
674               physic_set_start_vy(&pplayer_c->vphysic,2.);
675               pplayer_c->base.y = base.y - pplayer_c->base.height - 1;
676               
677               add_score(base.x - scroll_x,
678                         base.y,
679                         25 * score_multiplier);
680
681               /* play_sound(sounds[SND_SQUISH]); */
682             }
683           score_multiplier++;
684         }
685       break;
686     }
687
688 }
689
690 // EOF //