Пример #1
0
/**
 * @brief Updates this entity.
 */
void Hookshot::update() {

  MapEntity::update();

  if (suspended) {
    return;
  }

  uint32_t now = System::now();
  if (now >= next_sound_date) {
    Sound::play("hookshot");
    next_sound_date = now + 150;
  }

  if (entity_reached == NULL) {
    if (!going_back) {

      if (has_to_go_back) {
        going_back = true;
        Movement *movement = new TargetMovement(&get_hero(), 192, true);
        clear_movement();
        set_movement(movement);
      }
      else if (get_distance(get_hero()) >= 120) {
        go_back();
      }
    }
    else if (get_distance(get_hero()) == 0 ||
        (get_movement() != NULL && get_movement()->is_finished())) {
      remove_from_map();
      get_hero().start_state_from_ground();
    }
  }
}
Пример #2
0
/**
 * \brief This function is called when the entity has just moved.
 *
 * If it is an NPC, its sprite's direction is updated.
 */
void Npc::notify_position_changed() {

  Entity::notify_position_changed();

  if (subtype == USUAL_NPC) {

    const SpritePtr& sprite = get_sprite();
    if (get_movement() != nullptr) {
      // The NPC is moving.
      if (sprite != nullptr) {
        if (sprite->get_current_animation() != "walking") {
          sprite->set_current_animation("walking");
        }
        int direction4 = get_movement()->get_displayed_direction4();
        sprite->set_current_direction(direction4);
      }
    }

    if (get_hero().get_facing_entity() == this &&
        get_commands_effects().get_action_key_effect() == CommandsEffects::ACTION_KEY_SPEAK &&
        !get_hero().is_facing_point_in(get_bounding_box())) {

      get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_NONE);
    }
  }
}
Пример #3
0
/**
 * \brief This function is called repeatedly.
 */
void Bomb::update() {

  Detector::update();

  if (is_suspended()) {
    return;
  }

  // check the explosion date
  uint32_t now = System::now();
  if (now >= explosion_date) {
    explode();
  }
  else if (now >= explosion_date - 1500
      && get_sprite().get_current_animation() != "stopped_explosion_soon") {
    get_sprite().set_current_animation("stopped_explosion_soon");
  }

  // destroy the movement once finished
  if (get_movement() != nullptr && get_movement()->is_finished()) {
    clear_movement();
  }

  // check collision with explosions, streams, etc.
  check_collision_with_detectors();
}
Пример #4
0
/**
 * \brief Returns whether the arrow has just hit the map border.
 * \return true if the arrow has just hit the map border
 */
bool Arrow::has_reached_map_border() const {

  if (get_sprite().get_current_animation() != "flying" || get_movement() == NULL) {
    return false;
  }

  return get_map().test_collision_with_border(get_movement()->get_last_collision_box_on_obstacle());
}
Пример #5
0
char movement( int* x, int* y )
{
	char direction = get_movement();

	if (direction == '\033')
	{
		getch(); // skip [
		direction = getch();
	}
	if (direction == '6' || direction == 'C')
	{
		*x = *x+1;
	}
	else if (direction == '4' || direction == 'D')
	{
		*x = *x-1;
	}
	else if (direction == '2' || direction == 'A')
	{
		*y = *y+1;
	}
	else if (direction == '8' || direction == 'B')
	{
		*y = *y-1;
	}

	return direction;	
}
Пример #6
0
/**
 * @brief This function is called when the player tries to push or pull this block.
 * @return true if the player is allowed to move this block
 */
