+#include "tile.h"
+#include "resources.h"
+#include "sprite_manager.h"
+#include "camera.h"
+#include "lispwriter.h"
+#include "level.h"
+#include "sector.h"
+#include "tilemap.h"
+
+Sprite* img_mriceblock_flat_left;
+Sprite* img_mriceblock_flat_right;
+Sprite* img_mriceblock_falling_left;
+Sprite* img_mriceblock_falling_right;
+Sprite* img_mriceblock_left;
+Sprite* img_mriceblock_right;
+Sprite* img_jumpy_left_up;
+Sprite* img_jumpy_left_down;
+Sprite* img_jumpy_left_middle;
+Sprite* img_jumpy_left_iced;
+Sprite* img_mrbomb_left;
+Sprite* img_mrbomb_right;
+Sprite* img_mrbomb_iced_left;
+Sprite* img_mrbomb_iced_right;
+Sprite* img_mrbomb_ticking_left;
+Sprite* img_mrbomb_ticking_right;
+Sprite* img_mrbomb_explosion;
+Sprite* img_stalactite;
+Sprite* img_stalactite_broken;
+Sprite* img_flame;
+Sprite* img_fish;
+Sprite* img_fish_down;
+Sprite* img_fish_iced;
+Sprite* img_fish_iced_down;
+Sprite* img_bouncingsnowball_left;
+Sprite* img_bouncingsnowball_right;
+Sprite* img_bouncingsnowball_squished;
+Sprite* img_flyingsnowball;
+Sprite* img_flyingsnowball_squished;
+Sprite* img_spiky_left;
+Sprite* img_spiky_right;
+Sprite* img_spiky_iced_left;
+Sprite* img_spiky_iced_right;
+Sprite* img_snowball_left;
+Sprite* img_snowball_right;
+Sprite* img_snowball_squished_left;
+Sprite* img_snowball_squished_right;
+Sprite* img_wingling_left;
+Sprite* img_walkingtree_left;
+Sprite* img_walkingtree_left_small;
+
+#define BADGUY_WALK_SPEED .8f
+#define WINGLING_FLY_SPEED 1.6f
+
+BadGuyKind badguykind_from_string(const std::string& str)
+{
+ if (str == "money" || str == "jumpy") // was money in old maps
+ return BAD_JUMPY;
+ else if (str == "laptop" || str == "mriceblock") // was laptop in old maps
+ return BAD_MRICEBLOCK;
+ else if (str == "mrbomb")
+ return BAD_MRBOMB;
+ else if (str == "stalactite")
+ return BAD_STALACTITE;
+ else if (str == "flame")
+ return BAD_FLAME;
+ else if (str == "fish")
+ return BAD_FISH;
+ else if (str == "bouncingsnowball")
+ return BAD_BOUNCINGSNOWBALL;
+ else if (str == "flyingsnowball")
+ return BAD_FLYINGSNOWBALL;
+ else if (str == "spiky")
+ return BAD_SPIKY;
+ else if (str == "snowball" || str == "bsod") // was bsod in old maps
+ return BAD_SNOWBALL;
+ else if (str == "wingling")
+ return BAD_WINGLING;
+ else if (str == "walkingtree")
+ return BAD_WALKINGTREE;
+ else
+ {
+ return BAD_INVALID;
+ }
+}
+
+std::string badguykind_to_string(BadGuyKind kind)
+{
+ switch(kind)
+ {
+ case BAD_JUMPY:
+ return "jumpy";
+ break;
+ case BAD_MRICEBLOCK:
+ return "mriceblock";
+ break;
+ case BAD_MRBOMB:
+ return "mrbomb";
+ break;
+ case BAD_STALACTITE:
+ return "stalactite";
+ break;
+ case BAD_FLAME:
+ return "flame";
+ break;
+ case BAD_FISH:
+ return "fish";
+ break;
+ case BAD_BOUNCINGSNOWBALL:
+ return "bouncingsnowball";
+ break;
+ case BAD_FLYINGSNOWBALL:
+ return "flyingsnowball";
+ break;
+ case BAD_SPIKY:
+ return "spiky";
+ break;
+ case BAD_SNOWBALL:
+ return "snowball";
+ break;
+ case BAD_WINGLING:
+ return "wingling";
+ break;
+ case BAD_WALKINGTREE:
+ return "walkingtree";
+ default:
+ return "snowball";
+ }
+}
+
+BadGuy::BadGuy(BadGuyKind kind_, LispReader& lispreader)
+ : removable(false), squishcount(0)
+{
+ lispreader.read_float("x", start_position.x);
+ lispreader.read_float("y", start_position.y);
+
+ kind = kind_;
+
+ stay_on_platform = false;
+ lispreader.read_bool("stay-on-platform", stay_on_platform);
+
+ init();
+}
+
+BadGuy::BadGuy(BadGuyKind kind_, float x, float y)
+ : removable(false), squishcount(0)
+{
+ start_position.x = x;
+ start_position.y = y;
+ stay_on_platform = false;
+
+ kind = kind_;
+
+ init();
+}
+
+BadGuy::~BadGuy()
+{
+}
+
+void
+BadGuy::init()
+{
+ base.x = 0;
+ base.y = 0;
+ base.width = 0;
+ base.height = 0;
+
+ mode = NORMAL;
+ dying = DYING_NOT;
+ old_base = base;
+ dir = LEFT;
+ seen = false;
+ animation_offset = 0;
+ target.x = target.y = -1;
+ sprite_left = sprite_right = 0;
+ physic.reset();
+ frozen_timer.init(true);
+ timer.init(true);
+
+ // if we're in a solid tile at start correct that now
+ if(kind != BAD_FLAME && kind != BAD_FISH && collision_object_map(base))
+ {
+ std::cout << "Warning: badguy started in wall: kind: " << badguykind_to_string(kind)
+ << " pos: (" << base.x << ", " << base.y << ")" << std::endl;
+ while(collision_object_map(base))
+ --base.y;
+ }
+
+ if(Sector::current() && Sector::current()->camera) {
+ Vector scroll = Sector::current()->camera->get_translation();
+
+ if(start_position.x > scroll.x - X_OFFSCREEN_DISTANCE &&
+ start_position.x < scroll.x + screen->w + X_OFFSCREEN_DISTANCE &&
+ start_position.y > scroll.y - Y_OFFSCREEN_DISTANCE &&
+ start_position.y < scroll.y + screen->h + Y_OFFSCREEN_DISTANCE) {
+ activate(LEFT);
+ }
+ } else {
+ if(start_position.x > 0 && start_position.x <= screen->w
+ && start_position.y > 0 && start_position.y <= screen->h)
+ activate(LEFT);
+ }
+}
+
+void
+BadGuy::write(LispWriter& writer)
+{
+ writer.start_list(badguykind_to_string(kind));
+
+ writer.write_float("x", base.x);
+ writer.write_float("y", base.y);
+ writer.write_bool("stay-on-platform", stay_on_platform);