Esempio n. 1
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;
}
Esempio n. 2
0
void process_request(int fd) {
	if (server.clients[fd] == NULL) {
		return;
	}

	buffer* in_buf = server.clients[fd] -> in_buf;
	buffer* out_buf = server.clients[fd] -> out_buf;
	int i, len = buflen(in_buf);
	int req_len_end_pos = -1;
	for (i = 0; i < len; i++) {
		if (in_buf -> buf[i] == SEPARATOR) {
			req_len_end_pos = i;
			break;
		}
	}
	
	if (req_len_end_pos == -1) {
		return;
	}
	int req_len = -1;
	char tmp;
	sscanf(in_buf -> buf, "%d%c", &req_len, &tmp);
	if (len - req_len_end_pos - 1 < req_len) {
		return;
	}
	
	char op[100], *rest, tmp_buf[1024];
	memcpy(tmp_buf, in_buf -> buf + req_len_end_pos + 1, req_len * sizeof(char));
	tmp_buf[req_len] = '\0';
	sscanf(tmp_buf, "%s", op);
	rest = tmp_buf + strlen(op) + 1;
	
	if (strcmp(op, "GET") == 0) {
		void* res = get_from_map(server.db, rest);
		if (res) {
			append_to_buffer(out_buf, (char*) res);
		} else {
			append_to_buffer(out_buf, "");
		}
	} else if (strcmp(op, "SET") == 0) {
		char key[100], value[100];
		sscanf(rest, "%s %s", key, value);
		free(remove_from_map(server.db, key));
		char* kivi_obj = malloc((strlen(value) + 1) * sizeof(char));
		memcpy(kivi_obj, value, (strlen(value) + 1) * sizeof(char));
		put_in_map(server.db, key, kivi_obj);
		append_to_buffer(out_buf, "OK");
	} else if (strcmp(op, "DEL") == 0) {
		free(remove_from_map(server.db, rest));
		append_to_buffer(out_buf, "OK");
	}
	
	memcpy(in_buf -> buf, in_buf -> buf + req_len_end_pos + 1 + req_len, (len - req_len_end_pos - 1 - req_len) * sizeof(char));
	in_buf -> end_pos -= req_len_end_pos + 1 + req_len;
	in_buf -> buf[in_buf -> end_pos] = '\0';
}
Esempio n. 3
0
/**
 * @brief Updates the item.
 */
void Destructible::update() {

  MapEntity::update();

  if (suspended) {
    return;
  }

  if (is_being_cut && get_sprite().is_animation_finished()) {

    if (!features[subtype].can_regenerate) {
      // remove the item from the map
      destruction_callback();
      remove_from_map();
    }
    else {
      is_being_cut = false;
      regeneration_date = System::now() + 10000;
    }
  }

  else if (is_disabled() && System::now() >= regeneration_date && !overlaps(get_hero())) {
    get_sprite().set_current_animation("regenerating");
    is_regenerating = true;
    regeneration_date = 0;
  }
  else if (is_regenerating && get_sprite().is_animation_finished()) {
    get_sprite().set_current_animation("on_ground");
    is_regenerating = false;
  }
}
Esempio n. 4
0
/**
 * \brief Updates this entity.
 */
void Destructible::update() {

  MapEntity::update();

  if (is_suspended()) {
    return;
  }

  if (is_being_cut && get_sprite().is_animation_finished()) {

    if (!get_can_regenerate()) {
      // Remove this destructible from the map.
      remove_from_map();
    }
    else {
      is_being_cut = false;
      regeneration_date = System::now() + 10000;
    }
  }

  else if (is_waiting_for_regeneration()
      && System::now() >= regeneration_date
      && !overlaps(get_hero())) {
    get_sprite().set_current_animation("regenerating");
    is_regenerating = true;
    regeneration_date = 0;
    get_lua_context().destructible_on_regenerating(*this);
  }
  else if (is_regenerating && get_sprite().is_animation_finished()) {
    get_sprite().set_current_animation("on_ground");
    is_regenerating = false;
  }
}
Esempio n. 5
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();
    }
  }
}
Esempio n. 6
0
/**
 * \brief Gives the item to the player.
 */
