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