밴딧 카드 공용 효과 확장

This commit is contained in:
2026-06-19 01:26:15 +09:00
parent f64e35668d
commit 71435a2c91
12 changed files with 148 additions and 23 deletions

View File

@@ -90,12 +90,29 @@ function canPlayCardNow(card, ctx = {}) {
// 이며, Lua에 대응 AI가 없다(동기화 대상은 데미지/방어/의도/승패 규칙이지 플레이어 선택이 아님).
// 손패에서 낼 카드 인덱스(-1=종료). 파워 우선(지속 가치) → 공격 → 스킬.
export function chooseAction(hand, cards, energy, ctx = {}) {
const entries = hand.map((id, i) => ({ id, i })).filter((x) => cards[x.id] && cards[x.id].cost <= energy && !cards[x.id].unplayable && canPlayCardNow(cards[x.id], ctx));
const entries = hand.map((id, i) => ({ id, i })).filter((x) => {
const card = cards[x.id];
if (!card || card.unplayable || !canPlayCardNow(card, ctx)) return false;
let effectiveCost = card.cost || 0;
if (card.kind === 'Skill') {
if (ctx.nextSkillCostZero === true) effectiveCost = 0;
else effectiveCost = Math.max(0, effectiveCost - (ctx.skillCostReductionThisTurn || 0));
}
return effectiveCost <= energy;
});
const powers = entries.filter((x) => cards[x.id].kind === 'Power');
const attacks = entries.filter((x) => cards[x.id].kind === 'Attack');
const skills = entries.filter((x) => cards[x.id].kind === 'Skill');
const dmgEff = (x) => (cards[x.id].damage || 0) / Math.max(cards[x.id].cost, 1);
const blkEff = (x) => (cards[x.id].block || 0) / Math.max(cards[x.id].cost, 1);
const effectiveCost = (card) => {
let cost = card.cost || 0;
if (card.kind === 'Skill') {
if (ctx.nextSkillCostZero === true) cost = 0;
else cost = Math.max(0, cost - (ctx.skillCostReductionThisTurn || 0));
}
return cost;
};
const dmgEff = (x) => (cards[x.id].damage || 0) / Math.max(effectiveCost(cards[x.id]), 1);
const blkEff = (x) => (cards[x.id].block || 0) / Math.max(effectiveCost(cards[x.id]), 1);
const bestBy = (list, fn) => list.slice().sort((a, b) => fn(b) - fn(a))[0];
if (powers.length) return powers[0].i;
if (attacks.length) return bestBy(attacks, dmgEff).i;
@@ -128,6 +145,9 @@ export function simulateCombat(data, rng, stats) {
let hand = [];
let pHp = PLAYER_HP, pBlock = 0;
let pStr = 0, pDex = 0, pThorns = 0, pWeak = 0, pVuln = 0;
let blockGainMultiplier = 1;
let nextSkillCostZero = false;
let skillCostReductionThisTurn = 0;
let nextTurnBlock = 0, nextTurnDraw = 0, nextTurnKeepBlock = false;
let nextTurnAttackMultiplier = 1, turnAttackMultiplier = 1;
let nextTurnAddCards = [];
@@ -161,6 +181,7 @@ export function simulateCombat(data, rng, stats) {
function addBlock(base) {
let amount = base || 0;
if (amount > 0) amount += pDex;
if (blockGainMultiplier > 1) amount *= blockGainMultiplier;
if (amount < 0) amount = 0;
pBlock += amount;
return amount;
@@ -243,6 +264,9 @@ export function simulateCombat(data, rng, stats) {
const alive = aliveList();
let dmg = 0;
let blockGained = 0;
if (c.blockGainMultiplier && c.blockGainMultiplier > 0) blockGainMultiplier *= c.blockGainMultiplier;
if (c.nextSkillCostZero === true) nextSkillCostZero = true;
if (c.skillCostReductionThisTurn && c.skillCostReductionThisTurn > 0) skillCostReductionThisTurn += c.skillCostReductionThisTurn;
if (c.kind === 'Attack') {
if (alive.length && c.damage) {
const baseDamage = attackBaseForCard(id, c);
@@ -331,6 +355,8 @@ export function simulateCombat(data, rng, stats) {
turns++;
turnAttackCardsPlayed = 0;
turnDiscardedCards = 0;
blockGainMultiplier = 1;
skillCostReductionThisTurn = 0;
// 파워 발동 — Lua StartPlayerTurn 동기화 (블록 리셋 후 strength/energy/block 파워)
if (nextTurnKeepBlock === true) nextTurnKeepBlock = false;
else pBlock = 0;
@@ -362,12 +388,16 @@ export function simulateCombat(data, rng, stats) {
while (true) {
const alive = aliveList();
if (alive.length === 0) break;
const idx = chooseAction(hand, cards, energy, { drawPileCount: drawPile.length });
const idx = chooseAction(hand, cards, energy, { drawPileCount: drawPile.length, nextSkillCostZero, skillCostReductionThisTurn });
if (idx < 0) break;
const id = hand[idx], c = cards[id];
energy -= c.cost;
resolveCardEffects(id, c, c.cost);
const skillFree = c.kind === 'Skill' && nextSkillCostZero === true;
const baseCost = c.cost || 0;
const cost = skillFree ? 0 : (c.kind === 'Skill' ? Math.max(0, baseCost - skillCostReductionThisTurn) : baseCost);
energy -= cost;
resolveCardEffects(id, c, cost);
if (c.kind === 'Attack') turnAttackCardsPlayed++;
if (skillFree === true && c.nextSkillCostZero !== true) nextSkillCostZero = false;
const playedBlock = powerFieldTotal('cardPlayedBlock');
if (playedBlock > 0) addBlock(playedBlock);
hand.splice(idx, 1);