feat(card-frames): 보상 등급 가중 추첨 70/25/5 (Lua + JS 미러 rarityForRoll·경계 테스트)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 23:40:58 +09:00
parent 35dfcbaffe
commit aaa68ebe07
3 changed files with 29 additions and 2 deletions

View File

@@ -29,6 +29,13 @@ export function shuffle(arr, rng) {
// 공격 피해 공식 — Lua CalcPlayerAttack(힘·약화) + DealDamageToTarget(취약)과 동기화.
// floor((base + str) * (weak>0 ? 0.75 : 1)) → floor(... * (vulnOnTarget>0 ? 1.5 : 1))
// 보상 카드 등급 추첨 (Lua OfferReward 미러) — roll ∈ 1..100, normal 70 / unique 25 / legend 5
export function rarityForRoll(roll) {
if (roll > 95) return 'legend';
if (roll > 70) return 'unique';
return 'normal';
}
export function calcAttack(base, str, weak, vulnOnTarget) {
let dmg = base + str;
if (weak > 0) dmg = Math.floor(dmg * 0.75);

View File

@@ -1,9 +1,18 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import {
mulberry32, applyDamage, chooseAction, chooseTarget, simulateCombat, runBatch, calcAttack,
mulberry32, applyDamage, chooseAction, chooseTarget, simulateCombat, runBatch, calcAttack, rarityForRoll,
} from './sim-balance.mjs';
test('rarityForRoll: 70/25/5 경계 (Lua OfferReward 미러)', () => {
assert.equal(rarityForRoll(1), 'normal');
assert.equal(rarityForRoll(70), 'normal');
assert.equal(rarityForRoll(71), 'unique');
assert.equal(rarityForRoll(95), 'unique');
assert.equal(rarityForRoll(96), 'legend');
assert.equal(rarityForRoll(100), 'legend');
});
test('applyDamage: 방어 우선 차감 후 hp', () => {
assert.deepEqual(applyDamage(80, 0, 10), { hp: 70, block: 0 });
assert.deepEqual(applyDamage(80, 5, 10), { hp: 75, block: 0 });

View File

@@ -3999,9 +3999,20 @@ return pool`, [], 0, 'any'),
method('OfferReward', `self:SetEntityEnabled("/ui/DefaultGroup/CardHand", false)
self:SetEntityEnabled("/ui/DefaultGroup/DeckHud", false)
local pool = self:CardPool()
local byRarity = {}
for _, id in ipairs(pool) do
local r = self.Cards[id].rarity or "normal"
if byRarity[r] == nil then byRarity[r] = {} end
table.insert(byRarity[r], id)
end
self.RewardChoices = {}
for i = 1, 3 do
self.RewardChoices[i] = pool[math.random(1, #pool)]
local roll = math.random(1, 100)
local want = "normal"
if roll > 95 then want = "legend" elseif roll > 70 then want = "unique" end
local bucket = byRarity[want]
if bucket == nil or #bucket == 0 then bucket = pool end
self.RewardChoices[i] = bucket[math.random(1, #bucket)]
self:ApplyRewardVisual(i, self.RewardChoices[i])
end
local hud = _EntityService:GetEntityByPath("/ui/DefaultGroup/RewardHud")