|
|
@ -54,13 +54,32 @@ const getMonsterIcon = (iconName?: string) => { |
|
|
return `/src/assets/images/monster/${iconName}` |
|
|
return `/src/assets/images/monster/${iconName}` |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const calculateDamage = (attack: number, defend: number, criticalRate: number): { damage: number; isCritical: boolean } => { |
|
|
const defaultCriticalDamageBonusPercent = 50 |
|
|
const baseDamage = Math.max(1, attack - defend) |
|
|
|
|
|
|
|
|
const resolveCriticalDamageBonusPercent = (baseBonus: number, equipmentBonus: number) => { |
|
|
|
|
|
const sum = (baseBonus || 0) + (equipmentBonus || 0) |
|
|
|
|
|
return sum > 0 ? sum : defaultCriticalDamageBonusPercent |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** 与后端 CombatAttributeFormula / BattleService 一致:基础伤害 attack²/(attack+defend),暴击倍率 1+暴击伤害%/100 */ |
|
|
|
|
|
const calculateDamage = ( |
|
|
|
|
|
attack: number, |
|
|
|
|
|
defend: number, |
|
|
|
|
|
criticalRate: number, |
|
|
|
|
|
criticalDamageBonusPercent: number |
|
|
|
|
|
): { damage: number; isCritical: boolean } => { |
|
|
|
|
|
const a = Math.max(0, attack) |
|
|
|
|
|
const d = Math.max(0, defend) |
|
|
|
|
|
const baseDamage = a <= 0 ? 1 : Math.max(1, Math.floor((a * a) / (a + d))) |
|
|
const random = Math.random() |
|
|
const random = Math.random() |
|
|
const isCritical = random < criticalRate / 100 |
|
|
const isCritical = random < criticalRate / 100 |
|
|
const damage = isCritical ? Math.floor(baseDamage * 1.5) : baseDamage |
|
|
const critMult = 1 + criticalDamageBonusPercent / 100 |
|
|
|
|
|
let working = baseDamage |
|
|
|
|
|
if (isCritical) { |
|
|
|
|
|
working = Math.floor(working * critMult) |
|
|
|
|
|
} |
|
|
const variance = (90 + Math.floor(Math.random() * 21)) / 100 |
|
|
const variance = (90 + Math.floor(Math.random() * 21)) / 100 |
|
|
return { damage: Math.floor(damage * variance), isCritical } |
|
|
return { damage: Math.max(1, Math.floor(working * variance)), isCritical } |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const startBattle = async () => { |
|
|
const startBattle = async () => { |
|
|
@ -82,8 +101,16 @@ const startBattle = async () => { |
|
|
const playerAttack = currentCharacter.value.attack |
|
|
const playerAttack = currentCharacter.value.attack |
|
|
const playerDefend = currentCharacter.value.defend |
|
|
const playerDefend = currentCharacter.value.defend |
|
|
const playerCriticalRate = currentCharacter.value.criticalRate |
|
|
const playerCriticalRate = currentCharacter.value.criticalRate |
|
|
|
|
|
const playerCritDamagePct = resolveCriticalDamageBonusPercent( |
|
|
|
|
|
currentCharacter.value.baseCriticalDamage, |
|
|
|
|
|
currentCharacter.value.bonusCriticalDamage |
|
|
|
|
|
) |
|
|
const monsterAttack = currentMonster.value.attack |
|
|
const monsterAttack = currentMonster.value.attack |
|
|
const monsterDefend = currentMonster.value.defense |
|
|
const monsterDefend = currentMonster.value.defense |
|
|
|
|
|
const monsterCritDamagePct = resolveCriticalDamageBonusPercent( |
|
|
|
|
|
currentMonster.value.baseCriticalDamage ?? 0, |
|
|
|
|
|
currentMonster.value.bonusCriticalDamage ?? 0 |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
let round = 0 |
|
|
let round = 0 |
|
|
const maxRounds = 100 |
|
|
const maxRounds = 100 |
|
|
@ -94,7 +121,7 @@ const startBattle = async () => { |
|
|
round++ |
|
|
round++ |
|
|
|
|
|
|
|
|
// 玩家攻击 |
|
|
// 玩家攻击 |
|
|
const playerResult = calculateDamage(playerAttack, monsterDefend, playerCriticalRate) |
|
|
const playerResult = calculateDamage(playerAttack, monsterDefend, playerCriticalRate, playerCritDamagePct) |
|
|
monsterHealth.value = Math.max(0, monsterHealth.value - playerResult.damage) |
|
|
monsterHealth.value = Math.max(0, monsterHealth.value - playerResult.damage) |
|
|
battleLog.value.push({ |
|
|
battleLog.value.push({ |
|
|
round, |
|
|
round, |
|
|
@ -109,7 +136,7 @@ const startBattle = async () => { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 怪物攻击 |
|
|
// 怪物攻击 |
|
|
const monsterResult = calculateDamage(monsterAttack, playerDefend, currentMonster.value.criticalRate) |
|
|
const monsterResult = calculateDamage(monsterAttack, playerDefend, currentMonster.value.criticalRate, monsterCritDamagePct) |
|
|
playerHealth.value = Math.max(0, playerHealth.value - monsterResult.damage) |
|
|
playerHealth.value = Math.max(0, playerHealth.value - monsterResult.damage) |
|
|
battleLog.value.push({ |
|
|
battleLog.value.push({ |
|
|
round, |
|
|
round, |
|
|
|