This commit is contained in:
2026-09-30 16:59:10 +08:00
parent 12e9ac181f
commit b005a7ff15
14 changed files with 525 additions and 135 deletions
+1 -53
View File
@@ -1,8 +1,6 @@
// Mode-owned piles use real Card nodes so native searches/gain/insert operations agree.
// DIY must access ui piles inside the acting player's engine event, never cache global nodes.
import { cardCost } from "../battle/combat-rules.js";
import { AFFIX_INFO } from "./affixes.js";
import { createHandUpgradeBadges } from "../ui/hand-upgrade.js";
export function installPersonalPiles(session, owner, battle, run, resources, env) {
@@ -14,8 +12,7 @@ export function installPersonalPiles(session, owner, battle, run, resources, env
const draw = document.createElement("div"), discard = document.createElement("div");
// Detached nodes: engine get.position recognises these IDs; no duplicate document IDs.
draw.id = "cardPile"; discard.id = "discardPile";
const owned = new Set(), restores = [], costBadges = new Map();
const upgradeBadges = createHandUpgradeBadges(document);
const owned = new Set(), restores = [];
const strict = env.strict !== false;
let released = false, forcedOwner = false;
const personal = () => {
@@ -29,30 +26,6 @@ export function installPersonalPiles(session, owner, battle, run, resources, env
return false; // Never infer ownership from whose turn it is.
};
const refresh = () => { if (!released) env.refresh(); };
function showCost(card) {
if (!env.showCosts || !card?.name) return;
const cost = String(cardCost(card));
card.dataset.mengsanCost = cost;
let badge = costBadges.get(card);
if (!badge) {
badge = Array.from(card.children || []).find(child => child.classList?.contains("mengsan-hand-cost-shuying"));
if (!badge) {
badge = document.createElement("span");
badge.className = "mengsan-hand-cost-shuying";
badge.setAttribute("aria-hidden", "true");
card.appendChild(badge);
}
costBadges.set(card, badge);
}
// 十周年 UI scans thrown-card children via innerText when adding “刘备使用”.
// Keep this child text-free so its numeric cost cannot match that scan.
badge.textContent = "";
badge.dataset.mengsanCost = cost;
}
function showHandBadges(card) {
showCost(card);
if (env.showCosts) upgradeBadges.refresh(card);
}
function adopt(card, data) {
if (owned.has(card)) return;
owned.add(card); resources.card(card);
@@ -63,7 +36,6 @@ export function installPersonalPiles(session, owner, battle, run, resources, env
// Retired affixes from old saves must not acquire new battle behaviour.
card.storage.mengsanCard_shuying.affixes = (card.storage.mengsanCard_shuying.affixes || []).filter(key => key !== "annihilate");
}
if (data) showHandBadges(card);
// Existing foreign/generated cards retain their original destruction semantics.
if (!data) return;
card.destroyLog = false;
@@ -90,30 +62,6 @@ export function installPersonalPiles(session, owner, battle, run, resources, env
const card = game.createCard(data.name, data.suit, data.number, data.nature);
adopt(card, data); draw.appendChild(card);
}
// Native and 十周年 UI both move real card nodes into these hand containers.
// Decorate newly gained cards without patching either UI's card factory or layout.
const handZones = [owner.node?.handcards1, owner.node?.handcards2].filter(Boolean);
const handObserver = new MutationObserver(mutations => {
if (released) return;
for (const mutation of mutations) for (const card of mutation.addedNodes) {
if (card.classList?.contains("card")) showHandBadges(card);
}
});
for (const zone of handZones) {
for (const card of zone.childNodes) {
if (card.classList?.contains("card")) showHandBadges(card);
}
handObserver.observe(zone, { childList: true });
}
session.ownResource(handObserver, () => {
handObserver.disconnect();
for (const [card, badge] of costBadges) {
if (badge.parentNode === card) badge.remove();
delete card.dataset.mengsanCost;
}
costBadges.clear();
upgradeBadges.dispose();
});
const publicDiscard = ui.discardPile;
for (const [key, node] of [["cardPile", draw], ["discardPile", discard]]) {
const descriptor = Object.getOwnPropertyDescriptor(ui, key);