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