/*
  Code for additional keys started from "KeyE" and below were
  developed with assistance from ChatGPT by OpenAI:
  - What license for code that you're generating?
  - Code that I generate does not come with a separate OpenAI
    license attached by default. In general, you can use the
    generated code in your own projects, including commercial
    projects, subject to the terms that apply to your use of
    ChatGPT and any other relevant constraints.
  For those who still may need license the code below licensed
  under Apache-2.0 license.
*/
events$1.off("keydown", this._onKey, this);
events$1.off("keyup", this._onKey, this);
this._onKey = function (e) {
  const i = e.type === "keydown", s =
    this._sprintEnabled &&
    this._sprintPreventsJump &&
    this._sprintPressed;
  switch (e.code) {
  case "KeyW":
  case "ArrowUp":
    this._moveKeysPressed[0] = i;
    break;
  case "KeyS":
  case "ArrowDown":
    this._moveKeysPressed[1] = i;
    break;
  case "KeyA":
  case "ArrowLeft":
    this._moveKeysPressed[2] = i;
    break;
  case "KeyD":
  case "ArrowRight":
    this._moveKeysPressed[3] = i;
    break;
  case "Space":
  // new key X for jump
  case "KeyX":
    s || this._requestJump(i);
    break;
  case "ShiftLeft":
  case "ShiftRight":
    this._sprintEnabled &&
      (this._sprintPressed = i);
    break;
  // move camera left
  case "KeyZ":
    this._characters._camera._sphericalTarget.theta -=
      5 * math.DEG2RAD;
    break;
  // move camera right
  case "KeyC":
    this._characters._camera._sphericalTarget.theta +=
      5 * math.DEG2RAD;
    break;
  // snap camera behind character
  case "KeyV":
    if (i && this._characters._camera.isFollowCamera) {
      const
        t = this._characters._camera._sphericalTarget.theta,
        r = this._characters._localObject.rotationHorizontal;
      this._characters._camera._sphericalTarget.theta +=
        ((((r - t + Math.PI) % math.TWO_PI) +
        math.TWO_PI) % math.TWO_PI) - Math.PI;
    }
    break;
  // start dialogs and close final congratulations screen
  case "KeyE":
    if (i) {
      // final congratulations screen
      const endScreen =
        this._characters._scene.mainController
          .uiScene.scene2D.endScreen;
      if (endScreen.shown) {
        endScreen.interaction._onClick(
          new Set([endScreen.domButton])
        );
        break;
      }
      // existing NPC dialog code
      const scene = this._characters._scene;
      if (scene?.npcs) {
        for (const wrapper of scene.npcs) {
          const npc = wrapper.mesh;
          if (
            npc &&
            npc._isClose &&
            npc._talkEnabled &&
            npc._textsObjectRef?.length
          ) {
            npc._clickInteracted = true;
            npc._talkingDone = false;
            this.cancelJump();
            break;
          }
        }
      }
    }
    break;
  // toggle quest list panel
  case "KeyQ":
    if (i) {
      events$1.emit("ui_quest_log_toggle");
    }
    break;
  // toggle UI side button icons
  case "KeyM":
    if (i) {
      const sideButtons =
        this._characters._scene.mainController
          .uiScene.scene2D.sideButtons;
      if (sideButtons.shown) {
        sideButtons.hide();
      } else {
        sideButtons.show();
      }
    }
    break;
  // toggle music only keeping sounds intact
  case "KeyB":
    if (i) {
      const audio =
        this._characters._scene.mainController.audioController;
      this._musicMuted = !this._musicMuted;
      audio.setAudioVolume(
        "bgmusic",
         this._musicMuted ? 0 : 0.1
      );
    }
    break;
  // disable mouse input
  // FIXME: enabled again after talk to NPC
  // FIXME: you still can click on NPC active area
  case "KeyG":
    if (!i) break;
    this._mouseDisabled = !this._mouseDisabled;
    // mouse camera movement
    this._characters._camera.touchAmount =
      this._mouseDisabled ? 0 : 1;
    // display mouse cursor
    global$1.interactionNode.style.cursor =
      this._mouseDisabled ? "none" : "default";
    if (this._mouseDisabled) {
      // normal mouse
      events$1.off("touch_start", this._onTouchStart, this);
      events$1.off("touch_drag", this._onTouchDrag, this);
      events$1.off("touch_end", this._onTouchEnd, this);
      // secondary touch/mouse path
      events$1.off("touch2_start", this._onTouchStart, this);
      events$1.off("touch2_drag", this._onTouchDrag, this);
      events$1.off("touch2_end", this._onTouchEnd, this);
      this._isLeftMousePressed = false;
      this._touchMovingFinger = -1;
      this._touchCameraFinger = -1;
      this._touchMovingDelta.setScalar(0);
      // disable right click jump
      global$1.interactionNode.removeEventListener(
        "mousedown", this._boundMouseRightDown
      );
      global$1.interactionNode.removeEventListener(
        "mouseup", this._boundMouseRightUp
      );
    } else {
      events$1.on("touch_start", this._onTouchStart, this);
      events$1.on("touch_drag", this._onTouchDrag, this);
      events$1.on("touch_end", this._onTouchEnd, this);
      events$1.on("touch2_start", this._onTouchStart, this);
      events$1.on("touch2_drag", this._onTouchDrag, this);
      events$1.on("touch2_end", this._onTouchEnd, this);
      global$1.interactionNode.addEventListener(
        "mousedown", this._boundMouseRightDown
      );
      global$1.interactionNode.addEventListener(
        "mouseup", this._boundMouseRightUp
      );
    }
    break;
  // toggle players information
  case "KeyN":
    if (!i) { break; }
    if (!this._playerIdOverlay) {
      const syllables = [
        "ba", "be", "bi", "bo", "bu", "da", "de", "di", "do", "du",
        "fa", "fe", "fi", "fo", "fu", "ga", "ge", "gi", "go", "gu",
        "ha", "he", "hi", "ho", "hu", "ka",
        "ke", "ki", "ko", "ku", "la", "le", "li", "lo", "lu", "ma",
        "me", "mi", "mo", "mu", "na", "ne", "ni", "no", "nu", "pa",
        "pe", "pi", "po", "pu", "ra", "re",
        "ri", "ro", "ru", "sa", "se", "si", "so", "su", "va", "ve",
        "vi", "vo"
      ];
      const char_map =
        Object.fromEntries([...math.uidAlphabet].map((c, i) =>
          [c, syllables[i]]));
      this._playerIdOverlay = new Map();
      this._playerIdOverlayTimer = setInterval(() => {
        this._playerOverlayTick =
          (this._playerOverlayTick || 0) + 1;
        const tick = this._playerOverlayTick;
        const players = this._characters._charactersObjects;
        players.forEach((player, id) => {
          let div = this._playerIdOverlay.get(id);
          if (!div) {
            div = document.createElement("div");
            div.textContent = id;
            Object.assign(div.style, {
              position: "fixed",
              color: "#ffffff",
              background: "rgba(0,0,0,0.6)",
              padding: "2px 6px",
              borderRadius: "4px",
              fontSize: "14px",
              fontFamily: "Arial, sans-serif",
              pointerEvents: "none",
              zIndex: "999999",
              transform: "translate(-50%, -100%)",
              whiteSpace: "nowrap"
            });
            document.body.appendChild(div);
            this._playerIdOverlay.set(id, div);
          }
          const p = new player.position.constructor();
          p.copy(player.boundingSphere.center);
          const distance =
            p.distanceTo(this._characters._localObject.position);
          const offset = new player.position.constructor();
          offset.set(0, 1.0, 0);
          offset.applyQuaternion(player.quaternion);
          p.add(offset);
          p.project(this._characters._camera);
          const nid = [...id.slice(0, 4)].map(c =>
            char_map[c]).join("") + id.slice(4);
          if (id === this._characters.LOCAL_ID) {
            const pcount = players.size - 1;
            div.textContent = `players: ${pcount}`;
          } else {
            div.textContent = `${nid} (${distance.toFixed(1)}m)`;
          }
          div._lastUpdate = tick;
          if (
            (id !== this._characters.LOCAL_ID) && ((p.z > 1) ||
              (Math.abs(p.x) > 1) || (Math.abs(p.y) > 1)
            )
          ) {
            let dx = p.x;
            let dy = -p.y;
            if (p.z > 1) {
              dx = -dx;
              dy = -dy;
            }
            const len = Math.sqrt(dx * dx + dy * dy) || 1;
            dx /= len;
            dy /= len;
            const
              margin = 22,
              halfW = window.innerWidth / 2 - margin,
              halfH = window.innerHeight / 2 - margin,
              scale = Math.min(
                halfW / Math.abs(dx || 0.0001),
                halfH / Math.abs(dy || 0.0001)
              ),
              sx = window.innerWidth / 2 + dx * scale,
              sy = window.innerHeight / 2 + dy * scale;
              div.textContent = "^";
              div.style.textShadow = "0 0 3px black";
              div.style.fontSize = "22px";
              div.style.background = "transparent";
            const angle =
              ((Math.atan2(dy, dx) * 180) / Math.PI) + 90;
            div.style.transform =
              `translate(-50%, -45%) rotate(${angle}deg)`;
            div.style.left = sx + "px";
            div.style.top = sy + "px";
            div.style.display = "block";
          } else {
            div.style.textShadow = "";
            div.style.fontSize = "14px";
            div.style.background = "rgba(0,0,0,0.6)";
            div.style.transform = "translate(-50%, -100%)";
            div.style.left =
              ((p.x + 1) * 0.5 * window.innerWidth) + "px";
            div.style.top =
              ((-p.y + 1) * 0.5 * window.innerHeight) + "px";
            div.style.display = "block";
          }
        });
        this._playerIdOverlay.forEach((div, id) => {
          if (tick !== div._lastUpdate) {
            div.remove();
            this._playerIdOverlay.delete(id);
          }
        });
      }, 1000 / 30);
    } else {
      clearInterval(this._playerIdOverlayTimer);
      this._playerIdOverlayTimer = null;
      this._playerIdOverlay.forEach(div => {
          div.remove();
      });
      this._playerIdOverlay.clear();
      delete this._playerIdOverlay;
    }
    break;
  }
};
events$1.on("keydown", this._onKey, this);
events$1.on("keyup", this._onKey, this);