void Pickable::try_give_item_to_player() {

  EquipmentItem& item = treasure.get_item();

  if (!can_be_picked
      || given_to_player
      || get_game().is_dialog_enabled()
      || !get_hero().can_pick_treasure(item)) {
    return;
  }

  given_to_player = true;

  remove_from_map();

  // play the sound
  const std::string& sound_id = item.get_sound_when_picked();
  if (!sound_id.empty()) {
    Sound::play(sound_id);
  }

  // give the item
  if (item.get_brandish_when_picked()) {
    // The treasure is brandished.
    // on_obtained() will be called after the dialog.
    get_hero().start_treasure(treasure, ScopedLuaRef());
  }
  else {
    treasure.give_to_player();

    // Call on_obtained() immediately since the treasure is not brandished.
    get_lua_context().item_on_obtained(item, treasure);
    get_lua_context().map_on_obtained_treasure(get_map(), treasure);
  }
}
Esempio n. 7
0
/**
 * \brief Updates this entity.
 */
void Explosion::update() {

  Detector::update();

  if (get_sprite().is_animation_finished()) {
    remove_from_map();
  }
}
Esempio n. 8
0
/**
 * \brief Makes the bomb explode.
 */
void Bomb::explode() {

  get_entities().add_entity(std::make_shared<Explosion>(
      "", get_layer(), get_center_point(), true
  ));
  Sound::play("explosion");
  remove_from_map();
}
Esempio n. 9
0
/**
 * \brief Updates the pickable item.
 *
 * This function is called repeatedly by the map.
 * This is a redefinition of Entity::update() to make
 * the item blink and then disappear after an amount of time.
 */
void Pickable::update() {

  // update the animations and the movement
  Detector::update();

  // update the shadow
  if (shadow_sprite != nullptr) {
    shadow_sprite->update();
  }

  shadow_xy.x = get_x();
  if (!is_falling()) {
    shadow_xy.y = get_y();
  }

  if (entity_followed != nullptr && entity_followed->is_being_removed()) {

    if (entity_followed->get_type() == EntityType::BOOMERANG ||
        entity_followed->get_type() == EntityType::HOOKSHOT) {
      // The pickable may have been dropped by the boomerang/hookshot
      // not exactly on the hero so let's fix this.
      if (get_distance(get_hero()) < 16) {
        try_give_item_to_player();
      }
    }
    entity_followed = nullptr;
  }

  check_bad_ground();

  if (!is_suspended()) {

    // check the timer
    uint32_t now = System::now();

    // wait 0.7 second before allowing the hero to take the item
    if (!can_be_picked && now >= allow_pick_date) {
      can_be_picked = true;
      falling_height = FALLING_NONE;
      get_hero().check_collision_with_detectors();
    }
    else {
      // make the item blink and then disappear
      if (will_disappear) {

        if (now >= blink_date && !get_sprite().is_blinking() && entity_followed == nullptr) {
          set_blinking(true);
        }

        if (now >= disappear_date) {
          remove_from_map();
        }
      }
    }
  }
}
Esempio n. 10
0
/**
 * \brief Updates this entity.
 */
void Fire::update() {

  Detector::update();
  if (get_sprite().is_animation_finished()) {
    remove_from_map();
  }
  else {
    check_collision_with_detectors(true);
  }
}
Esempio n. 11
0
/**
 * \brief Notifies this detector that the player is interacting with it by
 * pressing the action command.
 *
 * This function is called when the player presses the action command
 * while the hero is facing this detector, and the action command effect lets
 * him do this.
 */
void Destructible::notify_action_command_pressed() {

  KeysEffect::ActionKeyEffect effect = get_keys_effect().get_action_key_effect();

  if ((effect == KeysEffect::ACTION_KEY_LIFT || effect == KeysEffect::ACTION_KEY_LOOK)
      && features[subtype].can_be_lifted
      && !is_being_cut
      && !is_disabled()
      && !is_regenerating) {

    int weight = features[subtype].weight;

    if (get_equipment().has_ability("lift", weight)) {

      uint32_t explosion_date = can_explode() ? System::now() + 6000 : 0;
      get_hero().start_lifting(new CarriedItem(
          get_hero(),
          *this,
          get_animation_set_id(),
          get_destruction_sound_id(),
          get_damage_on_enemies(),
          explosion_date)
      );

      // play the sound
      Sound::play("lift");

      // create the pickable item
      create_pickable();

      // remove the item from the map
      if (!features[subtype].can_regenerate) {
        destruction_callback();
        remove_from_map();
      }
      else {
        // the item can actually regenerate
        play_destroy_animation();
      }
    }
    else {
      if (features[subtype].can_be_cut
          && !features[subtype].can_explode
          && !get_equipment().has_ability("sword", 1)) {
        get_game().start_dialog("_cannot_lift_should_cut", LUA_REFNIL);
      }
      else if (!get_equipment().has_ability("lift", 1)) {
        get_game().start_dialog("_cannot_lift_too_heavy", LUA_REFNIL);
      }
      else {
        get_game().start_dialog("_cannot_lift_still_too_heavy", LUA_REFNIL);
      }
    }
  }
}
Esempio n. 12
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;
}
Esempio n. 13
0
/**
 * \copydoc Entity::notify_ground_below_changed
 */
