mirror of
https://github.com/Shu-Ying/noname-shuying.git
synced 2026-10-12 20:10:05 +08:00
105 lines
5.1 KiB
JavaScript
105 lines
5.1 KiB
JavaScript
// 累积仅属于真实牌对象和当前会话;不写Card.storage或永久牌组。
|
|
const NAME = "mengsan_baozou";
|
|
const growth = new WeakMap();
|
|
const validEntry = (card, entry) => card?.name === NAME && entry?.session.active &&
|
|
entry.battle.session === entry.session;
|
|
export function snapshotRampage(card) {
|
|
const entry = growth.get(card);
|
|
return validEntry(card, entry) ? {
|
|
mengsanRampageBonus_shuying: entry.bonus,
|
|
mengsanRampageSession_shuying: entry.session.id,
|
|
} : {};
|
|
}
|
|
export function copyRampageGrowth(source,target,battle) {
|
|
if(source?.cards?.length===1)source=source.cards[0];
|
|
const from=growth.get(source);
|
|
if(!validEntry(source,from) || from.battle!==battle || target?.name!==NAME)return;
|
|
const entry={battle,session:battle.session,bonus:from.bonus};
|
|
growth.set(target,entry);
|
|
battle.session.ownResource(entry,()=>{if(growth.get(target)===entry)growth.delete(target);});
|
|
}
|
|
function nearestUse(event) {
|
|
const seen = new Set();
|
|
for (let current = event; current && !seen.has(current); current = current.parent) {
|
|
seen.add(current);
|
|
if (current.name === "useCard") return current;
|
|
}
|
|
return null;
|
|
}
|
|
function original(event) {
|
|
const use = nearestUse(event);
|
|
if(use?.card?.name===NAME && use.mengsanIcRepeatOriginal_shuying?.name===NAME)return use.mengsanIcRepeatOriginal_shuying;
|
|
return use?.card?.name === NAME && use.cards?.length === 1 &&
|
|
use.cards[0]?.name === NAME ? use.cards[0] : null;
|
|
}
|
|
function cardOf(card) {
|
|
return card?.name === NAME && card.cards?.length === 1 && card.cards[0]?.name === NAME
|
|
? card.cards[0] : card;
|
|
}
|
|
function belongsTo(event, root) {
|
|
const seen = new Set();
|
|
for (let current = event; current && !seen.has(current); current = current.parent) {
|
|
if (current === root) return true;
|
|
seen.add(current);
|
|
}
|
|
return false;
|
|
}
|
|
export function createRampage(game, getActiveBattle) {
|
|
const used = new WeakSet();
|
|
const getPile = (player, battle) => player === game.me
|
|
? battle.personalPiles : battle.monsterPiles?.get(player);
|
|
function damage(card) {
|
|
const node = cardOf(card), battle = getActiveBattle(), entry = growth.get(node);
|
|
let bonus = validEntry(node, entry) && entry.battle === battle ? entry.bonus : 0;
|
|
// Only plain, current-session UI snapshots may expose serialized growth.
|
|
if (!node?.storage && battle?.session.active &&
|
|
node?.mengsanRampageSession_shuying === battle.session.id &&
|
|
Number.isSafeInteger(node.mengsanRampageBonus_shuying) && node.mengsanRampageBonus_shuying >= 0)
|
|
bonus = node.mengsanRampageBonus_shuying;
|
|
if (bonus > Number.MAX_SAFE_INTEGER - 9) throw new RangeError("暴走伤害越界");
|
|
return 9 + bonus;
|
|
}
|
|
return {
|
|
card: cardOf, original, damage,
|
|
async apply(player, event, baseDamage, increase) {
|
|
if (baseDamage !== 9 || !Number.isSafeInteger(increase) || increase <= 0)
|
|
throw new RangeError("暴走攻击参数无效");
|
|
const use = nearestUse(event), card = original(event);
|
|
const battle = getActiveBattle(), session = battle?.session, root = battle?.root;
|
|
if (!battle || !session?.active || !root || !card || use.player !== player ||
|
|
event.card?.name !== NAME || used.has(use) || !belongsTo(use, root)) return;
|
|
const pile = getPile(player, battle), target = event.target;
|
|
const valid = () => getActiveBattle() === battle && battle.session === session &&
|
|
session.active && battle.root === root && battle.players?.has(player) &&
|
|
player.isAlive() && card.name === NAME && getPile(player, battle) === pile &&
|
|
typeof pile?.battleCards === "function" && pile.battleCards(use.cards).includes(card);
|
|
if (!valid() || !battle.players.has(target) || !target?.isAlive?.() ||
|
|
target === player || !player.isEnemyOf(target)) return;
|
|
const amount = damage(card), bonus = amount - baseDamage;
|
|
if (increase > Number.MAX_SAFE_INTEGER - baseDamage - bonus)
|
|
throw new RangeError("暴走累积伤害越界");
|
|
used.add(use);
|
|
player.line(target, "green");
|
|
const hit = target.damage(amount, player);
|
|
hit.mengsanAttack_shuying = true;
|
|
await hit;
|
|
if (!valid()) return;
|
|
let entry = growth.get(card);
|
|
if (!validEntry(card, entry) || entry.battle !== battle) {
|
|
entry = { battle, session, bonus: 0 };
|
|
const record = entry;
|
|
session.ownResource(record, () => {
|
|
if (growth.get(card) === record) growth.delete(card);
|
|
});
|
|
growth.set(card, entry);
|
|
}
|
|
// Damage hooks may initiate nested uses; retain their increments without overwrite.
|
|
if (increase > Number.MAX_SAFE_INTEGER - baseDamage - entry.bonus)
|
|
throw new RangeError("暴走累积伤害越界");
|
|
entry.bonus += increase;
|
|
battle.handUI?.refresh();
|
|
battle.pilesUI?.refresh();
|
|
},
|
|
};
|
|
}
|