fix(deck): useAllEnergy 카드는 코스트감소를 무시하고 전 에너지 소비 (Lua/JS 동기화)

Malaise(불쾌, xWeakPerEnergy)·Skewer(꼬챙이, xDamagePerEnergy) 같은
useAllEnergy 카드는 X 효과가 소비 에너지에 비례하는데, Lua는 코스트
감소(스킬코스트감소·다음스킬무료·전투코스트감소)를 useAllEnergy에도
적용해 소비 에너지가 full보다 줄고 X도 약해졌다(코스트감소가 카드를
약화시키는 역설). JS는 스킬코스트감소만 건너뛰고 combatReduction은
적용해 양쪽이 미묘하게 달랐다.

정답: useAllEnergy는 "전 에너지 소비"이므로 어떤 코스트감소도 무시.
Lua는 3개 감소 조건에 useAllEnergy 제외 추가, JS는 finalCost를
useAllEnergy면 combatReduction 미적용으로. 양쪽 모두 full 에너지 소비로
일치. 산출물 재생성 포함.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UUvHKjrt8jqLzDeCsRRGmj
This commit is contained in:
2026-06-29 20:48:29 +09:00
parent d78049182b
commit ead73b427e
3 changed files with 5 additions and 5 deletions

View File

@@ -3340,7 +3340,7 @@
"Name": "slot" "Name": "slot"
} }
], ],
"Code": "if self:IsDiscardSelecting() == true then\n\tself:SelectDiscardSlot(slot)\n\treturn\nend\nif self:IsRetainSelecting() == true then\n\tself:SelectRetainSlot(slot)\n\treturn\nend\nif self:IsReserveSelecting() == true then\n\tself:SelectReserveSlot(slot)\n\treturn\nend\nif self.CombatOver == true or self.FxBusy == true or self.TurnBusy == true then\n\treturn\nend\nif self.Hand == nil then\n\treturn\nend\nlocal cardId = self.Hand[slot]\nif cardId == nil then\n\treturn\nend\nlocal c = self.Cards[cardId]\nif c == nil then\n\treturn\nend\nif c.unplayable == true then\n\tself:Toast(\"사용할 수 없는 카드입니다\")\n\treturn\nend\nif self:CanPlayCardNow(c) ~= true then\n\treturn\nend\nlocal cost = c.cost or 0\nlocal skillFree = false\nlocal skillRepeat = 0\nif self.HandCostZeroThisTurn == true then\n\tcost = 0\nelseif c.useAllEnergy == true then\n\tcost = self.Energy\nend\nif c.kind == \"Skill\" and self.NextSkillCostZero == true then\n\tcost = 0\n\tskillFree = true\nend\nif c.kind == \"Skill\" and self.SkillCostReductionThisTurn ~= nil and self.SkillCostReductionThisTurn > 0 then\n\tcost = math.max(0, cost - self.SkillCostReductionThisTurn)\nend\nif self.CombatCardCostReduction ~= nil and self.CombatCardCostReduction[cardId] ~= nil then\n\tcost = math.max(0, cost - self.CombatCardCostReduction[cardId])\nend\nif c.kind == \"Skill\" and self.NextSkillRepeatCount ~= nil and self.NextSkillRepeatCount > 0 then\n\tskillRepeat = self.NextSkillRepeatCount\nend\nif self.Energy < cost then\n\tself:Toast(\"에너지가 부족합니다\")\n\treturn\nend\nself.Energy = self.Energy - cost\nself.ActiveKillReward = c.rewardOnKill or 0\nself:ResolveCardEffects(cardId, slot, c, false, cost)\nlocal function applyCardPlayHooks()\n\tif self:HasPowerField(\"cardPlayedBlock\") == true then\n\t\tself:AddCardBlock(self:AddPowerFieldTotal(\"cardPlayedBlock\"))\n\tend\n\tif c.cardPlayedDamage ~= nil and c.cardPlayedDamage > 0 then\n\t\tself:DealDirectDamageToTarget(c.cardPlayedDamage)\n\tend\n\tif c.cardPlayedRandomDamage ~= nil and c.cardPlayedRandomDamage > 0 then\n\t\tself:DealDirectDamageToRandomMonster(c.cardPlayedRandomDamage)\n\tend\nend\napplyCardPlayHooks()\nif skillRepeat > 0 then\n\tlocal remaining = (self.NextSkillRepeatCount or 0) - skillRepeat\n\tif remaining < 0 then\n\t\tremaining = 0\n\tend\n\tself.NextSkillRepeatCount = remaining\n\tfor i = 1, skillRepeat do\n\t\tself:ResolveCardEffects(cardId, slot, c, false, cost)\n\t\tapplyCardPlayHooks()\n\tend\nend\nif c.kind == \"Attack\" then\n\tself.TurnAttackCardsPlayed = (self.TurnAttackCardsPlayed or 0) + 1\nend\nif skillFree == true then\n\tif c.nextSkillCostZero ~= true then\n\t\tself.NextSkillCostZero = false\n\tend\nend\nif self.ActiveKillReward ~= nil and self.ActiveKillReward <= 0 then\n\tself.ActiveKillReward = 0\nend\nif c.combatCostReductionOnPlay ~= nil and c.combatCostReductionOnPlay > 0 then\n\tif self.CombatCardCostReduction == nil then\n\t\tself.CombatCardCostReduction = {}\n\tend\n\tself.CombatCardCostReduction[cardId] = (self.CombatCardCostReduction[cardId] or 0) + c.combatCostReductionOnPlay\nend\ntable.remove(self.Hand, slot)\nif c.exhaust == true then\n\tif self.ExhaustPile == nil then self.ExhaustPile = {} end\n\ttable.insert(self.ExhaustPile, cardId)\nelseif c.kind ~= \"Power\" then\n\ttable.insert(self.DiscardPile, cardId)\nend\nself:RenderHand(false)\nself:RenderPiles()\nself:RenderCombat()\nif self:BeginDiscardSelection(c) == true then\n\treturn\nend\nif self:BeginReserveSelection(c) == true then\n\treturn\nend\nself:RenderHand(false)\nself:RenderPiles()\nself:RenderCombat()\nself:CheckCombatEnd()", "Code": "if self:IsDiscardSelecting() == true then\n\tself:SelectDiscardSlot(slot)\n\treturn\nend\nif self:IsRetainSelecting() == true then\n\tself:SelectRetainSlot(slot)\n\treturn\nend\nif self:IsReserveSelecting() == true then\n\tself:SelectReserveSlot(slot)\n\treturn\nend\nif self.CombatOver == true or self.FxBusy == true or self.TurnBusy == true then\n\treturn\nend\nif self.Hand == nil then\n\treturn\nend\nlocal cardId = self.Hand[slot]\nif cardId == nil then\n\treturn\nend\nlocal c = self.Cards[cardId]\nif c == nil then\n\treturn\nend\nif c.unplayable == true then\n\tself:Toast(\"사용할 수 없는 카드입니다\")\n\treturn\nend\nif self:CanPlayCardNow(c) ~= true then\n\treturn\nend\nlocal cost = c.cost or 0\nlocal skillFree = false\nlocal skillRepeat = 0\nif self.HandCostZeroThisTurn == true then\n\tcost = 0\nelseif c.useAllEnergy == true then\n\tcost = self.Energy\nend\nif c.kind == \"Skill\" and c.useAllEnergy ~= true and self.NextSkillCostZero == true then\n\tcost = 0\n\tskillFree = true\nend\nif c.kind == \"Skill\" and c.useAllEnergy ~= true and self.SkillCostReductionThisTurn ~= nil and self.SkillCostReductionThisTurn > 0 then\n\tcost = math.max(0, cost - self.SkillCostReductionThisTurn)\nend\nif c.useAllEnergy ~= true and self.CombatCardCostReduction ~= nil and self.CombatCardCostReduction[cardId] ~= nil then\n\tcost = math.max(0, cost - self.CombatCardCostReduction[cardId])\nend\nif c.kind == \"Skill\" and self.NextSkillRepeatCount ~= nil and self.NextSkillRepeatCount > 0 then\n\tskillRepeat = self.NextSkillRepeatCount\nend\nif self.Energy < cost then\n\tself:Toast(\"에너지가 부족합니다\")\n\treturn\nend\nself.Energy = self.Energy - cost\nself.ActiveKillReward = c.rewardOnKill or 0\nself:ResolveCardEffects(cardId, slot, c, false, cost)\nlocal function applyCardPlayHooks()\n\tif self:HasPowerField(\"cardPlayedBlock\") == true then\n\t\tself:AddCardBlock(self:AddPowerFieldTotal(\"cardPlayedBlock\"))\n\tend\n\tif c.cardPlayedDamage ~= nil and c.cardPlayedDamage > 0 then\n\t\tself:DealDirectDamageToTarget(c.cardPlayedDamage)\n\tend\n\tif c.cardPlayedRandomDamage ~= nil and c.cardPlayedRandomDamage > 0 then\n\t\tself:DealDirectDamageToRandomMonster(c.cardPlayedRandomDamage)\n\tend\nend\napplyCardPlayHooks()\nif skillRepeat > 0 then\n\tlocal remaining = (self.NextSkillRepeatCount or 0) - skillRepeat\n\tif remaining < 0 then\n\t\tremaining = 0\n\tend\n\tself.NextSkillRepeatCount = remaining\n\tfor i = 1, skillRepeat do\n\t\tself:ResolveCardEffects(cardId, slot, c, false, cost)\n\t\tapplyCardPlayHooks()\n\tend\nend\nif c.kind == \"Attack\" then\n\tself.TurnAttackCardsPlayed = (self.TurnAttackCardsPlayed or 0) + 1\nend\nif skillFree == true then\n\tif c.nextSkillCostZero ~= true then\n\t\tself.NextSkillCostZero = false\n\tend\nend\nif self.ActiveKillReward ~= nil and self.ActiveKillReward <= 0 then\n\tself.ActiveKillReward = 0\nend\nif c.combatCostReductionOnPlay ~= nil and c.combatCostReductionOnPlay > 0 then\n\tif self.CombatCardCostReduction == nil then\n\t\tself.CombatCardCostReduction = {}\n\tend\n\tself.CombatCardCostReduction[cardId] = (self.CombatCardCostReduction[cardId] or 0) + c.combatCostReductionOnPlay\nend\ntable.remove(self.Hand, slot)\nif c.exhaust == true then\n\tif self.ExhaustPile == nil then self.ExhaustPile = {} end\n\ttable.insert(self.ExhaustPile, cardId)\nelseif c.kind ~= \"Power\" then\n\ttable.insert(self.DiscardPile, cardId)\nend\nself:RenderHand(false)\nself:RenderPiles()\nself:RenderCombat()\nif self:BeginDiscardSelection(c) == true then\n\treturn\nend\nif self:BeginReserveSelection(c) == true then\n\treturn\nend\nself:RenderHand(false)\nself:RenderPiles()\nself:RenderCombat()\nself:CheckCombatEnd()",
"Scope": 2, "Scope": 2,
"ExecSpace": 6, "ExecSpace": 6,
"Attributes": [], "Attributes": [],

