public static void reallyDie(Object cause) {

    int length = Level.LENGTH;
    int[] map = Dungeon.level.map;
    boolean[] visited = Dungeon.level.visited;
    boolean[] discoverable = Level.discoverable;

    for (int i = 0; i < length; i++) {

      int terr = map[i];

      if (discoverable[i]) {

        visited[i] = true;
        if ((Terrain.flags[terr] & Terrain.SECRET) != 0) {
          Level.set(i, Terrain.discover(terr));
          GameScene.updateMap(i);
        }
      }
    }

    Bones.leave();

    Dungeon.observe();

    Dungeon.hero.belongings.identify();

    int pos = Dungeon.hero.pos;

    ArrayList<Integer> passable = new ArrayList<Integer>();
    for (Integer ofs : Level.NEIGHBOURS8) {
      int cell = pos + ofs;
      if ((Level.passable[cell] || Level.avoid[cell]) && Dungeon.level.heaps.get(cell) == null) {
        passable.add(cell);
      }
    }
    Collections.shuffle(passable);

    ArrayList<Item> items = new ArrayList<Item>(Dungeon.hero.belongings.backpack.items);
    for (Integer cell : passable) {
      if (items.isEmpty()) {
        break;
      }

      Item item = Random.element(items);
      Dungeon.level.drop(item, cell).sprite.drop(pos);
      items.remove(item);
    }

    GameScene.gameOver();

    if (cause instanceof Hero.Doom) {
      ((Hero.Doom) cause).onDeath();
    }

    Dungeon.deleteGame(Dungeon.hero.heroClass, true);
  }
  @Override
  public int defenseProc(Char enemy, int damage) {

    GameScene.add(Blob.seed(pos, 20, ParalyticGas.class));

    return super.defenseProc(enemy, damage);
  }
  private void ready() {
    sprite.idle();
    curAction = null;
    ready = true;

    GameScene.ready();
  }
  @Override
  public void onOperateComplete() {

    if (curAction instanceof HeroAction.Unlock) {

      if (theKey != null) {
        theKey.detach(belongings.backpack);
        theKey = null;
      }

      int doorCell = ((HeroAction.Unlock) curAction).dst;
      int door = Dungeon.level.map[doorCell];

      Level.set(doorCell, door == Terrain.LOCKED_DOOR ? Terrain.DOOR : Terrain.UNLOCKED_EXIT);
      GameScene.updateMap(doorCell);

    } else if (curAction instanceof HeroAction.OpenChest) {

      if (theKey != null) {
        theKey.detach(belongings.backpack);
        theKey = null;
      }

      Heap heap = Dungeon.level.heaps.get(((HeroAction.OpenChest) curAction).dst);
      if (heap.type == Type.SKELETON) {
        Sample.INSTANCE.play(Assets.SND_BONES);
      }
      heap.open(this);
    }
    curAction = null;

    super.onOperateComplete();
  }
  @Override
  public void die(Object cause) {

    curAction = null;

    DewVial.autoDrink(this);
    if (isAlive()) {
      new Flare(8, 32).color(0xFFFF66, true).show(sprite, 2f);
      return;
    }

    Actor.fixTime();
    super.die(cause);

    Ankh ankh = (Ankh) belongings.getItem(Ankh.class);
    if (ankh == null) {

      reallyDie(cause);

    } else {

      Dungeon.deleteGame(Dungeon.hero.heroClass, false);
      GameScene.show(new WndResurrect(ankh, cause));
    }
  }
  private boolean actAscend(HeroAction.Ascend action) {
    int stairs = action.dst;
    if (pos == stairs && pos == Dungeon.level.entrance) {

      if (Dungeon.depth == 1) {

        if (belongings.getItem(Amulet.class) == null) {
          GameScene.show(new WndMessage(TXT_LEAVE));
          ready();
        } else {
          Dungeon.win(ResultDescriptions.WIN);
          Dungeon.deleteGame(Dungeon.hero.heroClass, true);
          Game.switchScene(SurfaceScene.class);
        }

      } else {

        curAction = null;

        Hunger hunger = buff(Hunger.class);
        if (hunger != null && !hunger.isStarving()) {
          hunger.satisfy(-Hunger.STARVING / 10);
        }

        InterlevelScene.mode = InterlevelScene.Mode.ASCEND;
        Game.switchScene(InterlevelScene.class);
      }

      return false;

    } else if (getCloser(stairs)) {

      return true;

    } else {
      ready();
      return false;
    }
  }
  private boolean actBuy(HeroAction.Buy action) {
    int dst = action.dst;
    if (pos == dst || Level.adjacent(pos, dst)) {

      ready();

      Heap heap = Dungeon.level.heaps.get(dst);
      if (heap != null && heap.type == Type.FOR_SALE && heap.size() == 1) {
        GameScene.show(new WndTradeItem(heap, true));
      }

      return false;

    } else if (getCloser(dst)) {

      return true;

    } else {
      ready();
      return false;
    }
  }
  public boolean search(boolean intentional) {

    boolean smthFound = false;

    int positive = 0;
    int negative = 0;
    for (Buff buff : buffs(RingOfDetection.Detection.class)) {
      int bonus = ((RingOfDetection.Detection) buff).level;
      if (bonus > positive) {
        positive = bonus;
      } else if (bonus < 0) {
        negative += bonus;
      }
    }
    int distance = 1 + positive + negative;

    float level = intentional ? (2 * awareness - awareness * awareness) : awareness;
    if (distance <= 0) {
      level /= 2 - distance;
      distance = 1;
    }

    int cx = pos % Level.WIDTH;
    int cy = pos / Level.WIDTH;
    int ax = cx - distance;
    if (ax < 0) {
      ax = 0;
    }
    int bx = cx + distance;
    if (bx >= Level.WIDTH) {
      bx = Level.WIDTH - 1;
    }
    int ay = cy - distance;
    if (ay < 0) {
      ay = 0;
    }
    int by = cy + distance;
    if (by >= Level.HEIGHT) {
      by = Level.HEIGHT - 1;
    }

    for (int y = ay; y <= by; y++) {
      for (int x = ax, p = ax + y * Level.WIDTH; x <= bx; x++, p++) {

        if (Dungeon.visible[p]) {

          if (intentional) {
            sprite.parent.addToBack(new CheckedCell(p));
          }

          if (Level.secret[p] && (intentional || Random.Float() < level)) {

            int oldValue = Dungeon.level.map[p];

            GameScene.discoverTile(p, oldValue);

            Level.set(p, Terrain.discover(oldValue));

            GameScene.updateMap(p);

            ScrollOfMagicMapping.discover(p);

            smthFound = true;
          }

          if (intentional) {
            Heap heap = Dungeon.level.heaps.get(p);
            if (heap != null && heap.type == Type.HIDDEN) {
              heap.open(this);
              smthFound = true;
            }
          }
        }
      }
    }

    if (intentional) {
      sprite.showStatus(CharSprite.DEFAULT, TXT_SEARCH);
      sprite.operate(pos);
      if (smthFound) {
        spendAndNext(Random.Float() < level ? TIME_TO_SEARCH : TIME_TO_SEARCH * 2);
      } else {
        spendAndNext(TIME_TO_SEARCH);
      }
    }

    if (smthFound) {
      GLog.w(TXT_NOTICED_SMTH);
      Sample.INSTANCE.play(Assets.SND_SECRET);
      interrupt();
    }

    return smthFound;
  }