void
Camera::parse(const lisp::Lisp& reader)
{
  std::string modename;
  
  reader.get("mode", modename);
  if(modename == "normal") {
    mode = NORMAL;

    do_backscrolling = true;
    reader.get("backscrolling", do_backscrolling);
  } else if(modename == "autoscroll") {
    mode = AUTOSCROLL;

    const lisp::Lisp* pathLisp = reader.get_lisp("path");
    if(pathLisp == NULL)
      throw std::runtime_error("No path specified in autoscroll camera.");

    autoscroll_path.reset(new Path());
    autoscroll_path->read(*pathLisp);
    autoscroll_walker.reset(new PathWalker(autoscroll_path.get()));
  } else if(modename == "manual") {
    mode = MANUAL;
  } else {
    std::stringstream str;
    str << "invalid camera mode '" << modename << "'found in worldfile.";
    throw std::runtime_error(str.str());
  }
}
void
Tile::parse(const lisp::Lisp& reader)
{
  if(!reader.get("id", id)) {
    throw std::runtime_error("Missing tile-id.");
  }
  
  bool value = false;
  if(reader.get("solid", value) && value)
    attributes |= SOLID;
  if(reader.get("unisolid", value) && value)
    attributes |= UNISOLID | SOLID;
  if(reader.get("brick", value) && value)
    attributes |= BRICK;
  if(reader.get("ice", value) && value)
    attributes |= ICE;
  if(reader.get("water", value) && value)
    attributes |= WATER;
  if(reader.get("hurts", value) && value)
    attributes |= HURTS;
  if(reader.get("fullbox", value) && value)
    attributes |= FULLBOX;
  if(reader.get("coin", value) && value)
    attributes |= COIN;
  if(reader.get("goal", value) && value)
    attributes |= GOAL;

  if(reader.get("north", value) && value)
    data |= WORLDMAP_NORTH;
  if(reader.get("south", value) && value)
    data |= WORLDMAP_SOUTH;
  if(reader.get("west", value) && value)
    data |= WORLDMAP_WEST;
  if(reader.get("east", value) && value) 
    data |= WORLDMAP_EAST;
  if(reader.get("stop", value) && value)
    data |= WORLDMAP_STOP;                      

  reader.get("data", data);
  reader.get("anim-fps", anim_fps);

  if(reader.get("slope-type", data)) {
    attributes |= SOLID | SLOPE;
  }
  
  const lisp::Lisp* images = reader.get_lisp("images");
  if(images)
    parse_images(*images);
}
Platform::Platform(const lisp::Lisp& reader)
{
  std::string sprite_name;
  reader.get("sprite", sprite_name);
  if(sprite_name == "")
    throw std::runtime_error("No sprite specified in platform object"); 
  sprite.reset(sprite_manager->create(sprite_name));

  const lisp::Lisp* pathLisp = reader.get_lisp("path");
  if(pathLisp == NULL)
    throw std::runtime_error("No path specified for platform");
  path.reset(new Path());
  path->read(*pathLisp);
  walker.reset(new PathWalker(path.get()));

  bbox.p1 = path->get_base();
  bbox.set_size(sprite->get_width(), sprite->get_height());
  
  set_group(COLGROUP_STATIC);
  flags |= FLAG_SOLID;
}
void
Sector::parse_old_format(const lisp::Lisp& reader)
{
  name = "main";
  reader.get("gravity", gravity);

  std::string backgroundimage;
  if (reader.get("background", backgroundimage) && (backgroundimage != "")) {
    if (backgroundimage == "arctis.png") backgroundimage = "arctis.jpg";
    if (backgroundimage == "arctis2.jpg") backgroundimage = "arctis.jpg";
    if (backgroundimage == "ocean.png") backgroundimage = "ocean.jpg";
    backgroundimage = "images/background/" + backgroundimage;
    if (!PHYSFS_exists(backgroundimage.c_str())) {
      log_warning << "Background image \"" << backgroundimage << "\" not found. Ignoring." << std::endl;
      backgroundimage = "";
    }
  }

  float bgspeed = .5;
  reader.get("bkgd_speed", bgspeed);
  bgspeed /= 100;

  Color bkgd_top, bkgd_bottom;
  int r = 0, g = 0, b = 128;
  reader.get("bkgd_red_top", r);
  reader.get("bkgd_green_top",  g);
  reader.get("bkgd_blue_top",  b);
  bkgd_top.red = static_cast<float> (r) / 255.0f;
  bkgd_top.green = static_cast<float> (g) / 255.0f;
  bkgd_top.blue = static_cast<float> (b) / 255.0f;

  reader.get("bkgd_red_bottom",  r);
  reader.get("bkgd_green_bottom", g);
  reader.get("bkgd_blue_bottom", b);
  bkgd_bottom.red = static_cast<float> (r) / 255.0f;
  bkgd_bottom.green = static_cast<float> (g) / 255.0f;
  bkgd_bottom.blue = static_cast<float> (b) / 255.0f;

  if(backgroundimage != "") {
    Background* background = new Background();
    background->set_image(backgroundimage, bgspeed);
    add_object(background);
  } else {
    Gradient* gradient = new Gradient();
    gradient->set_gradient(bkgd_top, bkgd_bottom);
    add_object(gradient);
  }

  std::string particlesystem;
  reader.get("particle_system", particlesystem);
  if(particlesystem == "clouds")
    add_object(new CloudParticleSystem());
  else if(particlesystem == "snow")
    add_object(new SnowParticleSystem());
  else if(particlesystem == "rain")
    add_object(new RainParticleSystem());

  Vector startpos(100, 170);
  reader.get("start_pos_x", startpos.x);
  reader.get("start_pos_y", startpos.y);

  SpawnPoint* spawn = new SpawnPoint;
  spawn->pos = startpos;
  spawn->name = "main";
  spawnpoints.push_back(spawn);

  music = "chipdisko.ogg";
  // skip reading music filename. It's all .ogg now, anyway
  /*
  reader.get("music", music);
  */
  music = "music/" + music;

  int width = 30, height = 15;
  reader.get("width", width);
  reader.get("height", height);

  std::vector<unsigned int> tiles;
  if(reader.get_vector("interactive-tm", tiles)
      || reader.get_vector("tilemap", tiles)) {
    TileMap* tilemap = new TileMap();
    tilemap->set(width, height, tiles, LAYER_TILES, true);

    // replace tile id 112 (old invisible tile) with 1311 (new invisible tile)
    for(size_t x=0; x < tilemap->get_width(); ++x) {
      for(size_t y=0; y < tilemap->get_height(); ++y) {
        const Tile* tile = tilemap->get_tile(x, y);
        if(tile->getID() == 112) tilemap->change(x, y, 1311);
      }
    }

    if (height < 19) tilemap->resize(width, 19);
    add_object(tilemap);
  }

  if(reader.get_vector("background-tm", tiles)) {
    TileMap* tilemap = new TileMap();
    tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false);
    if (height < 19) tilemap->resize(width, 19);
    add_object(tilemap);
  }

  if(reader.get_vector("foreground-tm", tiles)) {
    TileMap* tilemap = new TileMap();
    tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false);
    
    // fill additional space in foreground with tiles of ID 2035 (lightmap/black)
    if (height < 19) tilemap->resize(width, 19, 2035); 

    add_object(tilemap);
  }

  // read reset-points (now spawn-points)
  const lisp::Lisp* resetpoints = reader.get_lisp("reset-points");
  if(resetpoints) {
    lisp::ListIterator iter(resetpoints);
    while(iter.next()) {
      if(iter.item() == "point") {
        Vector sp_pos;
        if(reader.get("x", sp_pos.x) && reader.get("y", sp_pos.y))
          {
          SpawnPoint* sp = new SpawnPoint;
          sp->name = "main";
          sp->pos = sp_pos;
          spawnpoints.push_back(sp);
          }
      } else {
        log_warning << "Unknown token '" << iter.item() << "' in reset-points." << std::endl;
      }
    }
  }

  // read objects
  const lisp::Lisp* objects = reader.get_lisp("objects");
  if(objects) {
    lisp::ListIterator iter(objects);
    while(iter.next()) {
      GameObject* object = parse_object(iter.item(), *(iter.lisp()));
      if(object) {
        add_object(object);
      } else {
        log_warning << "Unknown object '" << iter.item() << "' in level." << std::endl;
      }
    }
  }

  // add a camera
  Camera* camera = new Camera(this, "Camera");
  add_object(camera);

  update_game_objects();

  if(solid_tilemaps.size() < 1) log_warning << "sector '" << name << "' does not contain a solid tile layer." << std::endl;

  fix_old_tiles();
  update_game_objects();
}