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