bool Block::start_movement_by_hero() {

  Hero& hero = get_hero();
  bool pulling = hero.is_grabbing_or_pulling();
  int allowed_direction = get_direction();
  int hero_direction = hero.get_animation_direction();
  if (pulling) {
    // the movement direction is backwards
    hero_direction = (hero_direction + 2) % 4;
  }

  if (get_movement() != NULL                // the block is already moving
      || maximum_moves == 0                 // the block cannot move anymore
      || System::now() < when_can_move      // the block cannot move for a while
      || (pulling && !can_be_pulled)        // the hero tries to pull a block that cannot be pulled
      || (!pulling && !can_be_pushed)       // the hero tries to push a block that cannot be pushed
      || (allowed_direction != -1 && hero_direction != allowed_direction)) { // incorrect direction
    return false;
  }

  int dx = get_x() - hero.get_x();
  int dy = get_y() - hero.get_y();

  set_movement(new FollowMovement(&hero, dx, dy, false));
  sound_played = false;

  return true;
}
Пример #7
0
/**
 * \brief Suspends or resumes the animation.
 *
 * Nothing is done if the parameter specified does not change.
 *
 * \param suspended true to suspend the animation, false to resume it
 */
void Sprite::set_suspended(bool suspended) {

  if (suspended != this->suspended && !ignore_suspend) {
    this->suspended = suspended;

    // compte next_frame_date if the animation is being resumed
    if (!suspended) {
      uint32_t now = System::now();
      next_frame_date = now + get_frame_delay();
      blink_next_change_date = now;
    }
    else {
      blink_is_sprite_visible = true;
    }

    // Also suspend or resumed the transition effect and the movement if any.
    Transition* transition = get_transition();
    if (transition != NULL) {
      transition->set_suspended(suspended);
    }

    Movement* movement = get_movement();
    if (movement != NULL) {
      movement->set_suspended(suspended);
    }
  }
}
Пример #8
0
/**
 * \brief Destroys the item while it is being thrown.
 */
void CarriedItem::break_item() {

  if (is_throwing && throwing_direction != 3) {
    // destroy the item where it is actually drawn
    set_y(get_y() - item_height);
  }

  get_movement()->stop();

  if (!can_explode()) {
    if (!destruction_sound_id.empty()) {
      Sound::play(destruction_sound_id);
    }
    if (get_sprite().has_animation("destroy")) {
      get_sprite().set_current_animation("destroy");
    }
    else {
      remove_from_map();
    }
  }
  else {
    get_entities().add_entity(std::make_shared<Explosion>(
        "", get_layer(), get_xy(), true
    ));
    Sound::play("explosion");
    if (is_throwing) {
      remove_from_map(); // because if the item was still carried by the hero, then the hero class will destroy it
    }
  }
  is_throwing = false;
  is_breaking = true;
}
Пример #9
0
/**
 * @brief This function is called when the movement of the entity is finished.
 */
void CustomEnemy::notify_movement_finished() {

  Enemy::notify_movement_finished();

  if (!is_being_hurt()) {
    script->event_movement_finished(*get_movement());
  }
}
Пример #10
0
/**
 * \brief Notifies the block that it has just moved.
 */
void Block::notify_position_changed() {

  Entity::notify_position_changed();

  // Now we know that the block moves at least of 1 pixel:
  // we can play the sound.
  if (get_movement() != nullptr && !sound_played) {
    Sound::play("hero_pushes");
    sound_played = true;
  }
}
Пример #11
0
/**
 * \brief Returns whether the hero is currently considered as an obstacle by this entity.
 * \param hero the hero
 * \return true if the hero is an obstacle for this entity.
 */
bool Block::is_hero_obstacle(Hero& hero) {

  // The block is not an obstacle when the hero is already overlapping it,
  // which is easily possible with blocks created dynamically.
  if (hero.overlaps(*this)) {
    return false;
  }

  // When the block is moved by the hero, one pixel can overlap.
  return get_movement() == nullptr;
}
Пример #12
0
/**
 * @brief Notifies this entity that it has just failed to change its position
 * because of obstacles.
 */
void Hookshot::notify_obstacle_reached() {

  if (is_flying()) {
    if (!get_map().test_collision_with_border(
        get_movement()->get_last_collision_box_on_obstacle())) {
      // play a sound unless the obstacle is the map border
      Sound::play("sword_tapping");
    }
    go_back();
  }
}
Пример #13
0
/**
 * @brief Starts a movement handled by this script and removes it from the list of unassigned movements.
 *
 * This function is called when the movement is assigned to an object.
 *
 * @param movement_handle handle of the movement
 * @return the corresponding movement
 */
