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