- removed NO_UPDATE and let the default argument handle it
[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                 }
382               else
383                 {
384                   texture_draw(&img_bsod_right[(frame / 5) % 4],
385                                pbad->base.x - scroll_x,
386                                pbad->base.y);
387                 }
388             }
389           else if (pbad->dying == DYING_FALLING)
390             {
391               /* Falling: */
392
393               if (pbad->dir == LEFT)
394                 {
395                   texture_draw(&img_bsod_falling_left,
396                                pbad->base.x - scroll_x,
397                                pbad->base.y);
398                 }
399               else
400                 {
401                   texture_draw(&img_bsod_falling_right,
402                                pbad->base.x - scroll_x,
403                                pbad->base.y);
404                 }
405             }
406           else if (pbad->dying == DYING_SQUISHED)
407             {
408               /* Dying - Squished: */
409
410               if (pbad->dir == LEFT)
411                 {
412                   texture_draw(&img_bsod_squished_left,
413                                pbad->base.x - scroll_x,
414                                pbad->base.y + 24);
415                 }
416               else
417                 {
418                   texture_draw(&img_bsod_squished_right,
419                                pbad->base.x - scroll_x,
420                                pbad->base.y + 24);
421                 }
422             }
423         }
424       else if (pbad->kind == BAD_LAPTOP)
425         {
426           /* --- LAPTOP MONSTER: --- */
427
428           if (pbad->dying == DYING_NOT)
429             {
430               /* Alive: */
431
432               if (pbad->mode == NORMAL)
433                 {
434                   /* Not flat: */
435
436                   if (pbad->dir == LEFT)
437                     {
438                       texture_draw(&img_laptop_left[(frame / 5) % 3],
439                                    pbad->base.x - scroll_x,
440                                    pbad->base.y);
441                     }
442                   else
443                     {
444                       texture_draw(&img_laptop_right[(frame / 5) % 3],
445                                    pbad->base.x - scroll_x,
446                                    pbad->base.y);
447                     }
448                 }
449               else
450                 {
451                   /* Flat: */
452
453                   if (pbad->dir == LEFT)
454                     {
455                       texture_draw(&img_laptop_flat_left,
456                                    pbad->base.x - scroll_x,
457                                    pbad->base.y);
458                     }
459                   else
460                     {
461                       texture_draw(&img_laptop_flat_right,
462                                    pbad->base.x - scroll_x,
463                                    pbad->base.y);
464                     }
465                 }
466             }
467           else if (pbad->dying == DYING_FALLING)
468             {
469               /* Falling: */
470
471               if (pbad->dir == LEFT)
472                 {
473                   texture_draw(&img_laptop_falling_left,
474                                pbad->base.x - scroll_x,
475                                pbad->base.y);
476                 }
477               else
478                 {
479                   texture_draw(&img_laptop_falling_right,
480                                pbad->base.x - scroll_x,
481                                pbad->base.y);
482                 }
483             }
484         }
485       else if (pbad->kind == BAD_MONEY)
486         {
487           if (pbad->base.ym != 300 /* > -16*/)
488             {
489               if (pbad->dir == LEFT)
490                 {
491                   texture_draw(&img_money_left[0],
492                                pbad->base.x - scroll_x,
493                                pbad->base.y);
494                 }
495               else
496                 {
497                   texture_draw(&img_money_right[0],
498                                pbad->base.x - scroll_x,
499                                pbad->base.y);
500                 }
501             }
502           else
503             {
504               if (pbad->dir == LEFT)
505                 {
506                   texture_draw(&img_money_left[1],
507                                pbad->base.x - scroll_x,
508                                pbad->base.y);
509                 }
510               else
511                 {
512                   texture_draw(&img_money_right[1],
513                                pbad->base.x - scroll_x,
514                                pbad->base.y);
515                 }
516             }
517         }
518       else if (pbad->kind == -1)
519       {}
520     }
521 }
522
523 void badguy_collision(bad_guy_type* pbad, void *p_c_object, int c_object)
524 {
525   bad_guy_type* pbad_c = NULL;
526   player_type* pplayer_c = NULL;
527
528   switch (c_object)
529     {
530     case CO_BULLET:
531       pbad->dying = DYING_FALLING;
532       pbad->base.ym = -8;
533
534       /* Gain some points: */
535
536       if (pbad->kind == BAD_BSOD)
537         add_score(pbad->base.x - scroll_x, pbad->base.y,
538                   50 * score_multiplier);
539       else if (pbad->kind == BAD_LAPTOP)
540         add_score(pbad->base.x - scroll_x, pbad->base.y,
541                   25 * score_multiplier);
542       else if (pbad->kind == BAD_MONEY)
543         add_score(pbad->base.x - scroll_x, pbad->base.y,
544                   50 * score_multiplier);
545
546       /* Play death sound: */
547       play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
548       break;
549     case CO_BADGUY:
550       pbad_c = (bad_guy_type*) p_c_object;
551       if (pbad->mode == NORMAL)
552       {
553       /* do nothing */
554       }
555       else if(pbad->mode == KICK)
556         {
557           /* We're in kick mode, kill the other guy
558              and yourself(wuahaha) : */
559
560           pbad_c->dying = DYING_FALLING;
561           pbad_c->base.ym = -8;
562           play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
563
564           add_score(pbad->base.x - scroll_x,
565                     pbad->base.y, 100);
566                   pbad_c->dying = DYING_FALLING;
567                   
568           pbad->dying = DYING_FALLING;
569           pbad->base.ym = -8;
570
571           add_score(pbad_c->base.x - scroll_x,
572                     pbad_c->base.y, 100);
573         }
574       break;
575     case CO_PLAYER:
576       pplayer_c = (player_type*) p_c_object;
577       if(pbad->kind != BAD_MONEY)
578         {
579           if (pbad->kind == BAD_BSOD)
580             {
581               pbad->dying = DYING_SQUISHED;
582               timer_start(&pbad->timer,4000);
583               physic_set_state(&pplayer_c->vphysic,PH_VT);
584               physic_set_start_vy(&pplayer_c->vphysic,2.);
585               pplayer_c->base.y = pbad->base.y - pplayer_c->base.height - 1;
586
587               add_score(pbad->base.x - scroll_x, pbad->base.y,
588                         50 * score_multiplier);
589
590               play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
591             }
592           else if (pbad->kind == BAD_LAPTOP)
593             {
594
595               if (pbad->mode == NORMAL || pbad->mode == KICK)
596                 {
597                   /* Flatten! */
598
599                   play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
600                   pbad->mode = FLAT;
601                   pbad->base.xm = 4;
602
603                   timer_start(&pbad->timer,10000);
604
605                   physic_set_state(&pplayer_c->vphysic,PH_VT);
606                   physic_set_start_vy(&pplayer_c->vphysic,2.);
607                   pplayer_c->base.y = pbad->base.y - pplayer_c->base.height - 1;
608                 }
609               else if (pbad->mode == FLAT)
610                 {
611                   /* Kick! */
612                   play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
613
614                   if (pplayer_c->base.x < pbad->base.x + (pbad->base.width/2))
615                     pbad->dir = RIGHT;
616                   else
617                     pbad->dir = LEFT;
618
619                   pbad->base.xm = 5;
620                   pbad->mode = KICK;
621
622                   timer_start(&pbad->timer,5000);
623                 }
624                 
625               physic_set_state(&pplayer_c->vphysic,PH_VT);
626               physic_set_start_vy(&pplayer_c->vphysic,2.);
627               pplayer_c->base.y = pbad->base.y - pplayer_c->base.height - 1;
628               
629               add_score(pbad->base.x - scroll_x,
630                         pbad->base.y,
631                         25 * score_multiplier);
632
633               /* play_sound(sounds[SND_SQUISH]); */
634             }
635           score_multiplier++;
636         }
637       break;
638     }
639
640 }