void
Player::check_bounds(Camera* camera)
{
  /* Keep tux in bounds: */
  if (get_pos().x < 0) {
    // Lock Tux to the size of the level, so that he doesn't fall of
    // on the left side
    set_pos(Vector(0, get_pos().y));
  }

  /* Keep in-bounds, vertically: */
  if (get_pos().y > Sector::current()->solids->get_height() * 32) {
    kill(true);
    return;
  }

  bool adjust = false;
  // can happen if back scrolling is disabled
  if(get_pos().x < camera->get_translation().x) {
    set_pos(Vector(camera->get_translation().x, get_pos().y));
    adjust = true;
  }
  if(get_pos().x >= camera->get_translation().x + SCREEN_WIDTH - bbox.get_width())
  {
    set_pos(Vector(
          camera->get_translation().x + SCREEN_WIDTH - bbox.get_width(),
          get_pos().y));
    adjust = true;
  }

  if(adjust) {
    // FIXME
#if 0
    // squished now?
    if(collision_object_map(bbox)) {
      kill(KILL);
      return;
    }
#endif
  }
}
void
Player::action(double frame_ratio)
{
  bool jumped_in_solid = false;

  if (input.fire == UP)
    holding_something = false;

  /* Move tux: */
  previous_base = base;

  /* --- HANDLE TUX! --- */
  if(dying == DYING_NOT)
    handle_input();

  physic.apply(frame_ratio, base.x, base.y);

  if(dying == DYING_NOT) 
    {
      base_type target = base;

      collision_swept_object_map(&old_base, &base);

      // Don't accelerate Tux if he is running against a wall
      if (target.x != base.x)
        {
          physic.set_velocity_x(0);
        }

      // special exception for cases where we're stuck under tiles after
      // being ducked. In this case we drift out
      if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
         && collision_object_map(base))
        {
          base.x += frame_ratio * WALK_SPEED * (dir ? 1 : -1);
          previous_base = old_base = base;
        }

      // Land:
      if (!on_ground())
        {
          physic.enable_gravity(true);
          if(under_solid())
            {
              // fall down
              physic.set_velocity_y(0);
              jumped_in_solid = true;
            }
        }
      else
        {
          /* Land: */
          if (physic.get_velocity_y() < 0)
            {
              base.y = (int)(((int)base.y / 32) * 32);
              physic.set_velocity_y(0);
            }

          physic.enable_gravity(false);
          /* Reset score multiplier (for multi-hits): */
          player_status.score_multiplier = 1;
        }

      if(jumped_in_solid)
        {
          if (isbrick(base.x, base.y) ||
              isfullbox(base.x, base.y))
            {
              World::current()->trygrabdistro(base.x, base.y - 32,BOUNCE);
              World::current()->trybumpbadguy(base.x, base.y - 64);

              World::current()->trybreakbrick(base.x, base.y, size == SMALL, RIGHT);

              bumpbrick(base.x, base.y);
              World::current()->tryemptybox(base.x, base.y, RIGHT);
            }

          if (isbrick(base.x+ 31, base.y) ||
              isfullbox(base.x+ 31, base.y))
            {
              World::current()->trygrabdistro(base.x+ 31, base.y - 32,BOUNCE);
              World::current()->trybumpbadguy(base.x+ 31, base.y - 64);

              if(size == BIG)
                World::current()->trybreakbrick(base.x+ 31, base.y, size == SMALL, LEFT);

              bumpbrick(base.x+ 31, base.y);
              World::current()->tryemptybox(base.x+ 31, base.y, LEFT);
            }
        }

      grabdistros();

      if (jumped_in_solid)
        {
          ++base.y;
          ++old_base.y;
          if(on_ground())
            {
              /* Make sure jumping is off. */
              jumping = false;
            }
        }
    }

  /* ---- DONE HANDLING TUX! --- */

  // check some timers
  skidding_timer.check();
  invincible_timer.check();
  safe_timer.check();
  kick_timer.check();
}
void
BadGuy::action_mriceblock(double frame_ratio)
{
  Player& tux = *World::current()->get_tux();

  if(mode != HELD)
    fall();
  
  /* Move left/right: */
  if (mode != HELD)
    {
      // move
      physic.apply(frame_ratio, base.x, base.y);
      if (dying != DYING_FALLING)
        collision_swept_object_map(&old_base,&base);
    }
  else if (mode == HELD)
    { /* FIXME: The pbad object shouldn't know about pplayer objects. */
      /* If we're holding the iceblock */
      dir = tux.dir;
      if(dir==RIGHT)
        {
          base.x = tux.base.x + 16;
          base.y = tux.base.y + tux.base.height/1.5 - base.height;
        }
      else /* facing left */
        {
          base.x = tux.base.x - 16;
          base.y = tux.base.y + tux.base.height/1.5 - base.height;
        }
      if(collision_object_map(base))
        {
          base.x = tux.base.x;
          base.y = tux.base.y + tux.base.height/1.5 - base.height;
        }

      if(tux.input.fire != DOWN) /* SHOOT! */
        {
          if(dir == LEFT)
            base.x -= 24;
          else
            base.x += 24;
          old_base = base;

          mode=KICK;
          tux.kick_timer.start(KICKING_TIME);
          set_sprite(img_mriceblock_flat_left, img_mriceblock_flat_right);
          physic.set_velocity_x((dir == LEFT) ? -3.5 : 3.5);
          play_sound(sounds[SND_KICK],SOUND_CENTER_SPEAKER);
        }
    }

  if (!dying)
    {
      int changed = dir;
      check_horizontal_bump();
      if(mode == KICK && changed != dir)
        {
          /* handle stereo sound (number 10 should be tweaked...)*/
          if (base.x < scroll_x + screen->w/2 - 10)
            play_sound(sounds[SND_RICOCHET], SOUND_LEFT_SPEAKER);
          else if (base.x > scroll_x + screen->w/2 + 10)
            play_sound(sounds[SND_RICOCHET], SOUND_RIGHT_SPEAKER);
          else
            play_sound(sounds[SND_RICOCHET], SOUND_CENTER_SPEAKER);
        }
    }

  /* Handle mode timer: */
  if (mode == FLAT)
    {
      if(!timer.check())
        {
          mode = NORMAL;
          set_sprite(img_mriceblock_left, img_mriceblock_right);
          physic.set_velocity( (dir == LEFT) ? -.8 : .8, 0);
        }
    }
}
BadGuy::BadGuy(float x, float y, BadGuyKind kind_, bool stay_on_platform_)
  : removable(false), squishcount(0)
{
  base.x   = x;
  base.y   = y;    
  base.width  = 0;
  base.height = 0;
  base.xm  = 0;
  base.ym  = 0;

  stay_on_platform = stay_on_platform_;
  mode     = NORMAL;
  dying    = DYING_NOT;
  kind     = kind_;
  old_base = base;
  dir      = LEFT;
  seen     = false;
  animation_offset = 0;
  sprite_left = sprite_right = 0;
  physic.reset();
  timer.init(true);

  if(kind == BAD_MRBOMB) {
    physic.set_velocity(-BADGUY_WALK_SPEED, 0);
    set_sprite(img_mrbomb_left, img_mrbomb_right);
  } else if (kind == BAD_MRICEBLOCK) {
    physic.set_velocity(-BADGUY_WALK_SPEED, 0);
    set_sprite(img_mriceblock_left, img_mriceblock_right);
  } else if(kind == BAD_JUMPY) {
    set_sprite(img_jumpy_left_up, img_jumpy_left_up);
  } else if(kind == BAD_BOMB) {
    set_sprite(img_mrbomb_ticking_left, img_mrbomb_ticking_right);
    // hack so that the bomb doesn't hurt until it expldes...
    dying = DYING_SQUISHED;
  } else if(kind == BAD_FLAME) {
    base.ym = 0; // we misuse base.ym as angle for the flame
    physic.enable_gravity(false);
    set_sprite(img_flame, img_flame);
  } else if(kind == BAD_BOUNCINGSNOWBALL) {
    physic.set_velocity(-1.3, 0);
    set_sprite(img_bouncingsnowball_left, img_bouncingsnowball_right);
  } else if(kind == BAD_STALACTITE) {
    physic.enable_gravity(false);
    set_sprite(img_stalactite, img_stalactite);
  } else if(kind == BAD_FISH) {
    set_sprite(img_fish, img_fish);
    physic.enable_gravity(true);
  } else if(kind == BAD_FLYINGSNOWBALL) {
    set_sprite(img_flyingsnowball, img_flyingsnowball);
    physic.enable_gravity(false);
  } else if(kind == BAD_SPIKY) {
    physic.set_velocity(-BADGUY_WALK_SPEED, 0);
    set_sprite(img_spiky_left, img_spiky_right);
  } else if(kind == BAD_SNOWBALL) {
    physic.set_velocity(-BADGUY_WALK_SPEED, 0);
    set_sprite(img_snowball_left, img_snowball_right);
  }

  // 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;
    }
}
void
GameSession::restart_level()
{
  game_pause   = false;
  exit_status  = ES_NONE;
  end_sequence = NO_ENDSEQUENCE;

  fps_timer.init(true);
  frame_timer.init(true);

  float old_x_pos = -1;

  if (world)
    { // Tux has lost a life, so we try to respawn him at the nearest reset point
      old_x_pos = world->get_tux()->base.x;
    }
  
  delete world;

  if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
    {
      world = new World(subset);
    }
  else if (st_gl_mode == ST_GL_DEMO_GAME)
    {
      world = new World(subset);
    }
  else
    {
      world = new World(subset, levelnb);
    }

  // Set Tux to the nearest reset point
  if (old_x_pos != -1)
    {
      ResetPoint best_reset_point = { -1, -1 };
      for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin();
          i != get_level()->reset_points.end(); ++i)
        {
          if (i->x - screen->w/2 < old_x_pos && best_reset_point.x < i->x)
            best_reset_point = *i;
        }
      
      if (best_reset_point.x != -1)
        {
          world->get_tux()->base.x = best_reset_point.x;
          world->get_tux()->base.y = best_reset_point.y;
          world->get_tux()->old_base = world->get_tux()->base;
          world->get_tux()->previous_base = world->get_tux()->base;

          if(collision_object_map(world->get_tux()->base)) {
              std::cout << "Warning: reset point inside a wall.\n";
          }                                                                  

          scroll_x = best_reset_point.x - screen->w/2;
        }
    }
    
  if (st_gl_mode != ST_GL_DEMO_GAME)
    {
      if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
        levelintro();
    }

  time_left.init(true);
  start_timers();
  world->play_music(LEVEL_MUSIC);
}
Exemple #6
0
void collision_swept_object_map(base_type* old, base_type* current)
{
  int steps; /* Used to speed up the collision tests, by stepping every 16pixels in the path. */
  int h;
  float lpath; /* Holds the longest path, which is either in X or Y direction. */
  float xd,yd; /* Hold the smallest steps in X and Y directions. */
  float temp, xt, yt; /* Temporary variable. */

  lpath = 0;
  xd = 0;
  yd = 0;

  if(old->x == current->x && old->y == current->y)
    {
      return;
    }
  else if(old->x == current->x && old->y != current->y)
    {
      lpath = current->y - old->y;
      if(lpath < 0)
        {
          yd = -1;
          lpath = -lpath;
        }
      else
        {
          yd = 1;
        }

      h = 1;
      xd = 0;
    }
  else if(old->x != current->x && old->y == current->y)
    {
      lpath = current->x - old->x;
      if(lpath < 0)
        {
          xd = -1;
          lpath = -lpath;
        }
      else
        {
          xd = 1;
        }
      h = 2;
      yd = 0;
    }
  else
    {
      lpath = current->x - old->x;
      if(lpath < 0)
        lpath = -lpath;
      if(current->y - old->y > lpath || old->y - current->y > lpath)
        lpath = current->y - old->y;
      if(lpath < 0)
        lpath = -lpath;
      h = 3;
      xd = (current->x - old->x) / lpath;
      yd = (current->y - old->y) / lpath;
    }

  steps = (int)(lpath / (float)16);

  float orig_x = old->x;
  float orig_y = old->y;
  old->x += xd;
  old->y += yd;

  for(float i = 0; i <= lpath; old->x += xd, old->y += yd, ++i)
    {
      if(steps > 0)
        {
          old->y += yd*16.;
          old->x += xd*16.;
          steps--;
        }

      if(collision_object_map(*old))
        {
          switch(h)
            {
            case 1:
              current->y = old->y - yd;
              while(collision_object_map(*current))
                current->y -= yd;
              break;
            case 2:
              current->x = old->x - xd;
              while(collision_object_map(*current))
                current->x -= xd;
              break;
            case 3:
              xt = current->x;
              yt = current->y;
              current->x = old->x - xd;
              current->y = old->y - yd;
              while(collision_object_map(*current))
                {
                  current->x -= xd;
                  current->y -= yd;
                }

              temp = current->x;
              current->x = xt;
              if(!collision_object_map(*current))
                break;
              current->x = temp;
              temp = current->y;
              current->y = yt;

              if(!collision_object_map(*current))
                {
                  break;
                }
              else
                {
                  current->y = temp;
                  while(!collision_object_map(*current))
                    current->y += yd;
		  current->y -= yd;
                  break;
                }

              break;
            default:
              break;
            }
          break;
        }
    }

  if((xd > 0 && current->x < orig_x) || (xd < 0 && current->x > orig_x))
    current->x = orig_x;
  if((yd > 0 && current->y < orig_y) || (yd < 0 && current->y > orig_y))
    current->y = orig_y;

  *old = *current;
}