fixed # 更新刘备配置和奖励

This commit is contained in:
2026-09-30 15:43:07 +08:00
parent 82d80397b6
commit 0ccb14cecd
22 changed files with 681 additions and 30 deletions
+2
View File
@@ -18,6 +18,7 @@ EXCLUDE_DIRS = {
"__pycache__",
}
EXCLUDE_FILES = {".gitignore", "log.txt"}
EXCLUDE_EXTENSIONS = {".md", ".mjs"}
def sha256_file(path: Path) -> str:
@@ -33,6 +34,7 @@ def should_include(path: Path, root: Path) -> bool:
return (
path.is_file()
and relative.name not in EXCLUDE_FILES
and path.suffix.lower() not in EXCLUDE_EXTENSIONS
and not any(part in EXCLUDE_DIRS for part in relative.parts)
)
+95 -1
View File
@@ -1,7 +1,10 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { grantRelic, canAcquireRelic, getRelic, heldRelics,
relicRewardIds } from "../mengsan/relics/definitions.js";
relicRewardIds, initializeRelicMaxHp } from "../mengsan/relics/definitions.js";
import { applyRoomRelics, restRecovery } from "../mengsan/relics/rooms.js";
import { createOpeningEffects, createRelicCombatSkills }
from "../mengsan/relics/combat.js";
import { createRelicBattle, createRelicSkills,
applyBattleEndRelics } from "../mengsan/relics/battle.js";
import { canAcquireReward, getRandomRewardChoices }
@@ -32,6 +35,97 @@ const runtime = run => {
return { battle, draws, logs, stop: () => { running = false; } };
};
test("strawberry raises max HP once without healing, including early grants", () => {
const run = newRun();
grant(run, "strawberry", "strawberry");
assert.equal(run.player.maxHp, 57);
assert.equal(run.player.hp, 20);
run.player.maxHp = null;
run.player.items = [];
grant(run, "strawberry");
run.player.maxHp = 50;
initializeRelicMaxHp(run);
initializeRelicMaxHp(run);
assert.equal(run.player.maxHp, 57);
});
test("shop entrance and rest healing cap HP and survive reload without repeats", () => {
const run = newRun();
grant(run, "meal_ticket", "regal_pillow");
const shop = { id: "shop1", type: "shop" };
assert.equal(applyRoomRelics(run, shop, "enter").recovered, 15);
const restored = structuredClone(run);
assert.equal(applyRoomRelics(restored, shop, "enter"), null);
const rest = { id: "rest1", type: "rest" };
assert.equal(restRecovery(run), 23);
assert.equal(applyRoomRelics(run, rest, "upgrade"), null);
assert.equal(applyRoomRelics(run, rest, "heal").recovered, 15);
assert.equal(run.player.hp, 50);
assert.equal(applyRoomRelics(run, rest, "heal"), null);
assert.equal(restRecovery(newRun()), 8);
});
test("opening effects target enemies, apply buffs before damage, and lantern is temporary", async () => {
const run = newRun();
grant(run, "festive_poppers", "bag_of_marbles", "red_mask", "vajra", "lantern");
const hits = [];
const actor = camp => ({ storage: { mengsanCamp_shuying: camp },
isAlive: () => true, addSkill() {}, markSkill() {},
damage(amount, source, nature) {
hits.push({ amount, source, nature,
vulnerable: this.storage.mengsanVulnerable_shuying,
weak: this.storage.mengsanWeak_shuying });
return Promise.resolve();
} });
const owner = actor("player"), enemy = actor("enemy"), ally = actor("ally");
owner.storage.mengsanEnergy_shuying = 3;
owner.storage.mengsanMaxEnergy_shuying = 3;
let refreshes = 0;
const battle = createRelicBattle(run, { active: () => true,
draw: async () => {}, log: () => {},
effect: createOpeningEffects({ players: [owner, enemy, ally] },
owner, () => { refreshes++; }) });
await battle.start();
await battle.start();
assert.equal(hits.length, 1);
assert.equal(hits[0].amount, 9);
assert.equal(hits[0].vulnerable, 1);
assert.equal(hits[0].weak, 1);
assert.equal(hits[0].nature, "nocard");
assert.equal(owner.storage.mengsanStrength_shuying, 1);
assert.equal(ally.storage.mengsanWeak_shuying, undefined);
const first = {};
await battle.turnStart(first);
await battle.turnStart(first);
assert.equal(owner.storage.mengsanEnergy_shuying, 4);
assert.equal(owner.storage.mengsanMaxEnergy_shuying, 3);
owner.storage.mengsanEnergy_shuying = owner.storage.mengsanMaxEnergy_shuying;
await battle.turnStart({});
assert.equal(owner.storage.mengsanEnergy_shuying, 3);
assert.equal(refreshes, 1);
});
test("card attacks add owner strength before weakness and skip scripted damage", async () => {
const owner = { storage: { mengsanStrength_shuying: 1,
mengsanWeak_shuying: 1 } };
const skills = createRelicCombatSkills(() => ({ session: { active: true } }),
() => owner);
const attack = skills.mengsan_relic_attack_shuying;
const event = { source: owner, card: {}, num: 6 };
assert.equal(attack.filter(event), true);
await attack.content({}, event);
assert.equal(event.num, 5);
assert.equal(attack.filter({ ...event, card: null }), false);
assert.equal(attack.filter({ ...event, mengsanScriptedSkill_shuying: true }), false);
const enemy = { storage: { mengsanWeak_shuying: 1 },
removeSkill(skill) { assert.equal(skill, "mengsan_weak_shuying"); } };
const hit = { source: enemy, card: {}, num: 9 };
await attack.content({}, hit);
assert.equal(hit.num, 6);
await skills.mengsan_weak_shuying.content({}, {}, enemy);
assert.equal(enemy.storage.mengsanWeak_shuying, 0);
});
test("relics use existing items, reject duplicates and preserve belt saves", () => {
const run = newRun();
assert.equal(grantRelic(run, id("burning_blood")), true);