balance: 전사 계열 5섹션 성장 곡선 조정
This commit is contained in:
@@ -6,7 +6,7 @@ const cardsData = JSON.parse(readFileSync('data/cards.json', 'utf8'));
|
||||
const enemiesData = JSON.parse(readFileSync('data/enemies.json', 'utf8'));
|
||||
const relicsData = JSON.parse(readFileSync('data/relics.json', 'utf8'));
|
||||
|
||||
const PLAYER_MAX_HP = 70;
|
||||
const PLAYER_MAX_HP = { rogue: 70, warrior: 80 };
|
||||
const REST_HEAL = 30;
|
||||
const SECTION_COUNT = 5;
|
||||
const NORMAL_FIGHTS = 4;
|
||||
@@ -18,6 +18,8 @@ const BOSS_POOL = ['king_slime', 'slime_boss'];
|
||||
const JOBS = {
|
||||
thief: { tier2: 'thief', tier3: 'thiefmaster', tier2Starter: 'DaggerAcceleration', tier3Starter: 'Venom' },
|
||||
assassin: { tier2: 'assassin', tier3: 'hermit', tier2Starter: 'JavelinAcceleration', tier3Starter: 'SpiritJavelin' },
|
||||
fighter: { root: 'warrior', tier2: 'fighter', tier3: 'crusader', tier2Starter: 'ComboAttack', tier3Starter: 'ComboSynergy' },
|
||||
page: { root: 'warrior', tier2: 'page', tier3: 'knight', tier2Starter: 'HolyCharge', tier3Starter: 'DivineCharge' },
|
||||
};
|
||||
|
||||
const LINEAGES = {
|
||||
@@ -26,12 +28,17 @@ const LINEAGES = {
|
||||
thiefmaster: ['rogue', 'thief', 'thiefmaster'],
|
||||
assassin: ['rogue', 'assassin'],
|
||||
hermit: ['rogue', 'assassin', 'hermit'],
|
||||
warrior: ['warrior'],
|
||||
fighter: ['warrior', 'fighter'],
|
||||
crusader: ['warrior', 'fighter', 'crusader'],
|
||||
page: ['warrior', 'page'],
|
||||
knight: ['warrior', 'page', 'knight'],
|
||||
};
|
||||
|
||||
const pick = (rng, values) => values[Math.floor(rng() * values.length)];
|
||||
|
||||
export function campaignJobAtSection(branch, section) {
|
||||
if (section <= 1) return 'rogue';
|
||||
if (section <= 1) return JOBS[branch].root || 'rogue';
|
||||
if (section === 2) return JOBS[branch].tier2;
|
||||
return JOBS[branch].tier3;
|
||||
}
|
||||
@@ -102,11 +109,22 @@ function branchCardValue(card, branch, deck, id) {
|
||||
value += card.sly ? 5 : 0;
|
||||
value += (card.discard || 0) * 2 + (card.drawPerDiscarded || 0) * 4;
|
||||
value += (card.poisonApplicationBurstDamage || 0) * 1.5;
|
||||
} else {
|
||||
} else if (branch === 'assassin') {
|
||||
value += (card.addShiv || 0) * 3 + (card.turnStartShiv || 0) * 8;
|
||||
value += (card.shivDamageBonus || 0) * 6 + (card.firstShivDamageBonus || 0) * 3;
|
||||
value += card.shivAoe ? 12 : 0;
|
||||
value += card.shivRetain ? 5 : 0;
|
||||
} else if (branch === 'fighter') {
|
||||
value += (card.hits || 1) * 1.5;
|
||||
value += (card.comboGain || 0) * 5 + (card.comboOnAttack || 0) * 10;
|
||||
value += (card.damagePerCombo || 0) * 8 + (card.attackDamagePerCombo || 0) * 12;
|
||||
value += (card.attackPlayedDamage || 0) * 5;
|
||||
} else if (branch === 'page') {
|
||||
value += (card.block || 0) * 0.5 + (card.cardPlayedBlock || 0) * 7;
|
||||
value += (card.holyChargeOnHolyForce || 0) * 12 + (card.damagePerHolyCharge || 0) * 7;
|
||||
value += (card.blockPerHolyCharge || 0) * 6 + (card.healPerHolyCharge || 0) * 3;
|
||||
value += (card.damageTakenReduction || 0) * 40;
|
||||
value += (card.blockOnDamaged || 0) * 3 + (card.strengthOnDamagedOnce || 0) * 5;
|
||||
}
|
||||
const copies = deck.filter((cardId) => cardId === id).length;
|
||||
value -= copies * (card.kind === 'Power' ? 10 : 3);
|
||||
@@ -203,11 +221,13 @@ export function simulateCampaign(branch, rng, {
|
||||
minimumRewardValue = 10,
|
||||
} = {}) {
|
||||
if (!JOBS[branch]) throw new Error(`지원하지 않는 도적 분기: ${branch}`);
|
||||
const root = JOBS[branch].root || 'rogue';
|
||||
const maxHp = PLAYER_MAX_HP[root];
|
||||
const state = {
|
||||
hp: PLAYER_MAX_HP,
|
||||
maxHp: PLAYER_MAX_HP,
|
||||
deck: cardsData.starterDecks.rogue.slice(),
|
||||
job: 'rogue',
|
||||
hp: maxHp,
|
||||
maxHp,
|
||||
deck: cardsData.starterDecks[root].slice(),
|
||||
job: root,
|
||||
turns: 0,
|
||||
sectionCleared: 0,
|
||||
diedAt: '',
|
||||
@@ -306,7 +326,7 @@ function main() {
|
||||
else if (args[i] === '--scale-step') scaleStep = Number.parseFloat(args[++i]);
|
||||
else if (args[i] === '--reward-min') minimumRewardValue = Number.parseFloat(args[++i]);
|
||||
}
|
||||
for (const branch of ['thief', 'assassin']) {
|
||||
for (const branch of ['thief', 'assassin', 'fighter', 'page']) {
|
||||
console.log(formatCampaignReport(runCampaignBatch(branch, runs, seed, { restHeal, sectionHeal, scaleStep, minimumRewardValue })));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user