mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-15 15:51:17 +02:00
108 lines
4.2 KiB
Lua
108 lines
4.2 KiB
Lua
-- Experience gain (engine/battle/experience.asm):
|
|
-- exp = floor(baseExp * enemyLevel / 7) for a single participant
|
|
-- (trainer battles multiply by 1.5 in Gen 1)
|
|
-- Stat experience: the defeated species' base stats are added to each
|
|
-- participant's stat exp.
|
|
|
|
local Growth = require("src.pokemon.Growth")
|
|
local Runtime = require("src.mods.Runtime")
|
|
local Stats = require("src.pokemon.Stats")
|
|
|
|
local Experience = {}
|
|
|
|
-- engine/battle/experience.asm order: baseExp is divided by the
|
|
-- participant count FIRST, then *level/7, then the traded x1.5
|
|
-- (BoostExp) and finally the trainer x1.5.
|
|
--
|
|
-- EXP.ALL (core.asm .halveExpDataLoop): the base values are halved,
|
|
-- GainExperience runs for the participants, then reruns for the whole
|
|
-- party -- and because DivideExpDataByNumMonsGainingExp divides the
|
|
-- base values IN PLACE, the second pass inherits the participant
|
|
-- division: each party member gets (base/2)/participants/partyCount.
|
|
-- Sequential floor divisions equal one floor division by the product,
|
|
-- so callers pass numParticipants = 2*participants for the first pass
|
|
-- and 2*participants*partyCount for the whole-party pass.
|
|
--
|
|
-- consts is Data.constants; a constants.exp record can retune the
|
|
-- divisor and the traded/trainer multipliers, with the values above as
|
|
-- the defaults.
|
|
function Experience.gainFor(defeatedDef, level, isTrainer, numParticipants,
|
|
traded, consts)
|
|
local divisor, tradedMult, trainerMult = 7, nil, nil
|
|
local tuning = consts and consts.exp
|
|
if tuning then
|
|
divisor = tuning.divisor or divisor
|
|
tradedMult = tuning.tradedMult
|
|
trainerMult = tuning.trainerMult
|
|
end
|
|
local base = math.floor(defeatedDef.baseExp / math.max(1, numParticipants or 1))
|
|
local exp = math.floor(base * level / divisor)
|
|
if traded then
|
|
exp = math.floor(exp * (tradedMult or 1.5))
|
|
end
|
|
if isTrainer then
|
|
exp = math.floor(exp * (trainerMult or 1.5))
|
|
end
|
|
return math.max(1, exp)
|
|
end
|
|
|
|
-- Applies exp/stat exp; returns the list of levels gained plus the raw
|
|
-- exp delta (wExpAmountGained, printed by _ExpPointsText -- captured
|
|
-- before the max-level cap, experience.asm:92-100).
|
|
function Experience.apply(data, mon, defeatedDef, level, isTrainer,
|
|
numParticipants, traded)
|
|
local speciesDef = data.pokemon[mon.species]
|
|
-- stat exp is divided among participants too
|
|
-- (DivideExpDataByNumMonsGainingExp divides wEnemyMonBaseStats)
|
|
local statShare = math.max(1, numParticipants or 1)
|
|
for _, key in ipairs(Stats.ORDER) do
|
|
local gain = math.floor(defeatedDef.baseStats[key] / statShare)
|
|
mon.statExp[key] = math.min(65535, (mon.statExp[key] or 0) + gain)
|
|
end
|
|
local consts = data.constants
|
|
local gained
|
|
if Runtime.wantsHook("exp.gain") then
|
|
gained = Runtime.call("exp.gain", function(c)
|
|
return Experience.gainFor(c.defeatedDef, c.level, c.isTrainer,
|
|
c.participants, c.traded, consts)
|
|
end, { defeatedDef = defeatedDef, level = level, isTrainer = isTrainer,
|
|
participants = numParticipants, traded = traded, mon = mon })
|
|
else
|
|
gained = Experience.gainFor(defeatedDef, level, isTrainer,
|
|
numParticipants, traded, consts)
|
|
end
|
|
mon.exp = mon.exp + gained
|
|
|
|
local cap = consts and consts.levelCap or 100
|
|
local levels = {}
|
|
local newLevel = Growth.levelForExp(speciesDef.growthRate, mon.exp, cap,
|
|
data.growth_rates)
|
|
while mon.level < math.min(newLevel, cap) do
|
|
mon.level = mon.level + 1
|
|
local old = mon.stats
|
|
mon.stats = Stats.calc(speciesDef, mon.level, mon.dvs, mon.statExp)
|
|
mon.hp = math.min(mon.stats.hp, mon.hp + (mon.stats.hp - old.hp))
|
|
table.insert(levels, mon.level)
|
|
if Runtime.wants("pokemon.level_up") then
|
|
Runtime.emit("pokemon.level_up", {
|
|
mon = mon, level = mon.level, prevLevel = mon.level - 1,
|
|
learnable = Experience.movesLearnedAt(speciesDef, mon.level),
|
|
})
|
|
end
|
|
end
|
|
return levels, gained
|
|
end
|
|
|
|
-- Moves learned when reaching exactly `level`.
|
|
function Experience.movesLearnedAt(speciesDef, level)
|
|
local out = {}
|
|
for _, entry in ipairs(speciesDef.learnset) do
|
|
if entry.level == level then
|
|
table.insert(out, entry.move)
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
|
|
return Experience
|