View File

@@ -659,7 +659,7 @@ export function simulateCombat(data, rng, stats) {
const baseCost = c.cost || 0; const baseCost = c.cost || 0;
const combatReduction = combatCardCostReduction[id] || 0; const combatReduction = combatCardCostReduction[id] || 0;
const cost = handCostZeroThisTurn === true ? 0 : (c.useAllEnergy === true ? energy : (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)));
const finalCost = Math.max(0, cost - combatReduction); const finalCost = c.useAllEnergy === true ? cost : Math.max(0, cost - combatReduction);
energy -= finalCost; energy -= finalCost;
resolveCardEffects(id, c, finalCost); resolveCardEffects(id, c, finalCost);
const playedBlock = powerFieldTotal('cardPlayedBlock'); const playedBlock = powerFieldTotal('cardPlayedBlock');

View File

@@ -52,14 +52,14 @@ if self.HandCostZeroThisTurn == true then
elseif c.useAllEnergy == true then elseif c.useAllEnergy == true then
cost = self.Energy cost = self.Energy
end end
if c.kind == "Skill" and self.NextSkillCostZero == true then if c.kind == "Skill" and c.useAllEnergy ~= true and self.NextSkillCostZero == true then
cost = 0 cost = 0
skillFree = true skillFree = true
end end
if c.kind == "Skill" and self.SkillCostReductionThisTurn ~= nil and self.SkillCostReductionThisTurn > 0 then if c.kind == "Skill" and c.useAllEnergy ~= true and self.SkillCostReductionThisTurn ~= nil and self.SkillCostReductionThisTurn > 0 then
cost = math.max(0, cost - self.SkillCostReductionThisTurn) cost = math.max(0, cost - self.SkillCostReductionThisTurn)
end end
if self.CombatCardCostReduction ~= nil and self.CombatCardCostReduction[cardId] ~= nil then if c.useAllEnergy ~= true and self.CombatCardCostReduction ~= nil and self.CombatCardCostReduction[cardId] ~= nil then
cost = math.max(0, cost - self.CombatCardCostReduction[cardId]) cost = math.max(0, cost - self.CombatCardCostReduction[cardId])
end end
if c.kind == "Skill" and self.NextSkillRepeatCount ~= nil and self.NextSkillRepeatCount > 0 then if c.kind == "Skill" and self.NextSkillRepeatCount ~= nil and self.NextSkillRepeatCount > 0 then