void Block::notify_ground_below_changed() {

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

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

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

    default:
      break;
  }
}
Esempio n. 14
0
/**
 * \copydoc Entity::notify_action_command_pressed
 */
bool Npc::notify_action_command_pressed() {

  Hero& hero = get_hero();
  if (hero.is_free() &&
      get_commands_effects().get_action_key_effect() != CommandsEffects::ACTION_KEY_NONE
  ) {

    CommandsEffects::ActionKeyEffect effect = get_commands_effects().get_action_key_effect();
    get_commands_effects().set_action_key_effect(CommandsEffects::ACTION_KEY_NONE);

    SpritePtr sprite = get_sprite();

    // if this is a usual NPC, look towards the hero
    if (subtype == USUAL_NPC) {
      int direction = (get_hero().get_animation_direction() + 2) % 4;
      if (sprite != nullptr) {
        sprite->set_current_direction(direction);
      }
    }

    if (effect != CommandsEffects::ACTION_KEY_LIFT) {
      // start the normal behavior
      if (behavior == BEHAVIOR_DIALOG) {
        get_game().start_dialog(dialog_to_show, ScopedLuaRef(), ScopedLuaRef());
      }
      else {
        call_script_hero_interaction();
      }
      return true;
    }
    else {
      // lift the entity
      if (get_equipment().has_ability(Ability::LIFT)) {

        std::string animation_set_id = "stopped";
        if (sprite != nullptr) {
          animation_set_id = sprite->get_animation_set_id();
        }
        hero.start_lifting(std::make_shared<CarriedObject>(
            hero,
            *this,
            animation_set_id,
            "stone",
            2,
            0)
        );
        Sound::play("lift");
        remove_from_map();
        return true;
      }
    }
  }
  return false;
}
Esempio n. 15
0
/**
 * \brief This function is called when the movement of the entity is finished.
 */
void Boomerang::notify_movement_finished() {

  if (!is_going_back()) {
    // the maximum distance is reached
    go_back();
  }
  else {
    // the boomerang is back
    remove_from_map();
  }
}
Esempio n. 16
0
/**
 * @brief Updates the entity.
 */
void ShopItem::update() {

  if (is_looking_item && !get_game().is_dialog_enabled()) {

    // the description message has just finished
    const std::string question_dialog_id = "_shop.question";
    get_dialog_box().start_dialog(question_dialog_id);
    get_dialog_box().set_variable(question_dialog_id, price);
    is_asking_question = true;
    is_looking_item = false;
  }
  else if (is_asking_question && !get_game().is_dialog_enabled()) {

    // the question has just finished
    is_asking_question = false;
    int answer = get_dialog_box().get_last_answer();

    if (answer == 0) {

      // the player wants to buy the item
      Equipment& equipment = get_equipment();
      EquipmentItem& item = treasure.get_item();

      if (equipment.get_money() < price) {
        // not enough rupees
        Sound::play("wrong");
        get_dialog_box().start_dialog("_shop.not_enough_money");
      }
      else if (item.has_amount() && item.get_amount() >= item.get_max_amount()) {
        // the player already has the maximum amount of this item
        Sound::play("wrong");
        get_dialog_box().start_dialog("_shop.amount_full");
      }
      else {

        bool can_buy = get_lua_context().shop_item_on_buying(*this);
        if (can_buy) {

          // give the treasure
          equipment.remove_money(price);

          get_hero().start_treasure(treasure, LUA_REFNIL);
          if (treasure.is_saved()) {
            remove_from_map();
            get_savegame().set_boolean(treasure.get_savegame_variable(), true);
          }
          get_lua_context().shop_item_on_bought(*this);
        }
      }
    }
  }
}
Esempio n. 17
0
/**
 * \copydoc Detector::notify_action_command_pressed
 */
