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