Movement& Script::start_movement(int movement_handle) {

  Movement &movement = get_movement(movement_handle);

  if (unassigned_movements.count(movement_handle) > 0) {
    // the movemnt is still stored by the script: detach it
    movement.set_suspended(false);
    unassigned_movements.erase(movement_handle);
  }

  return movement;
}
Пример #14
0
/**
 * @brief Resets the block at its initial position.
 */
void Block::reset() {

  if (get_movement() != NULL) {
    // the block was being pushed or pulled by the hero
    clear_movement();
    when_can_move = System::now() + moving_delay;
  }

  set_xy(initial_position);
  last_position.set_xy(initial_position);
  this->maximum_moves = initial_maximum_moves;
}
Пример #15
0
/**
 * \brief Updates this entity.
 */
void Hookshot::update() {

  MapEntity::update();

  if (is_suspended()) {
    return;
  }

  uint32_t now = System::now();
  if (now >= next_sound_date) {
    Sound::play("hookshot");
    next_sound_date = now + 150;
  }

  if (entity_reached == nullptr) {
    if (!going_back) {

      if (has_to_go_back) {
        going_back = true;
        std::shared_ptr<Movement> movement = std::make_shared<TargetMovement>(
            std::static_pointer_cast<Hero>(get_hero().shared_from_this()),
            0,
            0,
            192,
            true
        );
        clear_movement();
        set_movement(movement);
      }
      else if (get_distance(get_hero()) >= 120) {
        go_back();
      }
    }
    else if (get_distance(get_hero()) == 0 ||
        (get_movement() != nullptr && get_movement()->is_finished())) {
      remove_from_map();
      get_hero().start_state_from_ground();
    }
  }
}
Пример #16
0
/**
 * \brief Resets the block at its initial position.
 */
void Block::reset() {

  if (get_movement() != nullptr) {
    // the block was being pushed or pulled by the hero
    clear_movement();
    when_can_move = System::now() + moving_delay;
  }

  last_position = initial_position;
  this->maximum_moves = initial_maximum_moves;
  set_xy(initial_position);
  notify_position_changed();
}
Пример #17
0
/**
 * \brief Notifies the block that it has just moved.
 */
void Block::notify_position_changed() {

  // now we know that the block moves at least of 1 pixel:
  // we can play the sound
  if (get_movement() != NULL && !sound_played) {
    Sound::play("hero_pushes");
    sound_played = true;
  }

  check_collision_with_detectors(false);
  update_ground_below();

  if (are_movement_notifications_enabled()) {
    get_lua_context().entity_on_position_changed(*this, get_xy(), get_layer());
  }
}
Пример #18
0
bool
InvisibleBlock::collides(GameObject& other, const CollisionHit& ) const
{
  if(visible)
    return true;

  // if we're not visible, only register a collision if this will make us visible
  auto player = dynamic_cast<Player*> (&other);
  if ((player)
      && (player->get_movement().y <= 0)
      && (player->get_bbox().get_top() > get_bbox().get_bottom() - SHIFT_DELTA)) {
    return true;
  }

  return false;
}
Пример #19
0
/**
 * \brief This function is called when a conveyor belt detects a collision with this entity.
 * \param conveyor_belt a conveyor belt
 * \param dx direction of the x move in pixels (0, 1 or -1)
 * \param dy direction of the y move in pixels (0, 1 or -1)
 */
void Bomb::notify_collision_with_conveyor_belt(ConveyorBelt& conveyor_belt, int dx, int dy) {

  if (get_movement() == NULL) {

    // check that a significant part of the bomb is on the conveyor belt
    Rectangle center = get_center_point();
    center.add_xy(-1, -1);
    center.set_size(2, 2);

    if (conveyor_belt.overlaps(center)) {
      set_xy(conveyor_belt.get_xy());

      std::string path = "  ";
      path[0] = path[1] = '0' + conveyor_belt.get_direction();
      clear_movement();
      set_movement(new PathMovement(path, 64, false, false, false));
    }
  }
}
Пример #20
0
/**
 * \brief Destroys the item after it finishes its thrown movement.
 *
 * How the item breaks depends on the ground where it lands.
 */
