도적 카드 공용 효과 추가

This commit is contained in:
2026-06-19 21:59:49 +09:00
parent f6650a6c70
commit 34531b184f
13 changed files with 331 additions and 35 deletions

View File

@@ -95,11 +95,12 @@ export function chooseAction(hand, cards, energy, ctx = {}) {
if (!card || card.unplayable || !canPlayCardNow(card, ctx)) return false;
let effectiveCost = card.cost || 0;
if (ctx.handCostZeroThisTurn === true) effectiveCost = 0;
else if (card.useAllEnergy === true) effectiveCost = 1;
else if (card.kind === 'Skill') {
if (ctx.nextSkillCostZero === true) effectiveCost = 0;
else effectiveCost = Math.max(0, effectiveCost - (ctx.skillCostReductionThisTurn || 0));
}
return effectiveCost <= energy;
return card.useAllEnergy === true ? true : effectiveCost <= energy;
});
const powers = entries.filter((x) => cards[x.id].kind === 'Power');
const attacks = entries.filter((x) => cards[x.id].kind === 'Attack');
@@ -107,6 +108,7 @@ export function chooseAction(hand, cards, energy, ctx = {}) {
const effectiveCost = (card) => {
let cost = card.cost || 0;
if (ctx.handCostZeroThisTurn === true) cost = 0;
else if (card.useAllEnergy === true) cost = 1;
else if (card.kind === 'Skill') {
if (ctx.nextSkillCostZero === true) cost = 0;
else cost = Math.max(0, cost - (ctx.skillCostReductionThisTurn || 0));
@@ -156,6 +158,7 @@ export function simulateCombat(data, rng, stats) {
let nextTurnAttackMultiplier = 1, turnAttackMultiplier = 1;
let nextTurnAddCards = [];
let turnAttackCardsPlayed = 0, turnDiscardedCards = 0;
let cardsDrawnThisCombat = 0;
let energy = 0;
const powers = [];
const mob = monsters.map((m) => ({
@@ -172,6 +175,7 @@ export function simulateCombat(data, rng, stats) {
if (drawPile.length === 0) break;
const card = drawPile.pop();
drawn.push(card);
cardsDrawnThisCombat++;
// 손패 10장 상한 — 초과 드로는 자동 버림 (Lua DrawCards 동기화)
if (hand.length >= 10) {
discard.push(card);
@@ -228,6 +232,7 @@ export function simulateCombat(data, rng, stats) {
if (c.damagePerAttackPlayedThisTurn) base += turnAttackCardsPlayed * c.damagePerAttackPlayedThisTurn;
if (c.damagePerDiscardedThisTurn) base += turnDiscardedCards * c.damagePerDiscardedThisTurn;
if (c.damagePerSkillInHand) base += countOtherHandSkills(id) * c.damagePerSkillInHand;
if (c.damagePerCardDrawnThisCombat) base += cardsDrawnThisCombat * c.damagePerCardDrawnThisCombat;
if (base < 0) base = 0;
return base;
}
@@ -277,9 +282,10 @@ export function simulateCombat(data, rng, stats) {
if (c.skillCostReductionThisTurn && c.skillCostReductionThisTurn > 0) skillCostReductionThisTurn += c.skillCostReductionThisTurn;
if (c.handCostZeroThisTurn === true) handCostZeroThisTurn = true;
if (c.drawDisabledThisTurn === true) drawDisabledThisTurn = true;
const xEnergy = costSpent || 0;
if (c.kind === 'Attack') {
if (alive.length && c.damage) {
const baseDamage = attackBaseForCard(id, c);
if (alive.length && (c.damage || c.xDamagePerEnergy)) {
const baseDamage = c.xDamagePerEnergy ? xEnergy * c.xDamagePerEnergy : attackBaseForCard(id, c);
const bonusHits = (c.otherHandAtLeast && c.bonusHitsWhenOtherHandAtLeast && Math.max(0, hand.length - 1) >= c.otherHandAtLeast)
? c.bonusHitsWhenOtherHandAtLeast : 0;
const hitN = (c.hits || 1) + bonusHits;
@@ -295,6 +301,8 @@ export function simulateCombat(data, rng, stats) {
const d2 = m2.vuln > 0 ? Math.floor(totalNv * 1.5) : totalNv;
const r2 = applyDamage(m2.hp, m2.block, d2);
m2.hp = r2.hp; m2.block = r2.block;
const attackPoison = powerFieldTotal('attackPoison');
if (d2 > 0 && attackPoison > 0) m2.poison += attackPoison;
if (m2.hp <= 0) m2.alive = false;
}
} else {
@@ -306,6 +314,8 @@ export function simulateCombat(data, rng, stats) {
const r = applyDamage(target.hp, target.block, dmg);
target.hp = r.hp; target.block = r.block;
}
const attackPoison = powerFieldTotal('attackPoison');
if (dmg > 0 && attackPoison > 0) target.poison += attackPoison;
if (target.hp <= 0) target.alive = false;
}
}
@@ -314,9 +324,10 @@ export function simulateCombat(data, rng, stats) {
if (recordStats) powers.push(id);
} else {
if (c.block) blockGained = addBlock(c.block);
if ((c.weak || c.vuln || c.poison) && alive.length) {
const weakAmount = (c.weak || 0) + (c.xWeakPerEnergy || 0) * xEnergy;
if ((weakAmount || c.vuln || c.poison) && alive.length) {
const target = chooseTarget(alive, 0);
if (c.weak) target.weak += c.weak;
if (weakAmount) target.weak += weakAmount;
if (c.vuln) target.vuln += c.vuln;
if (c.poison) target.poison += c.poison;
}
@@ -340,6 +351,25 @@ export function simulateCombat(data, rng, stats) {
}
}
if (c.addShiv && !c.discard && c.discardAll !== true) addCardsToHand('Shiv', c.addShiv);
if (c.cardPlayedDamage && alive.length) {
const target = chooseTarget(aliveList(), 0);
if (target && target.alive) {
target.hp -= c.cardPlayedDamage;
dmg += c.cardPlayedDamage;
if (target.hp <= 0) target.alive = false;
}
}
if (c.cardPlayedRandomDamage && alive.length) {
const pool = aliveList();
if (pool.length) {
const target = pool[Math.floor(rng() * pool.length)];
if (target) {
target.hp -= c.cardPlayedRandomDamage;
dmg += c.cardPlayedRandomDamage;
if (target.hp <= 0) target.alive = false;
}
}
}
if (recordStats && stats) stats[id] = bump(stats[id], costSpent, dmg, blockGained);
}
function triggerSly(id) {
@@ -421,7 +451,7 @@ export function simulateCombat(data, rng, stats) {
const id = hand[idx], c = cards[id];
const skillFree = c.kind === 'Skill' && nextSkillCostZero === true;
const baseCost = c.cost || 0;
const cost = handCostZeroThisTurn === true ? 0 : (skillFree ? 0 : (c.kind === 'Skill' ? Math.max(0, baseCost - skillCostReductionThisTurn) : baseCost));
const cost = handCostZeroThisTurn === true ? 0 : (c.useAllEnergy === true ? energy : (skillFree ? 0 : (c.kind === 'Skill' ? Math.max(0, baseCost - skillCostReductionThisTurn) : baseCost)));
energy -= cost;
resolveCardEffects(id, c, cost);
if (c.kind === 'Attack') turnAttackCardsPlayed++;