addHook("MobjMoveBlocked", function(s)
if not (s and s.valid and ActiveMint(s)) return end
if (P_IsObjectOnGround(s) or s.eflags&MFE_JUSTHITFLOOR) return end

local p = s.player local s = p.mo
local mint = p.minttable
if not (p and p.valid) return end
if P_PlayerInPain(p) return end
if p.powers[pw_carry] return end
if p.actionstate return end
if p.spectator or p.bot or not mint.ledgechance return end

p.lastlinehit = -1
p.lastsidehit = -1
P_SlideMove(s)
p.powers[pw_pushing] = 3

local line = lines[p.lastlinehit]
if (line and line.valid)
if (line.flags&ML_IMPASSIBLE) return end

local wallangle = R_PointToAngle2(s.x, s.y, P_ClosestPointOnLine(s.x, s.y, line))
local gravitydirection = P_MobjFlip(s)
local playerradius = FixedMul(skins[p.skin].radius, s.scale)
local playerheight = FixedMul(skins[p.skin].height, s.scale)
local playerspinheight = FixedMul(skins[p.skin].spinheight, s.scale)
local playergrabrange = s.scale*87
local playergrabz
if (gravitydirection > 0)
playergrabz = s.z + s.height - (s.scale*10)
elseif (gravitydirection < 0)
playergrabz = s.z + (s.scale*10)
else
return
end

local linex, liney = P_ClosestPointOnLine(s.x, s.y, line)
local ledgex = linex + P_ReturnThrustX(nil, wallangle, playerradius)
local ledgey = liney + P_ReturnThrustY(nil, wallangle, playerradius)
local ledgez = s.z
local ledgeheight = s.scale*3
local floorz, ceilingz

if (gravitydirection > 0)
floorz = P_FloorzAtPos(ledgex, ledgey, ledgez, playerheight + ledgeheight)
ceilingz = P_CeilingzAtPos(ledgex, ledgey, ledgez, playerheight + ledgeheight)
elseif (gravitydirection < 0)
floorz = P_FloorzAtPos(ledgex, ledgey, ledgez, -ledgeheight)
ceilingz = P_CeilingzAtPos(ledgex, ledgey, ledgez, -ledgeheight)
else
return
end
if (floorz==ceilingz)
return
end
if (abs(floorz - ceilingz) <= playerspinheight)
or (gravitydirection > 0) and (abs(s.z + s.height + playerheight) >= s.ceilingz)
or (gravitydirection < 0) and (abs(s.z - playerheight) <= s.floorz)
or (gravitydirection==0)
return
end
local ledgegrabrange, ledgegrabz
if (gravitydirection > 0)
ledgegrabrange = (playergrabz < floorz) and (playergrabz > (floorz - playergrabrange))
ledgegrabz = floorz - playerheight
elseif (gravitydirection < 0)
ledgegrabrange = (playergrabz > ceilingz) and (playergrabz < (ceilingz + playergrabrange))
ledgegrabz = ceilingz
end
if (ledgegrabrange and ledgegrabz)
and ((s.momz*gravitydirection) < (s.scale*2))
and p.cmd.forwardmove
mint.ledgechance = $-1
P_InstaThrust(s, p.drawangle, 0*FU)
S_StartSound(s, sfx_mgrab)
S_StartSound(s, sfx_jump)
s.state = S_PLAY_MINTLEDGEGRAB
P_ResetPlayer(p)
FactoryReset(p,s,mint)
s.rollangle = 0
p.powers[pw_strong] = $&~ STR_SPRING
p.powers[pw_strong] = $&~ STR_BUST
p.pflags = $|PF_JUMPED
s.spritexscale = FU-28500
s.spriteyscale = FU+41000
mint.stretch = {timer = 15}
s.z = ledgegrabz
s.tics = 7
P_InstaThrust(s, wallangle, playerradius/4)
P_InstaThrust(s, p.drawangle, 0*FU)
s.momx,s.momy = 0,0
s.momz = max(-s.scale*2, min($, s.scale*2))
p.drawangle = wallangle
if mint.ledgechance
mint.ledgechance = $-1
end
if not (s.eflags&MFE_UNDERWATER)
P_SetObjectMomZ(s, 12*FU, false)
end
if (s.eflags&MFE_UNDERWATER)
P_SetObjectMomZ(s, 7*FU, false)
return true end;end;end
end, MT_PLAYER)