void CarriedItem::break_item_on_ground() {

  get_movement()->stop();

  Ground ground = get_ground_below();
  switch (ground) {

    case Ground::EMPTY:
      // Nothing here: fall one layer below.
    {
      int layer = get_layer();
      if (layer == 0) {
        // Cannot fall lower.
        break_item();
      }
      else {
        get_entities().set_entity_layer(*this, layer - 1);
        break_item_on_ground();  // Do this again on the next layer.
      }
      break;
    }

    case Ground::HOLE:
      Sound::play("jump");
      remove_from_map();
      break;

    case Ground::DEEP_WATER:
    case Ground::LAVA:
      Sound::play("walk_on_water");
      remove_from_map();
      break;

    default:
      // Break the item normally.
      break_item();
      break;
  }

  is_throwing = false;
  is_breaking = true;
}
Пример #21
0
HitResponse
Kugelblitz::collision_player(Player& player, const CollisionHit& )
{
  if(player.is_invincible()) {
    explode();
    return ABORT_MOVE;
  }
  // hit from above?
  if(player.get_movement().y - get_movement().y > 0 && player.get_bbox().p2.y <
     (get_bbox().p1.y + get_bbox().p2.y) / 2) {
    // if it's not is it possible to squish us, then this will hurt
    if(!collision_squished(player))
      player.kill(false);
    explode();
    return FORCE_MOVE;
  }
  player.kill(false);
  explode();
  return FORCE_MOVE;
}
Пример #22
0
/**
 * \copydoc MapEntity::notify_collision_with_stream
 */
