Skip to content

Commit be64db7

Browse files
fix: 修正战斗结算的 XP 和 EV 计算
- XP 公式改为使用真实 baseExperience(从 PokeAPI),而非 baseStats.hp - EV yield 改为使用真实数据(getPokedexEvYield),而非伪造的映射 - 进化检测改为遍历所有 evos 目标,支持分支进化 - 新增友谊度进化检测(friendship >= 220) - 解决 #1 XP 公式错误、#2 EV 伪造、#8 进化只取第一个目标 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 6fc365c commit be64db7

1 file changed

Lines changed: 30 additions & 32 deletions

File tree

packages/pokemon/src/battle/settlement.ts

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { levelFromXp } from '../dex/xpTable'
77
import { getSpeciesData } from '../dex/species'
88
import { MAX_EV_PER_STAT, MAX_EV_TOTAL } from '../dex/evMapping'
99
import { Dex } from '@pkmn/sim'
10+
import { getBaseExperience, getEvYield as getPokedexEvYield } from '../dex/pokedex-data'
1011

1112
/**
1213
* Settle battle results: XP, EV, level ups, move learning, evolution detection.
@@ -25,14 +26,13 @@ export async function settleBattle(
2526
return { data, learnableMoves: [], pendingEvolutions: [] }
2627
}
2728

28-
// Calculate XP reward (simplified: base XP from species)
29-
const oppSpecies = Dex.species.get(opponentSpeciesId)
30-
const baseXp = (oppSpecies?.baseStats?.hp ?? 50) * opponentLevel / 7
31-
const xpGained = Math.max(1, Math.floor(baseXp))
29+
// Calculate XP reward using real base_experience from PokeAPI
30+
const baseXp = getBaseExperience(opponentSpeciesId)
31+
const xpGained = Math.max(1, Math.floor(baseXp * opponentLevel / 7))
3232

33-
// Calculate EV reward
33+
// Calculate EV reward using real EV yield from PokeAPI
3434
const evGained: Record<StatName, number> = { hp: 0, attack: 0, defense: 0, spAtk: 0, spDef: 0, speed: 0 }
35-
const evYield = getEvYield(opponentSpeciesId)
35+
const evYield = getPokedexEvYield(opponentSpeciesId)
3636
for (const stat of STAT_NAMES) {
3737
evGained[stat] = evYield[TO_DEX_STAT[stat]] ?? 0
3838
}
@@ -88,18 +88,33 @@ export async function settleBattle(
8888
}
8989
}
9090

91-
// Detect evolution
91+
// Detect evolution — check ALL evolution targets (handles branch evolutions)
9292
if (newLevel > oldLevel) {
9393
const species = Dex.species.get(creature.speciesId)
9494
if (species?.evos?.length) {
95-
const targetId = species.evos[0]!.toLowerCase()
96-
const target = Dex.species.get(targetId)
97-
if (target?.evoLevel && newLevel >= target.evoLevel) {
98-
pendingEvolutions.push({
99-
creatureId: creature.id,
100-
from: creature.speciesId,
101-
to: targetId as SpeciesId,
102-
})
95+
for (const evoId of species.evos) {
96+
const targetId = evoId.toLowerCase()
97+
const target = Dex.species.get(targetId)
98+
if (!target?.exists) continue
99+
const trigger = species.evoType
100+
// Level-up evolutions
101+
if ((!trigger || trigger === 'levelUp') && target.evoLevel && newLevel >= target.evoLevel) {
102+
pendingEvolutions.push({
103+
creatureId: creature.id,
104+
from: creature.speciesId,
105+
to: targetId as SpeciesId,
106+
})
107+
break // Only evolve into one target per level-up
108+
}
109+
// Friendship evolutions (friendship >= 220)
110+
if (trigger === 'levelFriendship' && creature.friendship >= 220) {
111+
pendingEvolutions.push({
112+
creatureId: creature.id,
113+
from: creature.speciesId,
114+
to: targetId as SpeciesId,
115+
})
116+
break
117+
}
103118
}
104119
}
105120
}
@@ -172,20 +187,3 @@ export function applyEvolution(
172187
},
173188
}
174189
}
175-
176-
function getEvYield(speciesId: string): Record<string, number> {
177-
// @pkmn/sim Dex.species doesn't have evs field
178-
// Use baseStats as proxy: highest base stat gets 1-2 EVs
179-
const species = Dex.species.get(speciesId)
180-
if (!species?.baseStats) return {}
181-
const stats = species.baseStats as Record<string, number>
182-
const entries = Object.entries(stats)
183-
if (entries.length === 0) return {}
184-
// Sort by value descending, give 1-2 EV to top stats
185-
entries.sort((a, b) => b[1] - a[1])
186-
const result: Record<string, number> = {}
187-
// Top stat gets 2 EVs, second gets 1
188-
if (entries[0]) result[entries[0][0]] = 2
189-
if (entries[1]) result[entries[1][0]] = 1
190-
return result
191-
}

0 commit comments

Comments
 (0)