bool Destructible::notify_action_command_pressed() {

  KeysEffect::ActionKeyEffect effect = get_keys_effect().get_action_key_effect();

  if ((effect == KeysEffect::ACTION_KEY_LIFT || effect == KeysEffect::ACTION_KEY_LOOK)
      && get_weight() != -1
      && !is_being_cut
      && !is_waiting_for_regeneration()
      && !is_regenerating) {

    if (get_equipment().has_ability(Ability::LIFT, get_weight())) {

      uint32_t explosion_date = get_can_explode() ? System::now() + 6000 : 0;
      get_hero().start_lifting(std::make_shared<CarriedItem>(
          get_hero(),
          *this,
          get_animation_set_id(),
          get_destruction_sound(),
          get_damage_on_enemies(),
          explosion_date)
      );

      // Play the sound.
      Sound::play("lift");

      // Create the pickable treasure.
      create_treasure();

      if (!get_can_regenerate()) {
        // Remove this destructible from the map.
        remove_from_map();
      }
      else {
        // The item can actually regenerate.
        play_destroy_animation();
      }

      // Notify Lua.
      get_lua_context().destructible_on_lifting(*this);
    }
    else {
      // Cannot lift the object.
      get_hero().start_grabbing();
      get_lua_context().destructible_on_looked(*this);
    }

    return true;
  }

  return false;
}
Esempio n. 18
0
/**
 * \brief Notifies this detector that the player is interacting with it by
 * pressing the action command.
 *
 * This function is called when the player presses the action command
 * while the hero is facing this detector, and the action command effect lets
 * him do this.
 * The hero lifts the bomb if possible.
 */
void Bomb::notify_action_command_pressed() {

  KeysEffect::ActionKeyEffect effect = get_keys_effect().get_action_key_effect();

  if (effect == KeysEffect::ACTION_KEY_LIFT
      && get_hero().get_facing_entity() == this
      && get_hero().is_facing_point_in(get_bounding_box())) {

    get_hero().start_lifting(new CarriedItem(get_hero(), *this,
	"entities/bomb", "", 0, explosion_date));
    Sound::play("lift");
    remove_from_map();
  }
}
Esempio n. 19
0
/**
 * \brief This function is called when a destructible item detects a non-pixel perfect collision with this entity.
 * \param destructible the destructible item
 * \param collision_mode the collision mode that detected the event
 */
void Arrow::notify_collision_with_destructible(
    Destructible& destructible, CollisionMode collision_mode) {

  if (destructible.is_obstacle_for(*this) && is_flying()) {

    if (destructible.get_can_explode()) {
      destructible.explode();
      remove_from_map();
    }
    else {
      attach_to(destructible);
    }
  }
}
Esempio n. 20
0
/**
 * \brief Notifies this entity that it has just attacked an enemy.
 *
 * This function is called even if this attack was not successful.
 *
 * \param attack the attack
 * \param victim the enemy just hurt
 * \param result indicates how the enemy has reacted to the attack
 * \param killed indicates that the attack has just killed the enemy
 */
void Arrow::notify_attacked_enemy(EnemyAttack attack, Enemy& victim,
    EnemyReaction::Reaction& result, bool killed) {

  if (result.type == EnemyReaction::PROTECTED) {
    stop();
    attach_to(victim);
  }
  else if (result.type != EnemyReaction::IGNORED) {
    if (killed) {
      remove_from_map();
    }
    else {
      attach_to(victim);
    }
  }
}
Esempio n. 21
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();
    }
  }
}
Esempio n. 22
0
/**
 * \copydoc Entity::notify_action_command_pressed
 */
bool Bomb::notify_action_command_pressed() {

  CommandsEffects::ActionKeyEffect effect = get_commands_effects().get_action_key_effect();

  if (effect == CommandsEffects::ACTION_KEY_LIFT
      && get_hero().get_facing_entity() == this
      && get_hero().is_facing_point_in(get_bounding_box())) {

    get_hero().start_lifting(std::make_shared<CarriedObject>(
        get_hero(),
        *this,
        "entities/bomb",
        "",
        0,
        explosion_date)
    );
    Sound::play("lift");
    remove_from_map();
    return true;
  }

  return false;
}
Esempio n. 23
0
void Pickable::notify_collision(MapEntity& entity_overlapping, CollisionMode collision_mode) {
	if(entity_overlapping.is_hero() && pickable) {
		remove_from_map();
		hero_pick_item();
	}
}
Esempio n. 24
0
/**
 * @brief Makes the bomb explode.
 */
void Bomb::explode() {

  get_entities().add_entity(new Explosion(get_layer(), get_center_point(), true));
  Sound::play("explosion");
  remove_from_map();
}
Esempio n. 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++;
      }
    }
  }
}
Esempio n. 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++;
      }
    }
  }
}
Esempio n. 27
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;
  }
}
Esempio n. 28
0
/**
 * \brief Updates the enemy.
 */