void Bomb::notify_collision_with_stream(Stream& stream, int /* dx */, int /* dy */) {

  if (get_movement() == nullptr) {
    // TODO use a StreamAction, since it now works with any entity and not only the hero.

    // Check that a significant part of the bomb is on the stream.
    Rectangle center(get_center_point(), Size(2, 2));
    center.add_xy(-1, -1);

    if (stream.overlaps(center)) {
      set_xy(stream.get_xy());

      std::string path = "  ";
      path[0] = path[1] = '0' + stream.get_direction();
      clear_movement();
      set_movement(std::make_shared<PathMovement>(
          path, 64, false, false, false
      ));
    }
  }
}
/* -------------------------------------------------------------------- */
int fpc1020_input_task(fpc1020_data_t* fpc1020)
{
    u8 zones;
#ifdef DEBUG_TIME
    ktime_t capture_start_time;
#endif
    bool isReverse = false;
    int dx = 0;
    int dy = 0;
    int dy_bak = 0;
    int sumX = 0;
    int sumY = 0;
    int error = 0;
    unsigned char *prevBuffer = NULL;
    unsigned char *curBuffer = NULL;
    unsigned long diffTime = 0;

    fpc1020_dynamic_debug("%s %d\n", __func__, __LINE__);
    //set_cpus_allowed_ptr(current, cpumask_of(3));
    error = fpc1020_write_nav_setup(fpc1020);
    while (!fpc1020->worker.stop_request &&
           fpc1020->nav.enabled && (error >= 0))
    {
    	fpc1020_dynamic_debug("\n%s %d\n", __func__, __LINE__);
        error = fpc1020_capture_nav_wait_finger_down(fpc1020);
        if (error < 0)
        { break; }
        error = fpc1020_write_nav_setup(fpc1020);
        if (error < 0)
        { break; }
        error = fpc1020_check_finger_present_raw(fpc1020);
        process_navi_event(fpc1020, 0, 0, FNGR_ST_DETECTED);
	fpc1020->nav.click_start = jiffies; 
        zones = fpc1020_subzrea_zones_sum(error);
        fpc1020->nav.detect_zones = zones;
        fpc1020_dynamic_debug("[FPC] report touch zones=%d\n", fpc1020->nav.detect_zones);

#ifdef DEBUG_TIME
        capture_start_time = ktime_get();
#endif // DEBUG_TIME

#ifdef FPC1020_NAV_HEAP_BUF
        error = capture_nav_image(fpc1020);
#else
        error = fpc1020_capture_buffer(fpc1020, p_prev_img, 0, NAV_IMG_SIZE);
#endif /*FPC1020_NAV_HEAP_BUF*/

#ifdef DEBUG_TIME
        dev_dbg(&fpc1020->spi->dev,
                "Navigation, init capture time: %lld ns\n",
                (ktime_get().tv64 - capture_start_time.tv64));
#endif // DEBUG_TIME
        if (error < 0)
        { break; }
#ifdef FPC1020_NAV_HEAP_BUF
        memcpy(fpc1020->prev_img_buf,
               fpc1020->huge_buffer, NAV_IMG_SIZE);
#endif

        while (!fpc1020->worker.stop_request && (error >= 0))
        {
    	    fpc1020_dynamic_debug("\n%s %d\n", __func__, __LINE__);
	    hrtimer_start(&fpc1020->finger_up_timer, ktime_set(0, 50000000), HRTIMER_MODE_REL);

            error = fpc1020_check_finger_present_sum(fpc1020);
            if (error < fpc1020->setup.capture_finger_up_threshold + 1)
            {
#ifdef  FPC1020_NAV_DBG
                pr_info("[FPC] prepare report finger up\n");
#endif

                process_navi_event(fpc1020, 0, 0, FNGR_ST_LOST);
                fpc1020->nav.throw_event = 0;
                fpc1020->nav.report_keys = 0;
                sumX = 0;
                sumY = 0;
                fpc1020->nav.time = 0;
                isReverse = false;
                break;
            }

#ifdef FPC1020_NAV_HEAP_BUF
            if (isReverse)
            {
                prevBuffer = fpc1020->cur_img_buf;
                curBuffer = fpc1020->prev_img_buf;
            }
            else
            {
                prevBuffer = fpc1020->prev_img_buf;
                curBuffer = fpc1020->cur_img_buf;
            }
#else
            u8* p_tmp_curr_img = p_curr_img;
            p_curr_img = p_prev_img;
            p_prev_img = p_tmp_curr_img;
#endif
#ifdef DEBUG_TIME
            capture_start_time = ktime_get();
#endif // DEBUG_TIME
#ifdef FPC1020_NAV_HEAP_BUF
            error = capture_nav_image(fpc1020);
#else
            error = fpc1020_capture_buffer(fpc1020, p_curr_img, 0, NAV_IMG_SIZE);
#endif
            //fpc1020_debug_store_image(p_curr_img, NAV_IMG_W, NAV_IMG_H);
#ifdef DEBUG_TIME
            dev_dbg(&fpc1020->spi->dev,
                    "Navigation, capture time: %lld ns\n",
                    (ktime_get().tv64 - capture_start_time.tv64));
#endif
            if (error < 0)
            { break; }
#ifdef FPC1020_NAV_HEAP_BUF
            memcpy(curBuffer,
                   fpc1020->huge_buffer,
                   NAV_IMG_SIZE);
#endif
            //fpc1020_debug_store_image(fpc1020->cur_img_buf, NAV_IMG_W, NAV_IMG_H);
            error = fpc1020_check_finger_present_sum(fpc1020);
    	    fpc1020_dynamic_debug("%s %d\n", __func__, __LINE__);
            if (error < fpc1020->setup.capture_finger_up_threshold + 1)
            {
#ifdef	FPC1020_NAV_DBG
		pr_info("[FPC] prepare report finger up\n");
#endif
                process_navi_event(fpc1020, 0, 0, FNGR_ST_LOST);
                fpc1020->nav.throw_event = 0;
                fpc1020->nav.report_keys = 0;
                sumX = 0;
                sumY = 0;
                fpc1020->nav.time = 0;
                isReverse = false;
                break;
            }
#ifdef FPC1020_NAV_HEAP_BUF
            isReverse = !isReverse;
#endif
#ifdef DEBUG_TIME
            capture_start_time = ktime_get();
#endif // DEBUG_TIME
#ifdef FPC1020_NAV_HEAP_BUF
            //preempt_disable();
            get_movement(prevBuffer, curBuffer, &dx, &dy);
            //preempt_enable();
#else
            //preempt_disable();
            get_movement(p_prev_img, p_curr_img, &dx, &dy);
            //preempt_enable();
#endif
#ifdef DEBUG_TIME
            dev_dbg(&fpc1020->spi->dev,
                    "Navigation, caculate time: %lld ns\n",
                    (ktime_get().tv64 - capture_start_time.tv64));
#endif
	    if (dx!=0 && dy!=0) {
		fpc1020->nav.poll_filter++;
	    }
	    fpc1020->nav.poll_counter++;
            sumX += dx;
#if 1
	    if ((dy_bak > 0 && dy < 0) ||
			    (dy_bak < 0 && dy > 0))
		    sumY = 0;
#endif
            sumY += dy;
	    if(dx > 48 || dx < -48) dx = 0;
	    if(dy > 48 || dy < -48) dy = 0;
	    dy_bak = dy;
            fpc1020_dynamic_debug("[FPC] get_movement dx=%d, dy=%d, sumx=%d, sumy=%d\n", dx, dy, sumX, sumY);
            diffTime = abs(jiffies - fpc1020->nav.time);
            if (diffTime > 0)
            {
                diffTime = diffTime * 1000000 / HZ;

                if (diffTime >= FPC1020_INPUT_POLL_INTERVAL)
                {
#ifdef FPC1020_NAV_DBG
                    pr_info("[FPC] move poll \n");
#endif
		    if (fpc1020->nav.poll_counter > 1 && fpc1020->nav.poll_filter == 0)
                    	process_navi_event(fpc1020, sumX, sumY, FNGR_ST_MOVING);
		    else
			process_navi_event(fpc1020, 0, 0, FNGR_ST_MOVING);
	            fpc1020->nav.poll_counter = 0;
		    fpc1020->nav.poll_filter = 0;
                    sumX = 0;
                    sumY = 0;
		    
                    fpc1020->nav.time = jiffies;
                }
            }

        }
    }

    if (error < 0)
    {
        dev_err(&fpc1020->spi->dev,
                "%s %s (%d)\n\n",
                __func__,
                (error == -EINTR) ? "TERMINATED" : "FAILED", error);
    }
    fpc1020->nav.enabled = false;
    hrtimer_cancel(&fpc1020->finger_up_timer);
    fpc1020_dynamic_debug("\n%s %d\n", __func__, __LINE__);
    return error;
}
Пример #24
0
/**
 * \brief Returns whether the hero is currently considered as an obstacle by this entity.
 * \param hero the hero
 * \return true if the hero is an obstacle for this entity.
 */
