Implement dex and thorns effects

This commit is contained in:
2026-06-16 01:59:40 +09:00
parent 654a49f3a2
commit 98ca1668c8
5 changed files with 132 additions and 19 deletions

View File

@@ -111,7 +111,7 @@ export function simulateCombat(data, rng, stats) {
const exhaust = [];
let hand = [];
let pHp = PLAYER_HP, pBlock = 0;
let pStr = 0, pWeak = 0, pVuln = 0;
let pStr = 0, pDex = 0, pThorns = 0, pWeak = 0, pVuln = 0;
const powers = [];
const mob = monsters.map((m) => ({
name: m.name, hp: m.maxHp, maxHp: m.maxHp, block: 0, str: 0, weak: 0, vuln: 0, poison: 0,
@@ -135,6 +135,7 @@ export function simulateCombat(data, rng, stats) {
function resolveCardEffects(id, c, costSpent, recordStats = true) {
const alive = aliveList();
let dmg = 0;
let blockGained = 0;
if (c.kind === 'Attack') {
if (alive.length && c.damage) {
const target = chooseTarget(alive, calcAttack(c.damage || 0, pStr, pWeak, 0));
@@ -163,11 +164,11 @@ export function simulateCombat(data, rng, stats) {
if (target.hp <= 0) target.alive = false;
}
}
if (c.block) pBlock += c.block;
if (c.block) { blockGained = Math.max(0, c.block + pDex); pBlock += blockGained; }
} else if (c.kind === 'Power') {
if (c.powerEffect && recordStats) powers.push(id);
} else {
pBlock += c.block || 0;
if (c.block) { blockGained = Math.max(0, c.block + pDex); pBlock += blockGained; }
if ((c.weak || c.vuln || c.poison) && alive.length) {
const target = chooseTarget(alive, 0);
if (c.weak) target.weak += c.weak;
@@ -176,10 +177,12 @@ export function simulateCombat(data, rng, stats) {
}
}
if (c.strength) pStr += c.strength;
if (c.dex) pDex += c.dex;
if (c.thorns) pThorns += c.thorns;
if (c.selfVuln) pVuln += c.selfVuln;
if (c.heal) pHp = Math.min(pHp + c.heal, PLAYER_HP);
if (c.draw) draw(c.draw);
if (recordStats && stats) stats[id] = bump(stats[id], costSpent, dmg, c.block || 0);
if (recordStats && stats) stats[id] = bump(stats[id], costSpent, dmg, blockGained);
}
function triggerSly(id) {
const c = cards[id];
@@ -257,7 +260,12 @@ export function simulateCombat(data, rng, stats) {
if (it) {
if (it.kind === 'Attack') {
const atk = calcAttack(it.value, m.str, m.weak, pVuln);
const beforeHp = pHp;
const r = applyDamage(pHp, pBlock, atk); pHp = r.hp; pBlock = r.block;
if (beforeHp > pHp && pThorns > 0) {
m.hp -= pThorns;
if (m.hp <= 0) m.alive = false;
}
} else if (it.kind === 'Defend') { m.block += it.value; }
else if (it.kind === 'Debuff') {
if (it.effect === 'weak') pWeak += it.value;

View File

@@ -418,3 +418,32 @@ test("simulateCombat: exhaust cards do not return through discard reshuffle", ()
assert.equal(r.win, false);
assert.equal(r.draw, true);
});
test("simulateCombat: dex increases block gained from cards", () => {
const data = {
cards: {
Footwork: { name: "Footwork", cost: 1, kind: "Power", dex: 2 },
Defend: { name: "Defend", cost: 1, kind: "Skill", block: 5 },
},
starterDeck: ["Footwork", "Defend"],
monsters: [{ name: "Dummy", maxHp: 99, intents: [{ kind: "Attack", value: 6 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, false);
assert.equal(r.draw, true);
assert.equal(r.playerHpRemaining, 80);
});
test("simulateCombat: thorns reflects unblocked attack damage", () => {
const data = {
cards: {
Spikes: { name: "Spikes", cost: 1, kind: "Power", thorns: 4 },
},
starterDeck: ["Spikes"],
monsters: [{ name: "Dummy", maxHp: 4, intents: [{ kind: "Attack", value: 1 }] }],
};
const r = simulateCombat(data, () => 0.999999);
assert.equal(r.win, true);
assert.equal(r.turns, 1);
assert.equal(r.playerHpRemaining, 79);
});