mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-18 11:44:42 +02:00
big ass modding update
This commit is contained in:
+71
-29
@@ -1,45 +1,64 @@
|
||||
-- Gen 1 catch algorithm (engine/items/item_effects.asm, ItemUseBall).
|
||||
|
||||
local Status = require("src.battle.Status")
|
||||
|
||||
local Catching = {}
|
||||
|
||||
local BALL_RAND_MAX = { MASTER_BALL = 0, POKE_BALL = 255, GREAT_BALL = 200,
|
||||
ULTRA_BALL = 150, SAFARI_BALL = 150 }
|
||||
local BALL_HP_FACTOR = { POKE_BALL = 12, GREAT_BALL = 8, ULTRA_BALL = 12,
|
||||
SAFARI_BALL = 12 }
|
||||
-- randMax is the ceiling of the catch roll, hpFactor the X of the HP term,
|
||||
-- wobbleFactor the ballFactor2 divisor of the wobble math. MASTER_BALL
|
||||
-- never rolls (autoCatch), so its factors are unused. tossAnim picks the
|
||||
-- TossBallAnimation arc and flicker the Master/Ultra OBJ-palette strobe
|
||||
-- (DoBallTossSpecialEffects).
|
||||
local BALLS = {
|
||||
MASTER_BALL = { randMax = 0, autoCatch = true,
|
||||
tossAnim = "ULTRATOSS_ANIM", flicker = true },
|
||||
POKE_BALL = { randMax = 255, hpFactor = 12, wobbleFactor = 255,
|
||||
tossAnim = "TOSS_ANIM" },
|
||||
GREAT_BALL = { randMax = 200, hpFactor = 8, wobbleFactor = 200,
|
||||
tossAnim = "GREATTOSS_ANIM" },
|
||||
ULTRA_BALL = { randMax = 150, hpFactor = 12, wobbleFactor = 150,
|
||||
tossAnim = "ULTRATOSS_ANIM", flicker = true },
|
||||
SAFARI_BALL = { randMax = 150, hpFactor = 12, wobbleFactor = 150,
|
||||
tossAnim = "ULTRATOSS_ANIM" },
|
||||
}
|
||||
Catching.BALLS = BALLS
|
||||
|
||||
-- Returns caught, shakes (0-3). rateOverride replaces the species catch
|
||||
-- rate (the Safari game's BAIT/ROCK-modified wEnemyMonActualCatchRate).
|
||||
--
|
||||
-- On failure the ball wobbles per the original's shake calculation:
|
||||
-- Y = rate*100/ballFactor2 (255/200/150), Z = X*Y/255 + status2 (5/10)
|
||||
-- where X is the HP factor; Z<10: 0 shakes, <30: 1, <70: 2, else 3.
|
||||
-- (We use the HP factor for X on both failure paths; the original reads
|
||||
-- a stale quotient when the first roll fails.)
|
||||
function Catching.attempt(ball, targetMon, targetDef, rng, rateOverride)
|
||||
rng = rng or love.math.random
|
||||
if ball == "MASTER_BALL" then return true, 3 end
|
||||
local randMax = BALL_RAND_MAX[ball] or 255
|
||||
-- an unknown ball falls back to POKE_BALL's roll and the 150 wobble
|
||||
-- divisor, which is what the old per-field `or` defaults resolved to
|
||||
local DEFAULT_BALL = { randMax = 255, hpFactor = 12, wobbleFactor = 150 }
|
||||
|
||||
function Catching.registerInto(registry, _, owner)
|
||||
for id, record in pairs(BALLS) do
|
||||
registry:register(id, record, owner)
|
||||
end
|
||||
end
|
||||
|
||||
-- The stock ItemUseBall math. On failure the ball wobbles per the
|
||||
-- original's shake calculation: Y = rate*100/ballFactor2 (255/200/150),
|
||||
-- Z = X*Y/255 + status2 (5/10) where X is the HP factor; Z<10: 0 shakes,
|
||||
-- <30: 1, <70: 2, else 3. (We use the HP factor for X on both failure
|
||||
-- paths; the original reads a stale quotient when the first roll fails.)
|
||||
local function stockAttempt(def, targetMon, targetDef, rng, rateOverride, statuses)
|
||||
if def.autoCatch then return true, 3 end
|
||||
local randMax = def.randMax
|
||||
local rate = rateOverride or targetDef.catchRate
|
||||
|
||||
local statusBonus = 0
|
||||
-- the status subtraction and the wobble bonus come off the merged
|
||||
-- status record (SLP/FRZ 25 and +10, the rest 12 and +5)
|
||||
local s = targetMon.status
|
||||
if s == "SLP" or s == "FRZ" then
|
||||
statusBonus = 25
|
||||
elseif s == "PSN" or s == "BRN" or s == "PAR" then
|
||||
statusBonus = 12
|
||||
end
|
||||
local record = Status.recordFor(statuses, s)
|
||||
local statusBonus = record and record.catchBonus or 0
|
||||
|
||||
-- HP factor (X)
|
||||
local maxhp = targetMon.stats.hp
|
||||
local hpQuarter = math.max(1, math.floor(targetMon.hp / 4))
|
||||
local factor = BALL_HP_FACTOR[ball] or 12
|
||||
local factor = def.hpFactor or DEFAULT_BALL.hpFactor
|
||||
-- the 255 cap applies only after BOTH divisions (ItemUseBall keeps
|
||||
-- the intermediate in 16 bits); capping early collapses the value
|
||||
local f = math.min(255, math.floor(math.floor(maxhp * 255 / factor) / hpQuarter))
|
||||
|
||||
local function shakes()
|
||||
local ballFactor2 = ball == "POKE_BALL" and 255
|
||||
or ball == "GREAT_BALL" and 200 or 150
|
||||
local ballFactor2 = def.wobbleFactor or DEFAULT_BALL.wobbleFactor
|
||||
local y = math.floor(rate * 100 / ballFactor2)
|
||||
local z
|
||||
if y > 255 then
|
||||
@@ -47,10 +66,8 @@ function Catching.attempt(ball, targetMon, targetDef, rng, rateOverride)
|
||||
else
|
||||
z = math.floor(f * y / 255)
|
||||
end
|
||||
if s == "SLP" or s == "FRZ" then
|
||||
z = z + 10
|
||||
elseif s then
|
||||
z = z + 5
|
||||
if s then
|
||||
z = z + ((record and record.shakeBonus) or 5)
|
||||
end
|
||||
if z < 10 then return 0 elseif z < 30 then return 1
|
||||
elseif z < 70 then return 2 else return 3 end
|
||||
@@ -63,4 +80,29 @@ function Catching.attempt(ball, targetMon, targetDef, rng, rateOverride)
|
||||
return false, shakes()
|
||||
end
|
||||
|
||||
-- Returns caught, shakes (0-3). rateOverride replaces the species catch
|
||||
-- rate (the Safari game's BAIT/ROCK-modified wEnemyMonActualCatchRate).
|
||||
-- opts (all optional): ballDef = the merged ball record, statuses = the
|
||||
-- merged statuses table, battle = the running battle. A ball record's
|
||||
-- attempt fn supersedes the whole formula; its ctx.vanillaAttempt() runs
|
||||
-- the stock math with the ctx's (possibly rewritten) rateOverride.
|
||||
function Catching.attempt(ball, targetMon, targetDef, rng, rateOverride, opts)
|
||||
rng = rng or love.math.random
|
||||
opts = opts or {}
|
||||
local def = opts.ballDef or BALLS[ball] or DEFAULT_BALL
|
||||
local statuses = opts.statuses
|
||||
if def.attempt then
|
||||
local ctx = {
|
||||
ballDef = def, targetMon = targetMon, targetDef = targetDef,
|
||||
rng = rng, rateOverride = rateOverride, battle = opts.battle,
|
||||
}
|
||||
ctx.vanillaAttempt = function()
|
||||
return stockAttempt(def, targetMon, targetDef, rng, ctx.rateOverride,
|
||||
statuses)
|
||||
end
|
||||
return def.attempt(ctx)
|
||||
end
|
||||
return stockAttempt(def, targetMon, targetDef, rng, rateOverride, statuses)
|
||||
end
|
||||
|
||||
return Catching
|
||||
|
||||
Reference in New Issue
Block a user