bool Block::is_hero_obstacle(const Hero& hero) const {
  return get_movement() == NULL;
}
Пример #25
0
/**
 * \brief This function is called repeatedly.
 */
void CarriedItem::update() {

  // update the sprite and the position
  Entity::update();

  if (is_suspended()) {
    return;
  }

  // when the hero finishes lifting the item, start carrying it
  if (is_lifting && get_movement()->is_finished()) {
    is_lifting = false;

    // make the item follow the hero
    clear_movement();
    set_movement(std::make_shared<RelativeMovement>(
        std::static_pointer_cast<Hero>(hero.shared_from_this()),
        0,
        -18,
        true
    ));
  }

  // when the item has finished flying, destroy it
  else if (can_explode() && !is_breaking) {

    uint32_t now = System::now();

    if (now >= explosion_date) {
      break_item();
    }
    else if (will_explode_soon()) {

      std::string animation = get_sprite().get_current_animation();
      if (animation == "stopped") {
        get_sprite().set_current_animation("stopped_explosion_soon");
      }
      else if (animation == "walking") {
        get_sprite().set_current_animation("walking_explosion_soon");
      }
    }
  }

  if (is_broken()) {
    remove_from_map();
  }
  else if (is_throwing) {
    shadow_sprite->update();

    if (break_one_layer_above) {
      break_item();
      int layer = get_layer();
      if (layer != get_map().get_highest_layer()) {
        get_entities().set_entity_layer(*this, layer + 1);
      }
      break_one_layer_above = false;
    }
    else if (get_movement()->is_stopped() || y_increment >= 7) {
      // Interrupt the movement.
      break_item_on_ground();
    }
    else {
      uint32_t now = System::now();
      while (now >= next_down_date) {
        next_down_date += 40;
        item_height -= y_increment;
        y_increment++;
      }
    }
  }
}
Пример #26
0
/**
 * @brief This function is called repeatedly.
 */
