2 // C Implementation: badguy
7 // Author: Tobias Glaesser <tobi.web@gmx.de> & Bill Kendrick, (C) 2004
9 // Copyright: See COPYING file that comes with this distribution
20 texture_type img_bsod_squished_left;
21 texture_type img_bsod_squished_right;
22 texture_type img_bsod_falling_left;
23 texture_type img_bsod_falling_right;
24 texture_type img_laptop_flat_left;
25 texture_type img_laptop_flat_right;
26 texture_type img_laptop_falling_left;
27 texture_type img_laptop_falling_right;
28 texture_type img_bsod_left[4];
29 texture_type img_bsod_right[4];
30 texture_type img_laptop_left[3];
31 texture_type img_laptop_right[3];
32 texture_type img_money_left[2];
33 texture_type img_money_right[2];
34 texture_type img_mrbomb_left[4];
35 texture_type img_mrbomb_right[4];
36 texture_type img_mrbomb_ticking_left;
37 texture_type img_mrbomb_ticking_right;
38 texture_type img_mrbomb_explosion;
39 texture_type img_stalactite;
40 texture_type img_stalactite_broken;
41 texture_type img_flame[2];
43 BadGuyKind badguykind_from_string(const std::string& str)
47 else if (str == "laptop")
49 else if (str == "bsod")
51 else if (str == "mrbomb")
53 else if (str == "stalactite")
54 return BAD_STALACTITE;
55 else if (str == "flame")
59 printf("Couldn't convert badguy: %s\n", str.c_str());
64 std::string badguykind_to_string(BadGuyKind kind)
92 BadGuy::init(float x, float y, BadGuyKind kind_)
106 timer_init(&timer, true);
107 physic_init(&physic);
109 if(kind == BAD_BOMB) {
110 timer_start(&timer, 1000);
112 // hack so that the bomb doesn't hurt until it expldes...
113 dying = DYING_SQUISHED;
114 } else if(kind == BAD_FLAME) {
115 base.ym = 0; // we misuse base.ym as angle for the flame
116 } else if(kind == BAD_MONEY) {
121 void BadGuy::action_bsod()
123 /* --- BLUE SCREEN OF DEATH MONSTER: --- */
125 /* Move left/right: */
126 if (dying == DYING_NOT || dying == DYING_FALLING)
128 base.x += base.xm * frame_ratio;
131 /* Move vertically: */
132 base.y += base.ym * frame_ratio;
134 if (dying != DYING_FALLING)
135 collision_swept_object_map(&old_base,&base);
138 check_horizontal_bump();
142 // Handle dying timer:
143 if (dying == DYING_SQUISHED && !timer_check(&timer))
145 /* Remove it if time's up: */
151 void BadGuy::action_laptop()
153 /* Move left/right: */
154 if (mode == NORMAL || mode == KICK)
156 if (dying == DYING_NOT ||
157 dying == DYING_FALLING)
159 base.x += base.xm * frame_ratio;
162 else if (mode == HELD)
163 { /* FIXME: The pbad object shouldn't know about pplayer objects. */
164 /* If we're holding the laptop */
168 base.x = tux.base.x + 16;
169 base.y = tux.base.y + tux.base.height/1.5 - base.height;
171 else /* facing left */
173 base.x = tux.base.x - 16;
174 base.y = tux.base.y + tux.base.height/1.5 - base.height;
176 if(collision_object_map(&base))
179 base.y = tux.base.y + tux.base.height/1.5 - base.height;
182 if(tux.input.fire != DOWN) /* SHOOT! */
192 play_sound(sounds[SND_KICK],SOUND_CENTER_SPEAKER);
197 /* Move vertically: */
199 base.y = base.y + base.ym * frame_ratio;
201 if (dying != DYING_FALLING)
202 collision_swept_object_map(&old_base,&base);
203 /* Bump into things horizontally: */
208 check_horizontal_bump();
209 if(mode == KICK && changed != dir)
211 /* handle stereo sound (number 10 should be tweaked...)*/
212 if (base.x < scroll_x + screen->w/2 - 10)
213 play_sound(sounds[SND_RICOCHET], SOUND_LEFT_SPEAKER);
214 else if (base.x > scroll_x + screen->w/2 + 10)
215 play_sound(sounds[SND_RICOCHET], SOUND_RIGHT_SPEAKER);
217 play_sound(sounds[SND_RICOCHET], SOUND_CENTER_SPEAKER);
223 /* Handle mode timer: */
226 if(!timer_check(&timer))
229 base.xm = (dir == LEFT) ? -1.3 : 1.3;
234 void BadGuy::check_horizontal_bump(bool checkcliff)
236 if (dir == LEFT && issolid( base.x, (int) base.y + 16))
242 if (dir == RIGHT && issolid( base.x + base.width, (int) base.y + 16))
249 // don't check for cliffs when we're falling
252 if(!issolid(base.x + base.width/2, base.y + base.height + 16))
255 if(dir == LEFT && !issolid(base.x, (int) base.y + base.height + 16))
257 printf("Cliffcol left\n");
262 if(dir == RIGHT && !issolid(base.x + base.width,
263 (int) base.y + base.height + 16))
265 printf("Cliffcol right\n");
272 void BadGuy::fall(bool dojump)
274 /* Fall if we get off the ground: */
275 if (dying != DYING_FALLING)
277 if (!issolid(base.x+base.width/2, base.y + base.height))
279 if(!physic_is_set(&physic))
281 physic_set_state(&physic,PH_VT);
282 physic_set_start_vy(&physic, dojump ? 2. : 0.);
285 base.ym = physic_get_velocity(&physic);
292 base.y = int((base.y + base.height)/32) * 32 - base.height;
295 physic_init(&physic);
300 if(!physic_is_set(&physic))
302 physic_set_state(&physic,PH_VT);
303 physic_set_start_vy(&physic,0.);
305 base.ym = physic_get_velocity(&physic);
308 // BadGuy fall below the ground
309 if (base.y > screen->h) {
315 void BadGuy::remove_me()
317 std::vector<BadGuy>::iterator i;
318 for(i = bad_guys.begin(); i != bad_guys.end(); ++i) {
319 if( & (*i) == this) {
326 void BadGuy::action_money()
328 /* Move vertically: */
329 base.y = base.y + base.ym * frame_ratio;
331 if (dying != DYING_FALLING)
332 collision_swept_object_map(&old_base,&base);
334 if (base.y > screen->h) {
339 if(physic_get_state(&physic) == -1)
341 physic_set_state(&physic,PH_VT);
342 physic_set_start_vy(&physic,0.);
345 if (dying != DYING_FALLING)
348 if(issolid(base.x, base.y + 32))
350 physic_set_state(&physic,PH_VT);
351 physic_set_start_vy(&physic,6.);
352 base.ym = physic_get_velocity(&physic);
357 base.ym = physic_get_velocity(&physic);
363 if(!physic_is_set(&physic))
365 physic_set_state(&physic,PH_VT);
366 physic_set_start_vy(&physic,0.);
368 base.ym = physic_get_velocity(&physic);
372 void BadGuy::action_mrbomb()
375 base.x += base.xm * frame_ratio;
378 /* Move vertically: */
379 base.y += base.ym * frame_ratio;
381 if (dying != DYING_FALLING)
382 collision_swept_object_map(&old_base,&base);
384 check_horizontal_bump(true);
388 void BadGuy::action_bomb()
390 // eventually fall down
391 base.y += base.ym * frame_ratio;
392 collision_swept_object_map(&old_base,&base);
395 if(!timer_check(&timer)) {
396 if(mode == BOMB_TICKING) {
398 dying = DYING_NOT; // now the bomb hurts
399 timer_start(&timer, 1000);
400 // explosion image has different size
401 base.x -= (img_mrbomb_explosion.w - base.width) / 2;
402 base.y -= img_mrbomb_explosion.h - base.height;
403 base.width = img_mrbomb_explosion.w;
404 base.height = img_mrbomb_explosion.h;
406 } else if(mode == BOMB_EXPLODE) {
413 void BadGuy::action_stalactite()
416 static const int range = 40;
417 // start shaking when tux is below the stalactite and at least 40 pixels
419 if(tux.base.x + 32 > base.x - range && tux.base.x < base.x + 32 + range
420 && tux.base.y + tux.base.height > base.y) {
421 timer_start(&timer, 800);
422 mode = STALACTITE_SHAKING;
424 } if(mode == STALACTITE_SHAKING) {
425 base.x = old_base.x + (rand() % 6) - 3; // TODO this could be done nicer...
426 if(!timer_check(&timer)) {
427 mode = STALACTITE_FALL;
429 } else if(mode == STALACTITE_FALL) {
430 base.y += base.ym * frame_ratio;
432 /* Destroy if collides land */
433 if(issolid(base.x+16, base.y+32))
435 timer_start(&timer, 3000);
436 dying = DYING_SQUISHED;
439 } else if(mode == FLAT) {
440 if(!timer_check(&timer)) {
447 BadGuy::action_flame()
449 static const float radius = 100;
450 static const float speed = 0.02;
451 base.x = old_base.x + cos(base.ym) * radius;
452 base.y = old_base.y + sin(base.ym) * radius;
454 base.ym = fmodf(base.ym + frame_ratio * speed, 2*M_PI);
460 // Remove if it's far off the screen:
461 if (base.x < scroll_x - OFFSCREEN_DISTANCE)
467 // Once it's on screen, it's activated!
468 if (base.x <= scroll_x + screen->w + OFFSCREEN_DISTANCE)
509 texture_type* texture = 0;
511 if(dying == DYING_NOT) {
512 size_t frame = (global_frame_counter / 5) % 4;
513 texture = (dir == LEFT) ? &img_bsod_left[frame] : &img_bsod_right[frame];
514 } else if(dying == DYING_FALLING) {
515 texture = (dir == LEFT) ? &img_bsod_falling_left : &img_bsod_falling_right;
516 } else if(dying == DYING_SQUISHED) {
517 texture = (dir == LEFT)
518 ? &img_bsod_squished_left : &img_bsod_squished_right;
521 texture_draw(texture, base.x - scroll_x, base.y);
525 BadGuy::draw_laptop()
527 texture_type* texture;
528 size_t frame = (global_frame_counter / 5) % 3;
530 if(dying == DYING_NOT) {
533 texture = &img_laptop_left[frame];
535 texture = &img_laptop_right[frame];
537 texture = (dir == LEFT) ? &img_laptop_flat_left : &img_laptop_flat_right;
540 texture = (dir == LEFT)
541 ? &img_laptop_falling_left : &img_laptop_falling_right;
544 texture_draw(texture, base.x - scroll_x, base.y);
550 texture_type* texture;
551 size_t frame = (mode == NORMAL) ? 0 : 1;
553 if(tux.base.x + tux.base.width < base.x) {
554 texture = &img_money_left[frame];
556 texture = &img_money_right[frame];
559 texture_draw(texture, base.x - scroll_x, base.y);
563 BadGuy::draw_mrbomb()
565 texture_type* texture;
566 size_t frame = (global_frame_counter/5) % 4;
569 texture = &img_mrbomb_left[frame];
571 texture = &img_mrbomb_right[frame];
573 texture_draw(texture, base.x - scroll_x, base.y);
579 texture_type* texture;
581 // TODO add real bomb graphics
582 if(mode == BOMB_TICKING) {
583 texture = (dir == LEFT)
584 ? &img_mrbomb_ticking_left : &img_mrbomb_ticking_right;
586 texture = &img_mrbomb_explosion;
589 texture_draw(texture, base.x - scroll_x, base.y);
593 BadGuy::draw_stalactite()
595 texture_type* texture;
597 texture = &img_stalactite;
599 texture = &img_stalactite_broken;
601 texture_draw(texture, base.x - scroll_x, base.y);
607 size_t frame = (global_frame_counter / 10) % 2;
608 texture_type* texture = &img_flame[frame];
610 texture_draw(texture, base.x - scroll_x, base.y);
616 // Don't try to draw stuff that is outside of the screen
617 if (base.x <= scroll_x - base.width || base.x >= scroll_x + screen->w)
656 if(kind == BAD_BSOD || kind == BAD_LAPTOP || kind == BAD_BOMB) {
657 dying = DYING_FALLING;
659 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
664 BadGuy::make_player_jump(Player* player)
666 physic_set_state(&player->vphysic,PH_VT);
667 physic_set_start_vy(&player->vphysic, 2.);
668 player->base.y = base.y - player->base.height - 2;
672 BadGuy::squich(Player* player)
674 if(kind == BAD_MRBOMB) {
675 // mrbomb transforms into a bomb now
676 add_bad_guy(base.x, base.y, BAD_BOMB);
678 make_player_jump(player);
679 add_score(base.x - scroll_x, base.y, 50 * score_multiplier);
680 play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
686 } else if(kind == BAD_BSOD) {
687 make_player_jump(player);
689 add_score(base.x - scroll_x, base.y, 50 * score_multiplier);
690 play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
693 dying = DYING_SQUISHED;
694 timer_start(&timer, 2000);
695 base.y += base.height - img_bsod_squished_left.h;
696 base.height = img_bsod_squished_left.h;
697 base.xm = base.ym = 0;
701 } else if (kind == BAD_LAPTOP) {
702 if (mode == NORMAL || mode == KICK)
705 play_sound(sounds[SND_STOMP], SOUND_CENTER_SPEAKER);
709 timer_start(&timer, 4000);
710 } else if (mode == FLAT) {
712 play_sound(sounds[SND_KICK], SOUND_CENTER_SPEAKER);
714 if (player->base.x < base.x + (base.width/2)) {
725 make_player_jump(player);
727 add_score(base.x - scroll_x, base.y, 25 * score_multiplier);
734 BadGuy::collision(void *p_c_object, int c_object, CollisionType type)
736 BadGuy* pbad_c = NULL;
738 if(type == COLLISION_BUMP) {
742 if(type == COLLISION_SQUICH) {
743 Player* player = static_cast<Player*>(p_c_object);
751 if(kind == BAD_BOMB || kind == BAD_STALACTITE || kind == BAD_FLAME)
754 dying = DYING_FALLING;
757 /* Gain some points: */
758 if (kind == BAD_BSOD)
759 add_score(base.x - scroll_x, base.y,
760 50 * score_multiplier);
761 else if (kind == BAD_LAPTOP)
762 add_score(base.x - scroll_x, base.y,
763 25 * score_multiplier);
764 else if (kind == BAD_MONEY)
765 add_score(base.x - scroll_x, base.y,
766 50 * score_multiplier);
768 /* Play death sound: */
769 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
773 pbad_c = (BadGuy*) p_c_object;
774 if(kind == BAD_LAPTOP && mode == KICK)
776 /* We're in kick mode, kill the other guy
777 and yourself(wuahaha) : */
779 pbad_c->dying = DYING_FALLING;
780 pbad_c->base.ym = -8;
781 play_sound(sounds[SND_FALL], SOUND_CENTER_SPEAKER);
783 add_score(base.x - scroll_x,
786 dying = DYING_FALLING;
789 add_score(pbad_c->base.x - scroll_x,
790 pbad_c->base.y, 100);
796 //---------------------------------------------------------------------------
798 void load_badguy_gfx()
801 texture_load(&img_bsod_left[0], datadir +
802 "/images/shared/bsod-left-0.png",
805 texture_load(&img_bsod_left[1], datadir +
806 "/images/shared/bsod-left-1.png",
809 texture_load(&img_bsod_left[2], datadir +
810 "/images/shared/bsod-left-2.png",
813 texture_load(&img_bsod_left[3], datadir +
814 "/images/shared/bsod-left-3.png",
817 texture_load(&img_bsod_right[0], datadir +
818 "/images/shared/bsod-right-0.png",
821 texture_load(&img_bsod_right[1], datadir +
822 "/images/shared/bsod-right-1.png",
825 texture_load(&img_bsod_right[2], datadir +
826 "/images/shared/bsod-right-2.png",
829 texture_load(&img_bsod_right[3], datadir +
830 "/images/shared/bsod-right-3.png",
833 texture_load(&img_bsod_squished_left, datadir +
834 "/images/shared/bsod-squished-left.png",
837 texture_load(&img_bsod_squished_right, datadir +
838 "/images/shared/bsod-squished-right.png",
841 texture_load(&img_bsod_falling_left, datadir +
842 "/images/shared/bsod-falling-left.png",
845 texture_load(&img_bsod_falling_right, datadir +
846 "/images/shared/bsod-falling-right.png",
852 texture_load(&img_laptop_left[0], datadir +
853 "/images/shared/laptop-left-0.png",
856 texture_load(&img_laptop_left[1], datadir +
857 "/images/shared/laptop-left-1.png",
860 texture_load(&img_laptop_left[2], datadir +
861 "/images/shared/laptop-left-2.png",
864 texture_load(&img_laptop_right[0], datadir +
865 "/images/shared/laptop-right-0.png",
868 texture_load(&img_laptop_right[1], datadir +
869 "/images/shared/laptop-right-1.png",
872 texture_load(&img_laptop_right[2], datadir +
873 "/images/shared/laptop-right-2.png",
876 texture_load(&img_laptop_flat_left, datadir +
877 "/images/shared/laptop-flat-left.png",
880 texture_load(&img_laptop_flat_right, datadir +
881 "/images/shared/laptop-flat-right.png",
884 texture_load(&img_laptop_falling_left, datadir +
885 "/images/shared/laptop-falling-left.png",
888 texture_load(&img_laptop_falling_right, datadir +
889 "/images/shared/laptop-falling-right.png",
895 texture_load(&img_money_left[0], datadir +
896 "/images/shared/bag-left-0.png",
899 texture_load(&img_money_left[1], datadir +
900 "/images/shared/bag-left-1.png",
903 texture_load(&img_money_right[0], datadir +
904 "/images/shared/bag-right-0.png",
907 texture_load(&img_money_right[1], datadir +
908 "/images/shared/bag-right-1.png",
912 for(int i=0; i<4; ++i) {
914 snprintf(num, 4, "%d", i);
915 texture_load(&img_mrbomb_left[i],
916 datadir + "/images/shared/mrbomb-left-" + num + ".png", USE_ALPHA);
917 texture_load(&img_mrbomb_right[i],
918 datadir + "/images/shared/mrbomb-right-" + num + ".png", USE_ALPHA);
920 texture_load(&img_mrbomb_ticking_left,
921 datadir + "/images/shared/mrbombx-left-0.png", USE_ALPHA);
922 texture_load(&img_mrbomb_ticking_right,
923 datadir + "/images/shared/mrbombx-right-0.png", USE_ALPHA);
924 texture_load(&img_mrbomb_explosion,
925 datadir + "/images/shared/mrbomb-explosion.png", USE_ALPHA);
928 texture_load(&img_stalactite,
929 datadir + "/images/shared/stalactite.png", USE_ALPHA);
930 texture_load(&img_stalactite_broken,
931 datadir + "/images/shared/stalactite-broken.png", USE_ALPHA);
934 texture_load(&img_flame[0],
935 datadir + "/images/shared/flame-0.png", USE_ALPHA);
936 texture_load(&img_flame[1],
937 datadir + "/images/shared/flame-1.png", USE_ALPHA);
940 void free_badguy_gfx()
942 for (int i = 0; i < 4; i++)
944 texture_free(&img_bsod_left[i]);
945 texture_free(&img_bsod_right[i]);
948 texture_free(&img_bsod_squished_left);
949 texture_free(&img_bsod_squished_right);
951 texture_free(&img_bsod_falling_left);
952 texture_free(&img_bsod_falling_right);
954 for (int i = 0; i < 3; i++)
956 texture_free(&img_laptop_left[i]);
957 texture_free(&img_laptop_right[i]);
960 texture_free(&img_laptop_flat_left);
961 texture_free(&img_laptop_flat_right);
963 texture_free(&img_laptop_falling_left);
964 texture_free(&img_laptop_falling_right);
966 for (int i = 0; i < 2; i++)
968 texture_free(&img_money_left[i]);
969 texture_free(&img_money_right[i]);
972 for(int i = 0; i < 4; i++) {
973 texture_free(&img_mrbomb_left[i]);
974 texture_free(&img_mrbomb_right[i]);
977 texture_free(&img_mrbomb_ticking_left);
978 texture_free(&img_mrbomb_ticking_right);
979 texture_free(&img_mrbomb_explosion);
981 texture_free(&img_stalactite);
982 texture_free(&img_stalactite_broken);
984 texture_free(&img_flame[0]);
985 texture_free(&img_flame[1]);