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