fixed # 修补缺失资源,修正已知BUG

This commit is contained in:
2026-09-30 00:33:30 +08:00
parent 98a55dd3d6
commit 3fdaf6d218
17 changed files with 415 additions and 45 deletions
+36 -15
View File
@@ -39,7 +39,25 @@ export function mountEnemyIntent(player, session, assetBase, document,
debuffIcon.src = `${assetBase}/assets/intent/Intent_debuff.png`;
const debuffAmount = document.createElement("span");
debuffLine.append(debuffIcon, debuffAmount);
badge.append(damageLine, debuffLine);
const blockLine = document.createElement("span");
blockLine.className = "mengsan-intent-block-shuying";
const blockIcon = document.createElement("img");
blockIcon.className = "mengsan-intent-icon-shuying";
blockIcon.alt = "Block";
blockIcon.decoding = "async";
blockIcon.src = `${assetBase}/assets/intent/Intent_defend.png`;
const blockAmount = document.createElement("span");
blockLine.append(blockIcon, blockAmount);
const buffLine = document.createElement("span");
buffLine.className = "mengsan-intent-buff-shuying";
const buffIcon = document.createElement("img");
buffIcon.className = "mengsan-intent-icon-shuying";
buffIcon.alt = "Buff";
buffIcon.decoding = "async";
buffIcon.src = `${assetBase}/assets/intent/Intent_buff.png`;
const buffAmount = document.createElement("span");
buffLine.append(buffIcon, buffAmount);
badge.append(damageLine, debuffLine, blockLine, buffLine);
player.appendChild(badge);
let currentIntent = null;
let timer;
@@ -56,6 +74,8 @@ export function mountEnemyIntent(player, session, assetBase, document,
if (isStunIntent(intent)) {
damageLine.hidden = false;
debuffLine.hidden = true;
blockLine.hidden = true;
buffLine.hidden = true;
amount.textContent = "";
const src = `${assetBase}/assets/intent/Intent_stun.png`;
if (icon.getAttribute("src") !== src) icon.src = src;
@@ -76,13 +96,20 @@ export function mountEnemyIntent(player, session, assetBase, document,
Number.isInteger(intent.stacks) && intent.stacks > 0;
debuffLine.hidden = !hasDebuff;
if (hasDebuff) {
const label = intent.id === "frail" ? "Frail" :
intent.id === "vulnerable" ? "Vulnerable" : "Debuff";
const label = intent.debuff === "脆弱" ? "Frail" :
intent.debuff === "易伤" ? "Vulnerable" : "Debuff";
const debuffText = `${label} ×${intent.stacks}`;
if (debuffAmount.textContent !== debuffText) {
debuffAmount.textContent = debuffText;
}
}
const hasBlock = Number.isInteger(intent.block) && intent.block > 0;
const hasStrength = Number.isInteger(intent.strength) && intent.strength > 0;
blockLine.hidden = !hasBlock;
buffLine.hidden = !hasStrength;
if (hasBlock) blockAmount.textContent = String(intent.block);
if (hasStrength) buffAmount.textContent = `力量 ×${intent.strength}`;
const effects = [];
if (hasDamage) {
const hits = attackHitCount(intent);
if (deathBlow && hits !== 1) {
@@ -101,19 +128,13 @@ export function mountEnemyIntent(player, session, assetBase, document,
`${assetBase}/assets/intent/Intent_attack_${tier}.png`;
if (icon.getAttribute("src") !== src) icon.src = src;
icon.alt = deathBlow ? "Death Blow" : "Attack";
const label = `${deathBlow ? "Death Blow" : "Attack"}: ` +
`${damage} damage${hits > 1 ?
` × ${hits} hits` : ""}${hasDebuff ?
`, ${debuffAmount.textContent}` : ""}`;
if (badge.getAttribute("aria-label") !== label) {
badge.setAttribute("aria-label", label);
}
} else {
const label = debuffAmount.textContent;
if (badge.getAttribute("aria-label") !== label) {
badge.setAttribute("aria-label", label);
}
effects.push(`${deathBlow ? "Death Blow" : "Attack"}: ${damage} damage${hits > 1 ? ` × ${hits} hits` : ""}`);
}
if (hasDebuff) effects.push(debuffAmount.textContent);
if (hasBlock) effects.push(`Block ${intent.block}`);
if (hasStrength) effects.push(`Strength +${intent.strength}`);
const label = effects.join(", ") || intent.name || "Intent";
if (badge.getAttribute("aria-label") !== label) badge.setAttribute("aria-label", label);
badge.hidden = false;
};
timer = setInterval(refresh, 100);
+22 -1
View File
@@ -16,6 +16,11 @@ const BASE_DECKS = Object.freeze({
const HEALTH = Object.freeze({
mengsan_soldier_shuying: 24,
mengsan_flyconid_shuying: 48,
mengsan_raider_brute_shuying: 32,
mengsan_raider_assassin_shuying: 21,
mengsan_raider_axe_shuying: 21,
mengsan_raider_crossbow_shuying: 20,
mengsan_raider_tracker_shuying: 23,
re_xiahoudun: 30, re_zhangliao: 28, re_xuzhu: 34, re_lvbu: 120,
re_ganning: 39, re_zhangfei: 42, re_huangzhong: 37, re_weiyan: 40,
re_guanyu: 65, dianwei: 62, shen_guanyu: 165,
@@ -63,9 +68,25 @@ export class OpeningSoldier extends Monster {
export class Flyconid extends Monster {
constructor(options = {}) { super({ ...options, character: "mengsan_flyconid_shuying", tier: "normal", hp: 48 }); }
}
const raiderClass = (character, hp) => class extends Monster {
constructor(options = {}) { super({ ...options, character, tier: "normal", hp }); }
};
export const RaiderBrute = raiderClass("mengsan_raider_brute_shuying", 32);
export const RaiderAssassin = raiderClass("mengsan_raider_assassin_shuying", 21);
export const RaiderAxe = raiderClass("mengsan_raider_axe_shuying", 21);
export const RaiderCrossbow = raiderClass("mengsan_raider_crossbow_shuying", 20);
export const RaiderTracker = raiderClass("mengsan_raider_tracker_shuying", 23);
// 新怪物子类在这里注册,未注册的角色使用 Monster 的阶级默认值。
export const MONSTER_TYPES = Object.freeze({ mengsan_soldier_shuying: OpeningSoldier, mengsan_flyconid_shuying: Flyconid });
export const MONSTER_TYPES = Object.freeze({
mengsan_soldier_shuying: OpeningSoldier,
mengsan_flyconid_shuying: Flyconid,
mengsan_raider_brute_shuying: RaiderBrute,
mengsan_raider_assassin_shuying: RaiderAssassin,
mengsan_raider_axe_shuying: RaiderAxe,
mengsan_raider_crossbow_shuying: RaiderCrossbow,
mengsan_raider_tracker_shuying: RaiderTracker,
});
export function createMonster(spec) {
const Type = Object.hasOwn(MONSTER_TYPES, spec.character) ? MONSTER_TYPES[spec.character] : Monster;
+39
View File
@@ -0,0 +1,39 @@
// 普通难度数值;团伙每名成员仅预测并执行自己的一项技能,随后照常出牌。
export const RAIDER_MOVES = Object.freeze({
beat: Object.freeze({ id: "beat", name: "殴打", damage: 7 }),
roar: Object.freeze({ id: "roar", name: "怒吼", strength: 3 }),
killshot: Object.freeze({ id: "killshot", name: "致命射击", damage: 10 }),
swing: Object.freeze({ id: "swing", name: "挥击", damage: 5, block: 5 }),
bigSwing: Object.freeze({ id: "bigSwing", name: "大力挥舞", damage: 12 }),
reload: Object.freeze({ id: "reload", name: "装填", block: 3 }),
fire: Object.freeze({ id: "fire", name: "射击!", damage: 14 }),
track: Object.freeze({ id: "track", name: "追踪", debuff: "脆弱", stacks: 2 }),
hounds: Object.freeze({ id: "hounds", name: "放狗", damage: 1, hits: 8 }),
});
export const RAIDER_CYCLES = Object.freeze({
mengsan_raider_brute_shuying: Object.freeze([RAIDER_MOVES.beat, RAIDER_MOVES.roar]),
mengsan_raider_assassin_shuying: Object.freeze([RAIDER_MOVES.killshot]),
mengsan_raider_axe_shuying: Object.freeze([RAIDER_MOVES.swing, RAIDER_MOVES.swing, RAIDER_MOVES.bigSwing]),
mengsan_raider_crossbow_shuying: Object.freeze([RAIDER_MOVES.reload, RAIDER_MOVES.fire]),
mengsan_raider_tracker_shuying: Object.freeze([RAIDER_MOVES.track, RAIDER_MOVES.hounds]),
});
export function isRaiderCharacter(character) {
return Object.hasOwn(RAIDER_CYCLES, character);
}
export function selectRaiderMove(character, state = {}) {
const cycle = RAIDER_CYCLES[character];
if (!cycle) return null;
const turn = state.turnsTaken || 0;
if (!Number.isInteger(turn) || turn < 0) throw new RangeError("劫掠者行动次数无效");
if (character === "mengsan_raider_tracker_shuying") {
return turn === 0 ? RAIDER_MOVES.track : RAIDER_MOVES.hounds;
}
return cycle[turn % cycle.length];
}
export function recordRaiderAction(state = {}) {
return { turnsTaken: (state.turnsTaken || 0) + 1 };
}