void Enemy::update() {

  MapEntity::update();

  if (is_suspended() || !is_enabled()) {
    return;
  }

  uint32_t now = System::now();

  if (being_hurt) {

    // see if we should stop the animation "hurt"
    if (now >= stop_hurt_date) {
      being_hurt = false;
      set_movement_events_enabled(true);

      if (life <= 0) {
        kill();
      }
      else if (is_immobilized()) {
        clear_movement();
        set_animation("immobilized");
        notify_immobilized();
      }
      else {
        clear_movement();
        restart();
      }
    }
  }

  if (life > 0 && invulnerable && now >= vulnerable_again_date && !being_hurt) {
    invulnerable = false;
  }

  if (life > 0 && !can_attack && !is_immobilized()
      && can_attack_again_date != 0 && now >= can_attack_again_date) {
    can_attack = true;
  }

  if (is_immobilized() && !is_killed() && now >= end_shaking_date &&
      get_sprite().get_current_animation() == "shaking") {

    restart();
  }

  if (is_immobilized() && !is_killed() && !is_being_hurt() && now >= start_shaking_date &&
      get_sprite().get_current_animation() != "shaking") {

    end_shaking_date = now + 2000;
    set_animation("shaking");
  }

  if (exploding) {
    uint32_t now = System::now();
    if (now >= next_explosion_date) {

      // create an explosion
      Rectangle xy;
      xy.set_x(get_top_left_x() + Random::get_number(get_width()));
      xy.set_y(get_top_left_y() + Random::get_number(get_height()));
      get_entities().add_entity(new Explosion("", LAYER_HIGH, xy, false));
      Sound::play("explosion");

      next_explosion_date = now + 200;
      nb_explosions++;

      if (nb_explosions >= 15) {
        exploding = false;
      }
    }
  }

  if (is_killed() && is_dying_animation_finished()) {

    // Create the pickable treasure if any.
    get_entities().add_entity(Pickable::create(get_game(),
        "", get_layer(), get_x(), get_y(),
        treasure, FALLING_HIGH, false));

    // Remove the enemy.
    remove_from_map();

    // Notify Lua that this enemy is dead.
    // We need to do this after remove_from_map() so that this enemy is
    // considered dead in functions like map:has_entities(prefix).
    notify_dead();
  }

  get_lua_context().enemy_on_update(*this);
}
Esempio n. 29
0
/**
 * \brief Updates this entity.
 */
void Arrow::update() {

  MapEntity::update();

  if (is_suspended()) {
    return;
  }

  uint32_t now = System::now();

  // stop the movement if necessary (i.e. stop() was called)
  if (stop_now) {
    clear_movement();
    stop_now = false;

    if (entity_reached != NULL) {
      // the arrow just hit an entity (typically an enemy) and this entity may have a movement
      Rectangle dxy(get_x() - entity_reached->get_x(), get_y() - entity_reached->get_y());
      set_movement(new FollowMovement(entity_reached, dxy.get_x(), dxy.get_y(), true));
    }
  }

  if (entity_reached != NULL) {

    // see if the entity reached is still valid
    if (is_stopped()) {
      // the arrow is stopped because the entity that was reached just disappeared
      disappear_date = now;
    }
    else if (entity_reached->get_type() == ENTITY_DESTRUCTIBLE && !entity_reached->is_obstacle_for(*this)) {
      disappear_date = now;
    }
    else if (entity_reached->get_type() == ENTITY_ENEMY && ((Enemy*) entity_reached)->is_dying()) {
      // the enemy is dying
      disappear_date = now;
    }
  }

  // see if the arrow just hit a wall or an entity
  bool reached_obstacle = false;

  if (get_sprite().get_current_animation() != "reached_obstacle") {

    if (entity_reached != NULL) {
      // the arrow was just attached to an entity
      reached_obstacle = true;
    }
    else if (is_stopped()) {

      if (has_reached_map_border()) {
        // the map border was reached: destroy the arrow
        disappear_date = now;
      }
      else {
        // the arrow has just hit another obstacle
        reached_obstacle = true;
      }
    }
  }

  if (reached_obstacle) {
    // an obstacle or an entity was just reached
    disappear_date = now + 1500;
    get_sprite().set_current_animation("reached_obstacle");
    Sound::play("arrow_hit");

    if (entity_reached == NULL) {
      clear_movement();
    }
    check_collision_with_detectors(false);
  }

  // destroy the arrow when disappear_date is reached
  if (now >= disappear_date) {
    remove_from_map();
  }
}