AWBW Helper

Outils de jeu (unités en attente, prévisualisation de portée) pour AWBW

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         AWBW Helper
// @version      1.1.0
// @author       StormSheep
// @description  Outils de jeu (unités en attente, prévisualisation de portée) pour AWBW
// @license      MIT
// @match        https://awbw.amarriner.com/*
// @namespace https://greasyfork.org/users/1626573
// ==/UserScript==

(function () {
  'use strict';

  function getNextUnitButton() {
    return nextUnitBtn;
  }
  function isGameReady() {
    return typeof unitsInfo === "object" && typeof playersUnits === "object" && typeof getViewerPId === "function" && typeof unitClickHandler === "function";
  }
  function selectUnit(id) {
    unitClickHandler({ id });
  }
  function unitIconUrl(unit) {
    const unitSlug = unit.units_name.toLowerCase().replace(" ", "");
    return `terrain/ani/${unit.countries_code}${unitSlug}.gif`;
  }
  function unitHpIconUrl(unit) {
    if (unit.units_hit_points === 10) return null;
    return `terrain/ani/${unit.units_hit_points}.gif`;
  }
  const LOWEST_PRIORITY_UNIT_NAMES = /* @__PURE__ */ new Set(["black boat"]);
  const LOW_PRIORITY_UNIT_NAMES = /* @__PURE__ */ new Set(["missile", "pipe runner"]);
  function unitPriority(unit) {
    const name = unit.units_name.toLowerCase();
    if (LOWEST_PRIORITY_UNIT_NAMES.has(name)) return 2;
    if (LOW_PRIORITY_UNIT_NAMES.has(name)) return 1;
    return 0;
  }
  function isViewerTurn() {
    return currentTurn === getViewerPId();
  }
  function getPendingUnits() {
    const viewerId = getViewerPId();
    const viewerUnits = playersUnits[viewerId];
    if (!viewerUnits) return [];
    return Object.keys(viewerUnits).map((id) => unitsInfo[id]).filter((unit) => unit && unit.units_moved === 0 && unit.units_carried === "N").sort((a, b) => unitPriority(a) - unitPriority(b));
  }
  function getPendingMove() {
    var _a;
    if (!moving || !(currentClick == null ? void 0 : currentClick.info) || !((_a = currentClick.path) == null ? void 0 : _a.length)) return null;
    const destNode = currentClick.path[currentClick.path.length - 1];
    const { x, y } = coordsFromNode(destNode);
    return { unit: currentClick.info, destX: x, destY: y };
  }
  function heldPreviewKey() {
    if (!isGameFocused()) return null;
    if (keyboardKeysPressed.get("shift")) return "movement";
    if (keyboardKeysPressed.get("control")) return "range";
    if (keyboardKeysPressed.get("alt")) return "vision";
    return null;
  }
  function previewTilesAt(unit, x, y, type) {
    const previewUnit = { ...unit, units_x: x, units_y: y };
    const original = getUnitAt;
    getUnitAt = (px, py) => px === x && py === y ? previewUnit : original(px, py);
    try {
      addTilesForUnitAt(x, y, type);
    } finally {
      getUnitAt = original;
    }
  }
  function redrawPendingMovePath() {
    if (!(currentClick == null ? void 0 : currentClick.path)) return;
    const lastNode = currentClick.path[currentClick.path.length - 1];
    const { x, y } = coordsFromNode(lastNode);
    currentClick.path = drawPathTiles(movementInfo, x, y, currentClick.path);
  }
  const TICK_MS = 50;
  let lastPreviewKey = null;
  function tick() {
    const move = getPendingMove();
    const type = move ? heldPreviewKey() : null;
    if (!move) {
      lastPreviewKey = null;
      return;
    }
    if (!type) {
      if (lastPreviewKey !== null) {
        lastPreviewKey = null;
        previewTilesAt(move.unit, move.unit.units_x, move.unit.units_y, "movement");
        redrawPendingMovePath();
      }
      return;
    }
    const key = `${type}:${move.destX},${move.destY}`;
    if (key === lastPreviewKey) return;
    lastPreviewKey = key;
    previewTilesAt(move.unit, move.destX, move.destY, type);
    redrawPendingMovePath();
  }
  function initMovePreviewFeature() {
    setInterval(tick, TICK_MS);
  }
  const TILE_SIZE = 16;
  const HIGHLIGHT_KEY = "t";
  const HIGHLIGHT_CLASS = "awbw-pending-highlight";
  function buildPanel(nativeBtn) {
    const btn = document.createElement("div");
    btn.id = "awbw-pending-units-btn";
    btn.className = nativeBtn.className;
    btn.style.cursor = "pointer";
    btn.style.position = "relative";
    const bg = document.createElement("div");
    bg.className = "game-tools-bg";
    bg.style.position = "relative";
    const icon = document.createElement("img");
    icon.style.position = "relative";
    icon.style.left = "-3px";
    bg.appendChild(icon);
    const hpBadge = document.createElement("img");
    hpBadge.style.position = "absolute";
    hpBadge.style.right = "11px";
    hpBadge.style.bottom = "8px";
    bg.appendChild(hpBadge);
    const arrow = document.createElement("span");
    arrow.textContent = "▼";
    arrow.style.position = "absolute";
    arrow.style.right = "1px";
    arrow.style.top = "50%";
    arrow.style.transform = "translateY(-50%)";
    arrow.style.fontSize = "9px";
    arrow.style.lineHeight = "1";
    arrow.style.color = "#fff";
    arrow.style.textShadow = "0 0 2px #000, 0 0 2px #000";
    bg.appendChild(arrow);
    const label = document.createElement("span");
    label.className = "game-tools-btn-text small_text";
    btn.appendChild(bg);
    btn.appendChild(label);
    const list = document.createElement("div");
    list.style.position = "absolute";
    list.style.top = "100%";
    list.style.left = "0";
    list.style.display = "none";
    list.style.flexDirection = "column";
    list.style.background = "#fff";
    list.style.border = "1px solid #999";
    list.style.maxHeight = "300px";
    list.style.overflowY = "auto";
    list.style.zIndex = "1000";
    list.style.whiteSpace = "nowrap";
    const refreshButton = () => {
      const units = getPendingUnits();
      nativeBtn.style.display = "none";
      if (!isViewerTurn() || units.length === 0) {
        btn.style.display = "none";
        list.style.display = "none";
        return;
      }
      btn.style.display = "flex";
      icon.src = units[0] ? unitIconUrl(units[0]) : "";
      icon.style.visibility = units[0] ? "visible" : "hidden";
      const hpUrl = units[0] ? unitHpIconUrl(units[0]) : null;
      hpBadge.src = hpUrl ?? "";
      hpBadge.style.display = hpUrl ? "block" : "none";
      label.textContent = `Unités en attente (${units.length})`;
    };
    const refresh = () => {
      refreshButton();
      const units = getPendingUnits();
      list.innerHTML = "";
      for (const unit of units) {
        const row = document.createElement("div");
        row.style.display = "flex";
        row.style.alignItems = "center";
        row.style.gap = "6px";
        row.style.padding = "4px 8px";
        row.style.cursor = "pointer";
        row.style.fontFamily = "sans-serif";
        row.style.fontSize = "12px";
        row.addEventListener("mouseenter", () => row.style.background = "#eee");
        row.addEventListener("mouseleave", () => row.style.background = "");
        const rowIconWrap = document.createElement("div");
        rowIconWrap.style.position = "relative";
        rowIconWrap.style.width = "16px";
        rowIconWrap.style.height = "16px";
        rowIconWrap.style.flex = "none";
        const rowIcon = document.createElement("img");
        rowIcon.src = unitIconUrl(unit);
        rowIcon.width = 16;
        rowIcon.height = 16;
        rowIconWrap.appendChild(rowIcon);
        const rowHpUrl = unitHpIconUrl(unit);
        if (rowHpUrl) {
          const rowHp = document.createElement("img");
          rowHp.src = rowHpUrl;
          rowHp.style.position = "absolute";
          rowHp.style.right = "-2px";
          rowHp.style.bottom = "-2px";
          rowIconWrap.appendChild(rowHp);
        }
        const rowLabel = document.createElement("span");
        rowLabel.textContent = `(${unit.units_x}, ${unit.units_y})`;
        row.appendChild(rowIconWrap);
        row.appendChild(rowLabel);
        row.addEventListener("click", () => {
          selectUnit(unit.units_id);
          list.style.display = "none";
          refresh();
        });
        list.appendChild(row);
      }
    };
    btn.addEventListener("click", () => {
      const opening = list.style.display === "none";
      if (opening) refresh();
      list.style.display = opening ? "flex" : "none";
    });
    document.addEventListener("click", (event) => {
      if (!btn.contains(event.target) && !list.contains(event.target)) {
        list.style.display = "none";
      }
    });
    refresh();
    setInterval(refreshButton, 500);
    btn.appendChild(list);
    return btn;
  }
  function clearHighlights() {
    const existing = document.querySelectorAll(`.${HIGHLIGHT_CLASS}`);
    existing.forEach((el) => el.remove());
    return existing.length > 0;
  }
  function showHighlights() {
    const gamemap = document.getElementById("gamemap");
    if (!gamemap) return;
    for (const unit of getPendingUnits()) {
      const highlight = document.createElement("div");
      highlight.className = HIGHLIGHT_CLASS;
      highlight.style.position = "absolute";
      highlight.style.left = `${unit.units_x * TILE_SIZE}px`;
      highlight.style.top = `${unit.units_y * TILE_SIZE}px`;
      highlight.style.width = `${TILE_SIZE}px`;
      highlight.style.height = `${TILE_SIZE}px`;
      highlight.style.backgroundColor = "rgba(255, 255, 0, 0.45)";
      highlight.style.boxShadow = "0 0 0 1px rgba(255, 200, 0, 0.9) inset";
      highlight.style.pointerEvents = "none";
      highlight.style.zIndex = "999";
      gamemap.appendChild(highlight);
    }
  }
  function toggleHighlights() {
    if (!clearHighlights()) {
      showHighlights();
    }
  }
  function initPendingUnitsFeature() {
    const nativeBtn = getNextUnitButton();
    const panel = buildPanel(nativeBtn);
    nativeBtn.insertAdjacentElement("beforebegin", panel);
    nativeBtn.style.display = "none";
    document.addEventListener("keydown", (event) => {
      const target = event.target;
      if (target && /^(input|textarea|select)$/i.test(target.tagName)) return;
      if (event.key.toLowerCase() === HIGHLIGHT_KEY) {
        toggleHighlights();
      }
    });
  }
  function waitForGame() {
    if (isGameReady()) {
      initPendingUnitsFeature();
      initMovePreviewFeature();
      return;
    }
    setTimeout(waitForGame, 300);
  }
  waitForGame();

})();