mirror of
https://github.com/Shu-Ying/noname-shuying.git
synced 2026-10-19 22:00:03 +08:00
fixed # 新增羁绊系统
fixed # 新增遗物系统 fixed # 梦三模式下移除护甲上限限制
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { cardDefinitions, canAcquireCard } from "./card-definitions.js";
|
||||
import { cardUpgradeRule } from "./upgrades.js";
|
||||
|
||||
const suits = ["spade", "heart", "club", "diamond"];
|
||||
|
||||
@@ -14,6 +15,7 @@ export function createCardData(spec, { character, enemy = false, registry = card
|
||||
!Number.isInteger(spec.number) || spec.number < 1 || spec.number > 13 ||
|
||||
(spec.nature != null && typeof spec.nature !== "string") ||
|
||||
!Number.isInteger(spec.upgrade ?? 0) || (spec.upgrade ?? 0) < 0 ||
|
||||
(spec.upgrade ?? 0) > (cardUpgradeRule(spec.name)?.maxLevel || 0) ||
|
||||
!Array.isArray(spec.affixes ?? []) || !(spec.affixes ?? []).every(value => typeof value === "string")) {
|
||||
throw new Error(`梦三牌数据无效:${spec.name}`);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 新增武将专属牌时填写 owner 为该武将 ID;通用牌填写 owner: null。
|
||||
const definitions = [
|
||||
{ name: "sha", category: "damage", owner: null },
|
||||
{ name: "mengsan_zhongsha", category: "damage", owner: null },
|
||||
{ name: "shan", category: "utility", owner: null },
|
||||
{ name: "tao", category: "recovery", owner: null },
|
||||
{ name: "jiu", category: "recovery", owner: null },
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
// 保留原牌名,以兼容原有牌的响应、装备技能及转化牌引用。
|
||||
import standard from "../../../../card/standard.js";
|
||||
import extra from "../../../../card/extra.js";
|
||||
import { _status } from "../../../../noname.js";
|
||||
import { cardCost, canPayCard, isActiveCardUse, SHA_DAMAGE } from "../battle/combat-rules.js";
|
||||
import { _status, game } from "../../../../noname.js";
|
||||
import { cardCost, canPayCard, isActiveCardUse, SHA_DAMAGE,
|
||||
TRICK_DAMAGE } from "../battle/combat-rules.js";
|
||||
import { cardUpgradeLevel, cardUpgradeRule } from "./upgrades.js";
|
||||
|
||||
const packs = [standard, extra];
|
||||
const names = [...new Set(packs.flatMap(pack => pack.list.map(entry => entry[2])))];
|
||||
@@ -40,11 +42,71 @@ export function createMengsanCards() {
|
||||
card.sha.baseDamage = SHA_DAMAGE;
|
||||
card.sha.content = async function (event, trigger, player) {
|
||||
if (typeof event.baseDamage !== "number") event.baseDamage = SHA_DAMAGE;
|
||||
if (cardUpgradeLevel(event.card)) {
|
||||
event.baseDamage += cardUpgradeRule("sha").damage - SHA_DAMAGE;
|
||||
}
|
||||
return nativeSha.content.call(this, event, trigger, player);
|
||||
};
|
||||
card.sha.usable = Infinity;
|
||||
card.sha.cardPrompt = () => `梦三:主动使用消耗1费用;目标须使用【闪】,否则受到${SHA_DAMAGE}点伤害。`;
|
||||
card.sha.cardPrompt = used => {
|
||||
const damage = cardUpgradeLevel(used)
|
||||
? cardUpgradeRule("sha").damage : SHA_DAMAGE;
|
||||
return `梦三:主动使用消耗1费用;目标须使用【闪】,` +
|
||||
`否则受到${damage}点伤害。每回合使用次数不限。` +
|
||||
(cardUpgradeLevel(used) ? "已强化(上限1次)。" :
|
||||
"可强化1次:伤害变为9点。");
|
||||
};
|
||||
translate.sha_info = `梦三:主动使用消耗1费用。出牌阶段,对攻击范围内的一名角色使用;其须使用【闪】,否则受到${SHA_DAMAGE}点伤害。每回合使用次数不限。`;
|
||||
card.mengsan_zhongsha = {
|
||||
type: "basic",
|
||||
fullskin: true,
|
||||
image: "ext:术樱包/mengsan/assets/cards/mengsan_zhongsha.png",
|
||||
mengsanCost_shuying: cardCost({ name: "mengsan_zhongsha" }),
|
||||
enable(used, player, event) {
|
||||
return !isActiveCardUse(event || _status.event, player) ||
|
||||
canPayCard(player, used);
|
||||
},
|
||||
usable: Infinity,
|
||||
selectTarget: 1,
|
||||
range: nativeSha.range,
|
||||
filterTarget: nativeSha.filterTarget,
|
||||
async content(event, trigger, player) {
|
||||
const target = event.target;
|
||||
const effect = cardUpgradeLevel(event.card)
|
||||
? cardUpgradeRule("mengsan_zhongsha")
|
||||
: { damage: 8, vulnerable: 2 };
|
||||
const damage = target.damage(effect.damage, player);
|
||||
damage.mengsanAttack_shuying = true;
|
||||
await damage;
|
||||
if (!target.isAlive()) return;
|
||||
target.storage.mengsanVulnerable_shuying =
|
||||
(target.storage.mengsanVulnerable_shuying || 0) +
|
||||
effect.vulnerable;
|
||||
target.addSkill("mengsan_vulnerable_shuying");
|
||||
target.markSkill("mengsan_vulnerable_shuying");
|
||||
game.log(target, `获得${effect.vulnerable}层易伤`);
|
||||
},
|
||||
ai: { order: 4, result: { target: -1.5 },
|
||||
tag: { damage: 1 } },
|
||||
cardPrompt(used) {
|
||||
const effect = cardUpgradeLevel(used)
|
||||
? cardUpgradeRule("mengsan_zhongsha")
|
||||
: { damage: 8, vulnerable: 2 };
|
||||
return "梦三:主动使用消耗2费用。对攻击范围内的" +
|
||||
`一名其他角色造成${effect.damage}点伤害,然后给予其` +
|
||||
`${effect.vulnerable}层易伤。受到攻击伤害增加50%` +
|
||||
"(向上取整),每个自身回合结束减少1层。" +
|
||||
"每回合使用次数不限。" + (cardUpgradeLevel(used)
|
||||
? "已强化(上限1次)。" :
|
||||
"可强化1次:10点伤害、3层易伤。");
|
||||
},
|
||||
};
|
||||
translate.mengsan_zhongsha = "重杀";
|
||||
translate.mengsan_zhongsha_info =
|
||||
"梦三:主动使用消耗2费用。出牌阶段,对攻击范围内的" +
|
||||
"一名其他角色造成8点伤害,然后给予其2层易伤。" +
|
||||
"易伤使受到的攻击伤害增加50%(向上取整)," +
|
||||
"每个自身回合结束减少1层。每回合使用次数不限。";
|
||||
// 【桃】的回复量也由梦三牌本体提供;救援仍不消耗费用。
|
||||
card.tao.content = async function (event) { await event.target.recover(8); };
|
||||
translate.tao_info = "梦三:主动使用消耗1费用,回复8点生命;濒死救援不消耗费用,同样回复8点生命。";
|
||||
@@ -53,9 +115,9 @@ export function createMengsanCards() {
|
||||
card.taoyuan.cardPrompt = () => translate.taoyuan_info;
|
||||
for (const name of ["nanman", "wanjian", "juedou"]) {
|
||||
const nativeContent = sourceCard(name).content;
|
||||
card[name].baseDamage = SHA_DAMAGE;
|
||||
card[name].baseDamage = TRICK_DAMAGE;
|
||||
card[name].content = async function (event, trigger, player) {
|
||||
if (typeof event.baseDamage !== "number") event.baseDamage = SHA_DAMAGE;
|
||||
if (typeof event.baseDamage !== "number") event.baseDamage = TRICK_DAMAGE;
|
||||
return nativeContent.call(this, event, trigger, player);
|
||||
};
|
||||
const detail = {
|
||||
@@ -67,7 +129,7 @@ export function createMengsanCards() {
|
||||
card[name].cardPrompt = () => translate[`${name}_info`];
|
||||
}
|
||||
// 火攻通过当前牌事件的 baseDamage 传入 damage("fire")。
|
||||
card.huogong.baseDamage = SHA_DAMAGE;
|
||||
card.huogong.baseDamage = TRICK_DAMAGE;
|
||||
translate.huogong_info = "梦三:主动使用消耗1费用。令一名有手牌的角色展示一张手牌;若你弃置同花色牌,对其造成4点火焰伤害。";
|
||||
card.huogong.cardPrompt = () => translate.huogong_info;
|
||||
// 闪电属于延时锦囊,其命中伤害在 effect 中显式写死为3,需要独立覆写。
|
||||
@@ -77,5 +139,5 @@ export function createMengsanCards() {
|
||||
};
|
||||
translate.shandian_info = "梦三:主动使用消耗1费用。若判定为黑桃2~9,目标受到12点雷电伤害;否则移至下家的判定区。";
|
||||
card.shandian.cardPrompt = () => translate.shandian_info;
|
||||
return { card, translate, names };
|
||||
return { card, translate, names: [...names, "mengsan_zhongsha"] };
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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,6 +15,7 @@ export function installPersonalPiles(session, owner, battle, run, resources, env
|
||||
// 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 strict = env.strict !== false;
|
||||
let released = false, forcedOwner = false;
|
||||
const personal = () => {
|
||||
@@ -47,6 +49,10 @@ export function installPersonalPiles(session, owner, battle, run, resources, env
|
||||
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);
|
||||
@@ -57,7 +63,7 @@ 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) showCost(card);
|
||||
if (data) showHandBadges(card);
|
||||
// Existing foreign/generated cards retain their original destruction semantics.
|
||||
if (!data) return;
|
||||
card.destroyLog = false;
|
||||
@@ -90,11 +96,13 @@ export function installPersonalPiles(session, owner, battle, run, resources, env
|
||||
const handObserver = new MutationObserver(mutations => {
|
||||
if (released) return;
|
||||
for (const mutation of mutations) for (const card of mutation.addedNodes) {
|
||||
if (card.classList?.contains("card")) showCost(card);
|
||||
if (card.classList?.contains("card")) showHandBadges(card);
|
||||
}
|
||||
});
|
||||
for (const zone of handZones) {
|
||||
for (const card of zone.childNodes) if (card.classList?.contains("card")) showCost(card);
|
||||
for (const card of zone.childNodes) {
|
||||
if (card.classList?.contains("card")) showHandBadges(card);
|
||||
}
|
||||
handObserver.observe(zone, { childList: true });
|
||||
}
|
||||
session.ownResource(handObserver, () => {
|
||||
@@ -104,6 +112,7 @@ export function installPersonalPiles(session, owner, battle, run, resources, env
|
||||
delete card.dataset.mengsanCost;
|
||||
}
|
||||
costBadges.clear();
|
||||
upgradeBadges.dispose();
|
||||
});
|
||||
const publicDiscard = ui.discardPile;
|
||||
for (const [key, node] of [["cardPile", draw], ["discardPile", discard]]) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
const upgrades = Object.freeze({
|
||||
sha: Object.freeze({ maxLevel: 1, damage: 9 }),
|
||||
mengsan_zhongsha: Object.freeze({ maxLevel: 1, damage: 10,
|
||||
vulnerable: 3 }),
|
||||
});
|
||||
|
||||
export const cardUpgradeRule = name =>
|
||||
Object.hasOwn(upgrades, name) ? upgrades[name] : null;
|
||||
|
||||
export function cardUpgradeLevel(card) {
|
||||
const data = card?.storage?.mengsanCard_shuying || card;
|
||||
if (!data || data.name !== card?.name) return 0;
|
||||
const limit = cardUpgradeRule(card.name)?.maxLevel || 0;
|
||||
return Number.isInteger(data.upgrade) && data.upgrade > 0
|
||||
? Math.min(data.upgrade, limit) : 0;
|
||||
}
|
||||
|
||||
export function canUpgradeCard(card) {
|
||||
const rule = cardUpgradeRule(card?.name);
|
||||
const level = card?.upgrade ?? 0;
|
||||
return Boolean(rule && Number.isInteger(level) && level >= 0 &&
|
||||
level < rule.maxLevel && !card.affixes?.includes("eternal"));
|
||||
}
|
||||
|
||||
export const hasUpgradeableCard = deck =>
|
||||
Array.isArray(deck) && deck.some(canUpgradeCard);
|
||||
|
||||
export function upgradeRandomCard(deck, random) {
|
||||
const eligible = Array.isArray(deck) ? deck.filter(canUpgradeCard) : [];
|
||||
if (!eligible.length) return null;
|
||||
const value = random();
|
||||
if (!Number.isFinite(value) || value < 0 || value >= 1) {
|
||||
throw new RangeError("梦三强化随机数必须位于[0, 1)");
|
||||
}
|
||||
const card = eligible[Math.floor(value * eligible.length)];
|
||||
card.upgrade = (card.upgrade || 0) + 1;
|
||||
return card;
|
||||
}
|
||||
Reference in New Issue
Block a user