void CarriedItem::update() {

  // update the sprite and the position
  MapEntity::update();

  if (suspended) {
    return;
  }

  // when the hero finishes lifting the item, start carrying it
  if (is_lifting && get_movement()->is_finished()) {
    is_lifting = false;

    // make the item follow the hero
    clear_movement();
    set_movement(new FollowMovement(&hero, 0, -18, true));
  }

  // when the item has finished flying, destroy it
  else if (can_explode() && !is_breaking) {
    
    uint32_t now = System::now();
    
    if (now >= explosion_date) {
      break_item();
    }
    else if (will_explode_soon()) {

      std::string animation = get_sprite().get_current_animation();
      if (animation == "stopped") {
        get_sprite().set_current_animation("stopped_explosion_soon");
      }
      else if (animation == "walking") {
        get_sprite().set_current_animation("walking_explosion_soon");
      }
    }
  }

  if (is_throwing) {
    shadow_sprite->update();

    if (is_broken()) {
      remove_from_map();
    }
    else if (break_on_intermediate_layer) {
      break_item();
      get_entities().set_entity_layer(*this, LAYER_INTERMEDIATE);
      break_on_intermediate_layer = false;
    }
    else if (get_movement()->is_stopped() || y_increment >= 7) {
      break_item();
    }
    else {
      uint32_t now = System::now();
      while (now >= next_down_date) {
        next_down_date += 40;
        item_height -= y_increment;
        y_increment++;
      }
    }
  }
}
Пример #27
0
/**
 * @brief Returns whether the hero is currently considered as an obstacle by this entity.
 * @param hero the hero
 * @return true if the hero is an obstacle for this entity.
 */
bool Block::is_hero_obstacle(Hero& hero) {
  return get_movement() == NULL;
}
Пример #28
0
/**
 * \brief Returns whether the arrow is stopped.
 * \return true if the arrow is stopped
 */
bool Arrow::is_stopped() const {
  return get_movement() == NULL || get_movement()->is_finished();
}
Пример #29
0
/**
 * \brief Reacts to the ground of the pickable.
 *
 * It is removed it is on water, lava or a hole.
 * It goes to the lower layer if the ground is empty.
 */
void Pickable::check_bad_ground() {

  if (is_being_removed()) {
    // Be silent if the pickable was already removed by a script.
    return;
  }

  if (get_entity_followed() != nullptr) {
    // We are attached to a hookshot or boomerang: don't fall.
    return;
  }

  if (get_y() < shadow_xy.y) {
    // The pickable is above the ground for now, let it fall first.
    return;
  }

  if (get_movement() != nullptr && !get_movement()->is_finished()) {
    // The falling movement is not finished yet.
    return;
  }

  if (System::now() <= appear_date + 200) {
    // The pickable appeared very recently, let the user see it for
    // a short time at least.
    return;
  }

  Ground ground = get_ground_below();
  switch (ground) {

    case Ground::EMPTY:
    {
      // Fall to a lower layer.
      int layer = get_layer();
      if (layer > 0) {
        --layer;
        get_entities().set_entity_layer(*this, layer);
      }
    }
    break;

    case Ground::HOLE:
    {
      Sound::play("jump");
      remove_from_map();
    }
    break;

    case Ground::DEEP_WATER:
    case Ground::LAVA:
    {
      Sound::play("splash");
      remove_from_map();
    }
    break;

    default:
      break;
  }
}