mirror of
https://github.com/Shu-Ying/noname-shuying.git
synced 2026-10-18 05:10:00 +08:00
74 lines
6.5 KiB
JavaScript
74 lines
6.5 KiB
JavaScript
import { relicCatalog } from "./catalog.js";
|
|
import { relicRules, missingMechanisms, unhandledRelicRule } from "./rules.js";
|
|
import { applyRelicPickup, relicCardRequirements } from "./progression.js";
|
|
|
|
export const relicAdaptations = Object.freeze({
|
|
the_courier:"梦三商店出售【杀】、回复生命及三件随机遗物;购买后补货,折扣适用现有商品。药水尚无接口。遗物基价120金币,为梦三配置值。",
|
|
miniature_tent:"每个休息选项可各选择一次,直至选择离开;不允许无限重复同一选项。",
|
|
meat_cleaver:"网页没有烹饪细则;暂定每次烹饪最大生命+5,待用户确认。",
|
|
big_mushroom:"沿用梦三初始手牌4张,扣减2张;未改成STS2的基础手牌数量。",
|
|
ring_of_the_drake:"刘备仅映射铁甲战士池;其他角色池需配置player.relicPool才可获取。效果按前三个自身回合各摸2张接入。",
|
|
runic_pyramid:"梦三原本按手牌上限弃牌;这里让全部手牌不计入弃牌上限。虚无牌照常消耗。",
|
|
precarious_shears:"选牌后扣除16点生命;当前地图流程保留至少1点生命,待补充非战斗死亡结算。",
|
|
fragrant_mushroom:"随机强化2张并扣除15点生命;当前地图流程保留至少1点生命,待补充非战斗死亡结算。",
|
|
dusty_tome:"从已登记的先古事件牌池随机获得一张;网页未列出完整候选排除规则。",
|
|
sword_of_stone:"按5次精英战胜利计数,变化为玉之剑;尚无精英单位的独立击杀标签。",
|
|
paper_phrog:"依梦三易伤口径向上取整;作用于玩家发起的攻击,保留既有卡牌的额外易伤增幅。",
|
|
paper_krane:"依梦三虚弱口径向下取整,敌人攻击倍率0.6。",
|
|
maw_bank:"将进入一个新的梦三节点视为攀爬一层,先发12金币,再进行商店购买或战斗;原作楼层与额外剧情节点未单独区分。",
|
|
});
|
|
const entries = relicCatalog.map(item => {
|
|
const rule = relicRules[item.wikiId];
|
|
const missingCards = rule ? relicCardRequirements(rule) : [];
|
|
const unhandled = rule ? unhandledRelicRule(rule) : [];
|
|
const reason = missingMechanisms[item.wikiId] || (missingCards.length ? `尚缺网页对应卡牌:${missingCards.join("、")}` : !rule ? "尚未接入此效果" : unhandled.length ? `尚缺效果接口:${unhandled.join("、")}` : null);
|
|
return Object.freeze({ ...item, owner: null, rule: rule || Object.freeze({}),
|
|
implementation: reason ? "pending" : relicAdaptations[item.wikiId] ? "adapted" : "implemented",
|
|
implementationNote: reason || relicAdaptations[item.wikiId] || "效果已接入,实机验收待完成。", effect: "sts2" });
|
|
});
|
|
entries.push(Object.freeze({ id: "mengsan_hand_charm_shuying", wikiId: "legacy_hand_charm",
|
|
name: "束带", description: "基础手牌上限额外+1;重复获得不叠加。", pool: "通用", tier: "梦三道具",
|
|
ancient: null, owner: null, image: null, effect: "handLimit", amount: 1,
|
|
rule: Object.freeze({ handLimit: 1 }), implementation: "implemented", implementationNote: "保留原梦三道具。" }));
|
|
export const relicDefinitions = Object.freeze(Object.fromEntries(entries.map(entry => [entry.id, entry])));
|
|
const aliases = Object.freeze(Object.fromEntries(entries.flatMap(entry => [[entry.id, entry.id], [entry.wikiId, entry.id], [`mengsan_${entry.wikiId}_shuying`, entry.id]])));
|
|
export const getRelic = id => Object.hasOwn(aliases, id) ? relicDefinitions[aliases[id]] : null;
|
|
export const heldRelics = run => [...new Set((run?.player?.items || []).map(id => getRelic(id)?.id).filter(Boolean))].map(getRelic);
|
|
export const relicPoolFor = run => run?.player?.relicPool || (run?.player?.character === "mengsan_liubei_shuying" ? "铁甲战士" : null);
|
|
export function canAcquireRelic(run, id, { allowPending = false } = {}) {
|
|
const relic = getRelic(id);
|
|
if (!run?.player || !relic || !allowPending && relic.implementation === "pending") return false;
|
|
if (relic.pool !== "通用" && relic.pool !== relicPoolFor(run)) return false;
|
|
return !heldRelics(run).some(item => item.id === relic.id || item.rule.replaces === relic.wikiId);
|
|
}
|
|
export function grantRelic(run, id) {
|
|
const relic = getRelic(id);
|
|
if (!relic) throw new Error(`梦三遗物未注册:${id}`);
|
|
if (!canAcquireRelic(run, id)) return false;
|
|
const draft = JSON.parse(JSON.stringify(run));
|
|
draft.player.items ||= [];
|
|
if (relic.rule.replaces) draft.player.items = draft.player.items.filter(value => getRelic(value)?.wikiId !== relic.rule.replaces);
|
|
draft.player.items.push(relic.id);
|
|
applyRelicPickup(draft, relic, { entries, canAcquire: canAcquireRelic, grant: grantRelic });
|
|
Object.assign(run, draft);
|
|
return true;
|
|
}
|
|
export function initializeRelicMaxHp(run) {
|
|
const amount = run.player.pendingRelicMaxHp || 0;
|
|
if (!Number.isFinite(run.player.maxHp)) return;
|
|
run.player.maxHp = Math.max(1, run.player.maxHp + amount);
|
|
delete run.player.pendingRelicMaxHp;
|
|
run.player.hp = Math.min(run.player.hp, run.player.maxHp);
|
|
if (run.player.pendingRelicFullHeal) { run.player.hp = run.player.maxHp; delete run.player.pendingRelicFullHeal; }
|
|
}
|
|
export const relicRewardIds = entries.filter(entry => entry.implementation !== "pending" && ["普通", "罕见", "稀有"].includes(entry.tier)).map(entry => `shared.reward.relic.${entry.id}`);
|
|
export const relicShopRewardIds = entries.filter(entry => entry.implementation !== "pending" && ["普通", "罕见", "稀有", "商店"].includes(entry.tier)).map(entry => `shared.reward.relic.${entry.id}`);
|
|
export const relicRewards = Object.fromEntries(entries.map(relic => [`shared.reward.relic.${relic.id}`, { relic: relic.id, name: `遗物·${relic.name}`, description: relic.description, image: relic.image }]));
|
|
const ancientKeys={"涅奥":"neow","欧洛巴斯":"orobas","佩尔":"pael","特兹卡塔拉":"tezcatara","诺奴佩普":"nonupep","坦克斯":"tanx","瓦库":"vakuu","达弗":"darv"};
|
|
export const relicRewardPools={
|
|
"shared.pool.relic.shop":[...relicShopRewardIds],
|
|
"shared.pool.relic.event":entries.filter(r=>r.implementation!=="pending" && r.tier==="事件").map(r=>`shared.reward.relic.${r.id}`),
|
|
"shared.pool.relic.initial":entries.filter(r=>r.implementation!=="pending" && r.tier==="初始").map(r=>`shared.reward.relic.${r.id}`),
|
|
...Object.fromEntries(Object.entries(ancientKeys).map(([ancient,key])=>[`shared.pool.relic.ancient.${key}`,entries.filter(r=>r.implementation!=="pending" && r.ancient===ancient).map(r=>`shared.reward.relic.${r.id}`)])),
|
|
};
|