@Override
        public void onSelect(Item item) {
          if (item != null && item instanceof Scroll && item.isIdentified()) {
            String scroll = convertName(item.getClass().getSimpleName());
            Hero hero = Dungeon.hero;
            for (int i = 0; (i <= 1 && i < scrolls.size()); i++) {
              if (scrolls.get(i).equals(scroll)) {
                hero.sprite.operate(hero.pos);
                hero.busy();
                hero.spend(2f);
                Sample.INSTANCE.play(Assets.SND_BURNING);
                hero.sprite.emitter().burst(ElmoParticle.FACTORY, 12);

                scrolls.remove(i);
                item.detach(hero.belongings.backpack);

                upgrade();
                GLog.i("You infuse the scroll's energy into the book.");
                return;
              }
            }
            if (item != null) GLog.w("You are unable to add this scroll to the book.");
          } else if (item instanceof Scroll && !item.isIdentified())
            GLog.w("You're not sure what type of scroll this is yet.");
        }
  @Override
  public void execute(Hero hero, String action) {
    if (action.equals(AC_READ)) {

      if (hero.buff(Blindness.class) != null)
        GLog.w("You cannot read from the book while blinded.");
      else if (!isEquipped(hero)) GLog.i("You need to equip your spellbook to do that.");
      else if (charge == 0) GLog.i("Your spellbook is out of energy for now.");
      else if (cursed) GLog.i("Your cannot read from a cursed spellbook.");
      else {
        charge--;

        Scroll scroll;
        do {
          scroll = (Scroll) Generator.random(Generator.Category.SCROLL);
        } while (scroll == null
            ||
            // gotta reduce the rate on these scrolls or that'll be all the item does.
            ((scroll instanceof ScrollOfIdentify
                    || scroll instanceof ScrollOfRemoveCurse
                    || scroll instanceof ScrollOfMagicMapping)
                && Random.Int(2) == 0));

        scroll.ownedByBook = true;
        scroll.execute(hero, AC_READ);
      }

    } else if (action.equals(AC_ADD)) {
      GameScene.selectItem(itemSelector, mode, inventoryTitle);
    } else super.execute(hero, action);
  }
  @Override
  public void apply(Hero hero) {
    setKnown();
    Buff.affect(hero, MindVision.class, MindVision.DURATION);
    Dungeon.observe();

    if (Dungeon.level.mobs.size() > 0) {
      GLog.i("You can somehow feel the presence of other creatures' minds!");
    } else {
      GLog.i("You can somehow tell that you are alone on this level at the moment.");
    }
  }
  @Override
  public boolean act() {
    if (target.isAlive()) {

      if ((level = Random.NormalIntRange(level / 2, level)) > 0) {

        target.damage(level, this);
        if (target.sprite.visible) {
          Splash.at(
              target.sprite.center(),
              -PointF.PI / 2,
              PointF.PI / 6,
              target.sprite.blood(),
              Math.min(10 * level / target.HT, 10));
        }

        if (target == Dungeon.hero && !target.isAlive()) {
          Dungeon.fail(getClass());
          GLog.n(Messages.get(this, "ondeath"));
        }

        spend(TICK);
      } else {
        detach();
      }

    } else {

      detach();
    }

    return true;
  }
  @Override
  public boolean doEquip(Hero hero) {

    detach(hero.belongings.backpack);

    if (hero.belongings.armor == null || hero.belongings.armor.doUnequip(hero, true, false)) {

      hero.belongings.armor = this;

      cursedKnown = true;
      if (cursed) {
        equipCursed(hero);
        GLog.n(TXT_EQUIP_CURSED, toString());
      }

      ((HeroSprite) hero.sprite).updateArmor();

      hero.spendAndNext(2 * time2equip(hero));
      return true;

    } else {

      collect(hero.belongings.backpack);
      return false;
    }
  }
    public boolean checkOwner(Char owner) {
      if (!owner.isAlive() && owner instanceof Hero) {

        Dungeon.fail(Utils.format(ResultDescriptions.GLYPH, name()));
        GLog.n("%s killed you...", name());

        Badges.validateDeathFromGlyph();
        return true;

      } else {
        return false;
      }
    }
  public static void teleportHero(Hero hero) {

    int count = 10;
    int pos;
    do {
      pos = Dungeon.level.randomRespawnCell();
      if (count-- <= 0) {
        break;
      }
    } while (pos == -1);

    if (pos == -1) {

      GLog.w(TXT_NO_TELEPORT);

    } else {

      appear(hero, pos);
      Dungeon.level.press(pos, hero);
      Dungeon.observe();

      GLog.i(TXT_TELEPORTED);
    }
  }
  public int proc(Char attacker, Char defender, int damage) {

    if (glyph != null) {
      damage = glyph.proc(this, attacker, defender, damage);
    }

    if (!levelKnown) {
      if (--hitsToKnow <= 0) {
        levelKnown = true;
        GLog.w(TXT_IDENTIFY, name(), toString());
        Badges.validateItemLevelAquired(this);
      }
    }

    return damage;
  }
  public Item upgrade(boolean inscribe) {

    if (glyph != null) {
      if (!inscribe && Random.Int(level()) > 0) {
        GLog.w(TXT_INCOMPATIBLE);
        inscribe(null);
      }
    } else {
      if (inscribe) {
        inscribe(Glyph.random());
      }
    }
    ;

    STR--;

    return super.upgrade();
  }
  @Override
  public void execute(final Hero hero, String action) {
    if (action.equals(AC_BLESS)) {

      DewVial vial = hero.belongings.getItem(DewVial.class);
      if (vial != null) {
        blessed = true;
        vial.empty();
        GLog.p(TXT_BLESS);
        hero.spend(1f);
        hero.busy();

        Sample.INSTANCE.play(Assets.SND_DRINK);
        CellEmitter.get(hero.pos).start(Speck.factory(Speck.LIGHT), 0.2f, 3);
        hero.sprite.operate(hero.pos);
      }
    } else {

      super.execute(hero, action);
    }
  }
  @Override
  public void activate() {

    for (Mob mob : Dungeon.level.mobs) {
      mob.beckon(pos);
    }

    if (Dungeon.visible[pos]) {
      GLog.w("The trap emits a piercing sound that echoes throughout the dungeon!");
      CellEmitter.center(pos).start(Speck.factory(Speck.SCREAM), 0.3f, 3);
    }

    Sample.INSTANCE.play(Assets.SND_ALERT);

    for (int i = 0; i < (Dungeon.depth - 5) / 5; i++) {
      Guardian guardian = new Guardian();
      guardian.state = guardian.WANDERING;
      guardian.pos = Dungeon.level.randomRespawnCell();
      GameScene.add(guardian);
      guardian.beckon(Dungeon.hero.pos);
    }
  }