// --------------------------------------
// Lua_Sleep
// Sleep ability!
// --------------------------------------
local sleepytime = (TICRATE*6)+TICRATE/2

rawset(_G, "K_Sleep", function(checkflags, destroy, late, player)
	if(checkflags)
		return AF_NOFLOAT|AF_NODUCK|AF_NOJUMP|AF_NOSWIM|AF_NODROP
	end
	if(destroy)
//		player.pflags = $1 & !PF_FORCESTRAFE
		return
	end
	if(late)
		return
	end
	
	if not(player.mo.state == S_KIRBY_CONSUME)
		if(player.kvars.ablstate == 0)
			player.mo.state = S_KIRBY_SLEEP1	// Zzzzzzzz
		elseif not(player.mo.state >= S_KIRBY_SLEEP1 and player.mo.state <= S_KIRBY_SLEEP11)
			player.mo.state = S_KIRBY_SLEEP6
		end
		
		player.kvars.ablstate = $1 + 1
		
		if(player.kvars.ablstate >= sleepytime)
			or(P_PlayerInPain(player))
			or(player.kvars.industdevil)
			player.kvars.ability = 0	// Sleep time over
			player.kvars.ablstate = 0
			S_StartSound(player.mo, sfx_kwkeup)
			player.mo.momz = 5*player.mo.scale*P_MobjFlip(player.mo)
			player.mo.state = S_PLAY_PAIN
//			player.pflags = $1 & !PF_FORCESTRAFE	// If you're not constantly forcing this then... something :ohh_yeah:
		else
//			player.pflags = $1|PF_FORCESTRAFE
			player.mo.momx = player.cmomx		// Can't move at all
			player.mo.momy = player.cmomy		// Still can't move at all
			if not(player.powers[pw_nocontrol])
				player.powers[pw_nocontrol] = 1	// No control
			end
			if(player.mo.state == S_KIRBY_SLEEP6)
				and not(player.kvars.ablvar1 == S_KIRBY_SLEEP6)
				S_StartSound(player.mo, sfx_ksleep)
			end
		end
		
		player.kvars.ablvar1 = player.mo.state
	end
end)

// Secret abilities!

// --------------------------------------
// Lua_QPShu
// QP Shu~ ability!
// --------------------------------------

// Sparkles
local sparklecolors = {}
sparklecolors[0] = SKINCOLOR_PINK
sparklecolors[1] = SKINCOLOR_MOSS
sparklecolors[2] = SKINCOLOR_AZURE

local function RandomOff(num)
	return (P_RandomByte()%num)-(num/2)
end
local function SpawnSparkles(mobj, spriteheight)
	local zoff = -3*mobj.scale*P_MobjFlip(mobj)
	local offx = (RandomOff(20)*mobj.scale*2)
	local offy = (RandomOff(20)*mobj.scale*2)
	local offz = (mobj.height/2)+(RandomOff(spriteheight)*mobj.scale*2)+zoff
	local sparkle = P_SpawnMobj(mobj.x+offx, mobj.y+offy, mobj.z+offz, MT_BALLSPARKLE)
	sparkle.scale = mobj.scale
	if(mobj.eflags & MFE_VERTICALFLIP)
		sparkle.eflags = $1|MFE_VERTICALFLIP
	end
	sparkle.color = sparklecolors[P_RandomByte()%3]
	sparkle.target = mobj
	sparkle.offx = offx
	sparkle.offy = offy
	sparkle.offz = offz
end

local qpshutime = TICRATE*48

local chargetime = TICRATE
local bittime = TICRATE/10
rawset(_G, "K_QPShu", function(checkflags, destroy, late, player)
	if(checkflags)
		if(player.kvars.ablstate or player.kvars.ablvar1 or player.kvars.ablvar3)
			return AF_NOFLOAT|AF_NODUCK|AF_NOSWIM|AF_NODROP
		end
		return 0
	end
	if(destroy)
		if(player.kirbyrbit and player.kirbyrbit.valid)
			P_RemoveMobj(player.kirbyrbit)
		end
		if(player.kirbyextrabits)
			local bnum = 0
			while(player.kirbyextrabits[bnum] and player.kirbyextrabits[bnum].valid)
				P_RemoveMobj(player.kirbyextrabits[bnum])
				player.kirbyextrabits[bnum] = nil
				bnum = $1 + 1
			end
		end
		player.kirbyrbit = nil
		if(player.mo.state == S_KIRBY_BHOLD or (player.mo.state >= S_KIRBY_BTHROW1 and player.mo.state <= S_KIRBY_BTHROW2))
			player.mo.state = S_PLAY_STND
		elseif(player.mo.state >= S_KIRBY_BWALK1 and player.mo.state <= S_KIRBY_BWALK8)
			player.mo.state = S_PLAY_WALK
		end
		return
	end
	if(late)
		return
	end
	
	// Music!
	if not(player.kvars.abljingletime)
		player.kvars.abljingletime = 1
		S_ChangeMusic("QPSHU", false, player)
		S_StartMusicCaption("Lucky Star", qpshutime, player)
	elseif(player.kvars.abljingletime < qpshutime)
		player.kvars.abljingletime = $1 + 1
		if(player.kvars.abljingletime == qpshutime)
			P_RestoreMusic(player)
		end
	end
	
	if(player.mo.state >= S_PLAY_STND and player.mo.state <= S_PLAY_DASH)
		or(player.mo.state == S_PLAY_ROLL)
		or(player.mo.state >= S_PLAY_JUMP and player.mo.state <= S_PLAY_FALL)
		or(player.mo.state >= S_KIRBY_BHOLD and player.mo.state <= S_KIRBY_BTHROW2)
		or(player.kvars.ablstate)
		if not(P_IsObjectOnGround(player.mo))
			and not(player.mo.eflags & MFE_UNDERWATER)
			player.mo.state = S_KIRBY_BWALK7
		elseif(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy))
			if not(player.mo.state >= S_KIRBY_BWALK1 and player.mo.state <= S_KIRBY_BWALK8)
				player.mo.state = S_KIRBY_BWALK1
			end
			
			// Animation speed
			if(player.mo.eflags & MFE_UNDERWATER)
				and not(P_IsObjectOnGround(player.mo))
				if(player.mo.tics > 2)
					player.mo.tics = 2
				end
			else
				if(player.skidtime)	// Last time I touched this, it caused desyncs. Hopefully that doesn't happen again!
					player.mo.state = S_KIRBY_BWALK7
				else
					local speed = FixedDiv(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy), player.mo.scale)
					local maxtics = 4
					if(speed >= player.runspeed)	// Normally 30*FRACUNIT
						maxtics = 1
					elseif(speed >= 20*FRACUNIT)
						maxtics = 2
					elseif(speed >= 10*FRACUNIT)
						maxtics = 3
					end
					if(player.mo.tics > maxtics)
						player.mo.tics = maxtics
					end
				end
			end
		else
			player.mo.state = S_KIRBY_BHOLD
		end
	end
	
	if not(player.kvars.ducking)
		and not(player.kvars.floating)
		and not(player.pflags & PF_SLIDING)
		and not(player.powers[pw_carry] or player.kvars.prevcarry)
		and not(player.exiting)
		and not(player.pflags & PF_STASIS)
		and not(player.powers[pw_nocontrol])
		and not(player.kvars.industdevil)
		and not(player.kvars.ablvar3)
		if(player.cmd.buttons & BT_USE)
			and not(player.kvars.prevcmd & BT_USE)
			player.kvars.ablstate = 1
		end
	else
		player.kvars.ablstate = 0
	end
	
	if(player.kvars.ablstate)
		if(player.cmd.buttons & BT_USE)
			player.kvars.ablstate = $1 + 1
			// Charged!
			if(player.kvars.ablstate == chargetime)
				S_StartSound(player.mo, sfx_rbit)
			end
		else
			if(player.kvars.ablstate >= chargetime)
				S_StartSound(playermo, sfx_brifle)
				local shot = P_SPMAngle(player.mo, MT_KIRBYBITSHOT, player.mo.angle, 0)
				if(shot and shot.valid)
					shot.colorized = true
					shot.color = SKINCOLOR_MINT
				end
				player.kvars.ablvar3 = 1
			elseif not(player.kvars.ablvar1)
				player.kvars.ablvar1 = 1
			else
				player.kvars.ablvar1 = (($1-1)%bittime)+1
				player.kvars.ablvar2 = 1
			end
			player.kvars.ablstate = 0
		end
	end
	
	if(player.kvars.ablvar1)
		player.drawangle = player.mo.angle
		if((player.kvars.ablvar1+1)%bittime == 0)
			S_StartSound(player.mo, sfx_bshoot)
			local shot = P_SPMAngle(player.mo, MT_KIRBYBITSHOT, player.mo.angle, 0)
			if(shot and shot.valid)
				shot.colorized = true
				shot.color = SKINCOLOR_MINT
				if(player.mo.eflags & MFE_VERTICALFLIP)
					shot.eflags = $1|MFE_VERTICALFLIP
					shot.flags2 = $1|MF2_OBJECTFLIP
				end
			end
		end
		player.kvars.ablvar1 = $1 + 1
		if(player.kvars.ablvar1 > bittime*3)
			if(player.kvars.ablvar2)
				player.kvars.ablvar2 = 0
				player.kvars.ablvar1 = 1
			else
				player.kvars.ablvar1 = 0
			end
		end
	end
	
	if(player.kvars.ablvar3)
		player.drawangle = player.mo.angle
		player.kvars.ablvar3 = $1 + 1
		if(player.kvars.ablvar3 > bittime*3)
			player.kvars.ablvar3 = 0
		end
	end
	
	local hoff = player.mo.height
	local doff = 0
	if(player.mo.eflags & MFE_VERTICALFLIP)
		hoff = FixedMul(player.mo.scale, mobjinfo[MT_KIRBYUSABIT].height)
	end
	if(player.kvars.ablstate)
		or(player.kvars.ablvar1)
		or(player.kvars.ablvar3)
		hoff = $1-(19*player.mo.scale)
		doff = 25*player.mo.scale
	elseif(player.mo.state >= S_KIRBY_FLOATSTART and player.mo.state <= S_KIRBY_FLOATTIRE)
		hoff = $1+(18*player.mo.scale)
		if(frame == 1 or frame == 2)
			hoff = $1-(1*player.mo.scale)
		elseif(frame == 3)
			hoff = $1-(2*player.mo.scale)
		end
	elseif(player.mo.sprite2 == SPR2_SPNG)
		hoff = $1+(8*player.mo.scale)
	else
		hoff = $1+(6*player.mo.scale)
	end
	
	local xoff = FixedMul(cos(player.drawangle), doff)
	local yoff = FixedMul(sin(player.drawangle), doff)
	if not(player.kirbyrbit and player.kirbyrbit.valid)
		player.kirbyrbit = P_SpawnMobj(player.mo.x+xoff, player.mo.y+yoff, player.mo.z+(hoff*P_MobjFlip(player.mo)), MT_KIRBYUSABIT)
	end
	player.kirbyrbit.angle = player.drawangle
	player.kirbyrbit.scale = player.mo.scale
	P_TeleportMove(player.kirbyrbit, player.mo.x+xoff, player.mo.y+yoff, player.mo.z+(hoff*P_MobjFlip(player.mo)))
	if(player.mo.eflags & MFE_VERTICALFLIP)
		player.kirbyrbit.eflags = $1|MFE_VERTICALFLIP
		player.kirbyrbit.flags2 = $1|MF2_OBJECTFLIP
	else
		player.kirbyrbit.eflags = $1 & !MFE_VERTICALFLIP
		player.kirbyrbit.flags2 = $1 & !MF2_OBJECTFLIP
	end
	
	// Extra bits
	if(player.kirbyextrabits == nil)
		player.kirbyextrabits = {}
	end
	local angle = FixedAngle(30*FRACUNIT)
	local shangle = FixedAngle(10*FRACUNIT)
	local bnum = 0
	while(bnum < 6)
		doff = 40*player.mo.scale
		local bangle = (angle*bnum)-(angle*3)
		if(bnum >= 3)
			bangle = $1 + angle
		end
		local sangle = (shangle*bnum)-(shangle*3)
		if(bnum >= 3)
			sangle = $1 + shangle
		end
		xoff = FixedMul(cos(player.drawangle+bangle), doff)
		yoff = FixedMul(sin(player.drawangle+bangle), doff)
		if not(player.kirbyextrabits[bnum] and player.kirbyextrabits[bnum].valid)
			player.kirbyextrabits[bnum] = P_SpawnMobj(player.mo.x+xoff, player.mo.y+yoff, player.mo.z+(player.mo.height/2), MT_KIRBYUSABIT)
			player.kirbyextrabits[bnum].flags2 = $1|MF2_DONTDRAW
		end
		player.kirbyextrabits[bnum].scale = player.mo.scale/2
		player.kirbyextrabits[bnum].angle = player.drawangle+bangle
		local zoff = 0
		if(player.mo.eflags & MFE_VERTICALFLIP)
			zoff = -player.kirbyextrabits[bnum].height
		end
		P_TeleportMove(player.kirbyextrabits[bnum], player.mo.x+xoff, player.mo.y+yoff, player.mo.z+(player.mo.height/2)+zoff)
		
		// Draw?
		if(player.kvars.ablstate >= chargetime)
			or(player.kvars.ablvar3)
			if(player.kirbyextrabits[bnum].flags2 & MF2_DONTDRAW)
				local snum = 0
				while(snum < 5)
					SpawnSparkles(player.kirbyextrabits[bnum], 15)
					snum = $1 + 1
				end
				player.kirbyextrabits[bnum].frame = $1|FF_TRANS50
			else
				player.kirbyextrabits[bnum].frame = $1 & !FF_TRANS50
			end
			player.kirbyextrabits[bnum].flags2 = $1 & !MF2_DONTDRAW
			
			if(player.mo.eflags & MFE_VERTICALFLIP)
				player.kirbyextrabits[bnum].eflags = $1|MFE_VERTICALFLIP
				player.kirbyextrabits[bnum].flags2 = $1|MF2_OBJECTFLIP
			else
				player.kirbyextrabits[bnum].eflags = $1 & !MFE_VERTICALFLIP
				player.kirbyextrabits[bnum].flags2 = $1 & !MF2_OBJECTFLIP
			end
		else
			if not(player.kirbyextrabits[bnum].flags2 & MF2_DONTDRAW)
				local snum = 0
				while(snum < 5)
					SpawnSparkles(player.kirbyextrabits[bnum], 15)
					snum = $1 + 1
				end
			end
			player.kirbyextrabits[bnum].flags2 = $1|MF2_DONTDRAW
		end
		
		// Shoot!
		if(player.kvars.ablvar3 == 2)
			local shot1 = P_SPMAngle(player.mo, MT_KIRBYBITSHOT, player.drawangle+sangle+FixedAngle(3*FRACUNIT), 0)
			if(shot1 and shot1.valid)
				shot1.colorized = true
				shot1.color = SKINCOLOR_MINT
				if(player.mo.eflags & MFE_VERTICALFLIP)
					shot1.eflags = $1|MFE_VERTICALFLIP
					shot1.flags2 = $1|MF2_OBJECTFLIP
					P_TeleportMove(shot1, player.kirbyextrabits[bnum].x, player.kirbyextrabits[bnum].y, player.kirbyextrabits[bnum].z+player.kirbyextrabits[bnum].height-shot1.height)
				else
					P_TeleportMove(shot1, player.kirbyextrabits[bnum].x, player.kirbyextrabits[bnum].y, player.kirbyextrabits[bnum].z)
				end
			end
			local shot2 = P_SPMAngle(player.mo, MT_KIRBYBITSHOT, player.drawangle+sangle-FixedAngle(3*FRACUNIT), 0)
			if(shot2 and shot2.valid)
				shot2.colorized = true
				shot2.color = SKINCOLOR_MINT
				if(player.mo.eflags & MFE_VERTICALFLIP)
					shot2.eflags = $1|MFE_VERTICALFLIP
					shot2.flags2 = $1|MF2_OBJECTFLIP
					P_TeleportMove(shot2, player.kirbyextrabits[bnum].x, player.kirbyextrabits[bnum].y, player.kirbyextrabits[bnum].z+player.kirbyextrabits[bnum].height-shot1.height)
				else
					P_TeleportMove(shot2, player.kirbyextrabits[bnum].x, player.kirbyextrabits[bnum].y, player.kirbyextrabits[bnum].z)
				end
			end
		end
		
		bnum = $1 + 1
	end
end)

addHook("MobjThinker", function(mobj)
	local ghost = P_SpawnGhostMobj(mobj)
	ghost.tics = 3
end, MT_KIRBYBITSHOT)

// --------------------------------------
// Lua_Suguri
// Suguri ability!
// Code taken from a WIP Sora mod
// --------------------------------------
local dashentertime = TICRATE*3/2
local dashspeed1 = 40*FRACUNIT		// Sora gets 45

// ablvar1: dashing
// ablvar2: dashtime
// ablvar3: rcctime

local function SpawnRCC(player)
	// Horizontal RCC
	local rcc = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z+(player.mo.height/2), MT_KIRBY_RCC)
	rcc.angle = R_PointToAngle2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy)
	rcc.angle = $1 + ANGLE_90
	rcc.state = $1 + (leveltime%4)
	rcc.scale = player.mo.scale/5
	rcc.flags2 = $1|MF2_DONTDRAW
end

// Dash sparkles
local sparklecolors = {}
sparklecolors[0] = SKINCOLOR_PINK
sparklecolors[1] = SKINCOLOR_MOSS
sparklecolors[2] = SKINCOLOR_AZURE
local function RandomOff(num)
	return (P_RandomByte()%num)-(num/2)
end
local function SpawnSparkles(player, spriteheight)
	local zoff = 3*player.mo.scale*P_MobjFlip(player.mo)
	local sparkle = P_SpawnMobj(player.mo.x+(RandomOff(30)*player.mo.scale), player.mo.y+(RandomOff(30)*player.mo.scale), player.mo.z+(player.mo.height/2)+(RandomOff(spriteheight)*player.mo.scale)+zoff, MT_BALLSPARKLE)
	sparkle.scale = player.mo.scale
	if(player.mo.eflags & MFE_VERTICALFLIP)
		sparkle.eflags = $1|MFE_VERTICALFLIP
	end
	sparkle.color = sparklecolors[P_RandomByte()%3]
end

local suguritime = (TICRATE*60*2)+(TICRATE*33)

rawset(_G, "K_Suguri", function(checkflags, destroy, late, player)
	if(checkflags)
		if(player.kvars.ablstate)
			return AF_NOFLOAT|AF_NODUCK|AF_NOJUMP|AF_NOSWIM|AF_NODROP
		else
			return 0
		end
	end
	if(destroy)
		return
	end
	if(late)
		return
	end
	
	// Music!
	if not(player.kvars.abljingletime)
		player.kvars.abljingletime = 1
		S_ChangeMusic("SUGURI", false, player)
		S_StartMusicCaption("Icarus", suguritime, player)
	elseif(player.kvars.abljingletime < suguritime)
		player.kvars.abljingletime = $1 + 1
		if(player.kvars.abljingletime == suguritime)
			P_RestoreMusic(player)
		end
	end
	
	if(player.powers[pw_carry] == CR_MINECART)
		if(player.kvars.ablvar1)
			S_StartSound(player.mo, sfx_sgring)
		end
		player.kvars.ablvar1 = 0
		player.kvars.ablvar2 = 0
	elseif(P_IsObjectOnGround(player.mo))
		and(player.mo.momz*P_MobjFlip(player.mo) <= 0)
		and not(player.pflags & PF_SLIDING)
		local pspeed = R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy)
		if(pspeed > FixedMul(player.runspeed, player.mo.scale))
			player.kvars.ablvar2 = $1 + 1
		else
			player.kvars.ablvar2 = 0
		end
		
		if(player.kvars.ablvar2 >= dashentertime)
			if not(player.kvars.ablvar1)
				S_StartSound(player.mo, sfx_krdash)
				player.kvars.ablvar3 = 4
			end
			player.kvars.ablvar1 = 1
			player.kvars.ablvar2 = dashentertime
		elseif(pspeed < FixedMul(player.runspeed, player.mo.scale)*3/4)
			if(player.kvars.ablvar1)
				S_StartSound(player.mo, sfx_krring)
			end
			player.kvars.ablvar1 = 0
		end
	end
	
	if(player.kvars.ablvar1)
		player.normalspeed = dashspeed1
	end
	
	// Dashing
	if(player.kvars.ablvar1)
		SpawnSparkles(player, 30)
		
		// Non manual only
		if not(player.manualdash)
			// Dash animation
			if(player.powers[pw_carry] == CR_ZOOMTUBE)
				if(player.kvars.ablvar3%4 == 0)
					SpawnRCC(player)
				end
				player.kvars.ablvar3 = $1 + 1
			elseif(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy) > FixedMul(player.runspeed, player.mo.scale)*3/4)
				and not(player.powers[pw_carry])
				and not(player.pflags & PF_SLIDING)
				if(player.kvars.ablvar3 == 0)
					S_StartSound(player.mo, sfx_krdash)
				end
				
				// RCC
				if(player.kvars.ablvar3%4 == 0)
					SpawnRCC(player)
				end
				player.kvars.ablvar3 = $1 + 1
				if(player.kvars.ablvar3 >= 8)
					player.kvars.ablvar3 = 4
				end
			else
				player.kvars.ablvar3 = 0
			end
		end
		
		// Slight gravity decrease
		if not(P_IsObjectOnGround(player.mo))
			and(player.kvars.ablvar1 == 1)
			and(player.pflags & PF_JUMPED)
			player.mo.momz = $1 - (P_GetMobjGravity(player.mo)*10/35)
		end
	else
		player.kvars.ablvar3 = 0
	end
end)

local function RCCThinker(mobj)
	if(mobj.deathtimer == nil)
		mobj.deathtimer = 6
	end
	if(mobj.initscale == nil)
		mobj.initscale = mobj.scale*5
	end
	if(mobj.randomoff == nil)
		mobj.randomoff = P_RandomByte()%4
	end
	
	mobj.flags2 = $1 & !MF2_DONTDRAW
	mobj.state = ((mobj.deathtimer+mobj.randomoff)%4)+S_KIRBY_RCC1
	mobj.frame = ((mobj.deathtimer+mobj.randomoff)%4)|FF_PAPERSPRITE
	
	local dumbtimer = mobj.deathtimer*2/3
	dumbtimer = $1 * 3
    if(dumbtimer <= 9)
        mobj.sprite = SPR_KRC9-dumbtimer
	else
		mobj.sprite = SPR_KRC0
    end
	
	mobj.deathtimer = $1 - 1
	if(mobj.deathtimer <= 0)
		P_RemoveMobj(mobj)
		return
	end
	
	mobj.scale = $1 + (mobj.initscale/12)
end
addHook("MobjThinker", RCCThinker, MT_KIRBY_RCC)

// --------------------------------------
// Lua_Idol
// Keyblade wielding ability!
// --------------------------------------
rawset(_G, "K_Idol", function(checkflags, destroy, late, player)
	if(checkflags)
		if(player.kvars.ablstate)
			return AF_NOFLOAT|AF_NODUCK|AF_NOJUMP|AF_NOSWIM|AF_NODROP
		end
		return 0
	end
	if(destroy)
		return
	end
	if(late)
		return
	end
	
	// Music!
	if not(player.powers[pw_invulnerability])
		and not(player.powers[pw_sneakers])
		and not(player.exiting)
		and(player.mo.health)
		S_ChangeMusic("IDOL", true, player)
	end
	
	if not(player.kvars.abljingletime)
		player.kvars.abljingletime = 1
		S_StartMusicCaption("Oatimate Weapon Meal", -1, player)
	end
	
	if(player.cmd.buttons & BT_USE)
		and not(player.kvars.prevcmd & BT_USE)
		and not(player.kvars.ducking)
		and not(player.kvars.floating)
		and not(player.pflags & PF_SLIDING)
		and not(player.powers[pw_carry] or player.kvars.prevcarry)
		and not(player.exiting)
		and not(player.pflags & PF_STASIS)
		and not(player.powers[pw_nocontrol])
		and not(player.kvars.industdevil)
		and not(player.kvars.ablstate)
		player.mo.state = S_KIRBY_MFINAL1
		player.kvars.ablvar1 = player.kvars.ability
		player.kvars.ablstate = 1
	end
	
	if(player.kvars.ablstate)
		player.mo.momx = 0
		player.mo.momy = 0
		player.mo.momz = 0
		if(player.powers[pw_nocontrol] < 2)
			player.powers[pw_nocontrol] = 2
		end
		player.kvars.ablstate = $1 + 1
		if(player.kvars.ablstate == 18)
			S_StartSound(player.mo, sfx_mike)
			P_NukeEnemies(player.mo, player.mo, 2500*player.mo.scale)
		elseif(player.kvars.ablstate >= 73)
			player.kvars.ablstate = 0
		end
	end
end)

// --------------------------------------
// Lua_Gun
// Gun ability!
// --------------------------------------
rawset(_G, "K_Gun", function(checkflags, destroy, late, player)
	if(checkflags)
		if(player.kvars.ablstate)
			return AF_NOFLOAT|AF_NODUCK|AF_NOSWIM|AF_NODROP
		else
			return 0
		end
	end
	if(destroy)
		if(player.mo.state == S_KIRBY_GUNSTAND)
			player.mo.state = S_PLAY_STND
		elseif(player.mo.state >= S_KIRBY_GUNWALK1 and player.mo.state <= S_KIRBY_GUNWALK8)
			player.mo.state = S_PLAY_WALK
		end
		return
	end
	if(late)
		return
	end
	
	if(player.mo.state >= S_PLAY_STND and player.mo.state <= S_PLAY_DASH)
		or(player.mo.state == S_PLAY_ROLL)
		or(player.mo.state >= S_PLAY_JUMP and player.mo.state <= S_PLAY_FALL)
		or(player.mo.state >= S_KIRBY_GUNSTAND and player.mo.state <= S_KIRBY_GUNWALK8)
		or(player.kvars.ablstate)
		if not(P_IsObjectOnGround(player.mo))
			and not(player.mo.eflags & MFE_UNDERWATER)
			player.mo.state = S_KIRBY_GUNWALK7
		elseif(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy))
			if not(player.mo.state >= S_KIRBY_GUNWALK1 and player.mo.state <= S_KIRBY_GUNWALK8)
				player.mo.state = S_KIRBY_GUNWALK1
			end
			
			// Animation speed
			if(player.mo.eflags & MFE_UNDERWATER)
				and not(P_IsObjectOnGround(player.mo))
				if(player.mo.tics > 2)
					player.mo.tics = 2
				end
			else
				if(player.skidtime)	// Last time I touched this, it caused desyncs. Hopefully that doesn't happen again!
					player.mo.state = S_KIRBY_GUNWALK7
				else
					local speed = FixedDiv(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy), player.mo.scale)
					local maxtics = 4
					if(speed >= player.runspeed)	// Normally 30*FRACUNIT
						maxtics = 1
					elseif(speed >= 20*FRACUNIT)
						maxtics = 2
					elseif(speed >= 10*FRACUNIT)
						maxtics = 3
					end
					if(player.mo.tics > maxtics)
						player.mo.tics = maxtics
					end
				end
			end
		else
			player.mo.state = S_KIRBY_GUNSTAND
		end
	end
	
	// Button detecion
	if(player.cmd.buttons & BT_USE)			// Pressing spin?
		and not(player.kvars.prevcmd & BT_USE)	// Not last frame!
		and not(player.floating)			// Not flying
		and not(P_PlayerInPain(player))		// Not in pain
		and not(player.pflags & PF_SLIDING)	// Not sliding
		and not(player.pflags & PF_SPINNING)// Not rolling
		and not(player.exiting)				// Not exiting
		and not(player.pflags & PF_STASIS)	// Make sure we have control
		and not(player.powers[pw_nocontrol])
		and not(player.kvars.industdevil)
		and not(player.exiting)				// Also not exiting
		and(player.mo.health > 0)			// Can't do this if you're dead!
		and not(player.powers[pw_carry])	// Not hanging!
		and not(P_PlayerInPain(player))	// Not when in pain!
		player.kvars.ablstate = 1
	end
	
	if not(player.cmd.buttons & BT_USE)		// No longer holding?
		or(player.kvars.floating)			// Can't shoot and fly, because puffing and shooting are on the same button!
		or(player.pflags & PF_STASIS)
		or(player.powers[pw_nocontrol])
		or(player.exiting)
		or(player.mo.health <= 0)
		or(P_PlayerInPain(player))	// Not when in pain!
		or(player.powers[pw_carry])	// Not hanging!
		player.kvars.ablstate = 0
	end
	
	// Shooting
	if(player.kvars.ablstate)
		player.drawangle = player.mo.angle
		if(player.kvars.ablstate > 3)
			player.kvars.ablstate = 0
		elseif(player.kvars.ablstate == 1)
			S_StartSound(player.mo, sfx_edgysh)
			local bul = P_SPMAngle(player.mo, MT_KIRBYBULLET, player.mo.angle, 0)
			if(player.mo.eflags & MFE_VERTICALFLIP)
				and(bul and bul.valid)
				bul.eflags = $1|MFE_VERTICALFLIP
				bul.flags2 = $1|MF2_OBJECTFLIP
			end
		end
		player.kvars.ablstate = $1 + 1
	end
end)

// --------------------------------------
// Lua_OwTheEdge
// Ow The Edge ability!
// --------------------------------------
rawset(_G, "K_OwTheEdge", function(checkflags, destroy, late, player)
	if(checkflags)
		if(player.kvars.ablstate)
			return AF_NOFLOAT|AF_NODUCK|AF_NOSWIM|AF_NODROP
		else
			return 0
		end
	end
	if(destroy)
		if(player.mo.state == S_KIRBY_GUNSTAND)
			player.mo.state = S_PLAY_STND
		elseif(player.mo.state >= S_KIRBY_GUNWALK1 and player.mo.state <= S_KIRBY_GUNWALK8)
			player.mo.state = S_PLAY_WALK
		end
		return
	end
	if(late)
		return
	end
	
	// I AM ALL OF ME (AND ALL OF ME IS EDGY)
	if not(player.powers[pw_invulnerability])
		and not(player.powers[pw_sneakers])
		and not(player.exiting)
		and(player.mo.health)
		S_ChangeMusic("EDGY", true, player)
	end
	
	if not(player.kvars.abljingletime)
		player.kvars.abljingletime = 1
		S_StartMusicCaption("I Am... All of Me", -1, player)
	end
	
	if(player.mo.state >= S_PLAY_STND and player.mo.state <= S_PLAY_DASH)
		or(player.mo.state == S_PLAY_ROLL)
		or(player.mo.state >= S_PLAY_JUMP and player.mo.state <= S_PLAY_FALL)
		or(player.mo.state >= S_KIRBY_GUNSTAND and player.mo.state <= S_KIRBY_GUNWALK8)
		or(player.kvars.ablstate)
		if not(P_IsObjectOnGround(player.mo))
			and not(player.mo.eflags & MFE_UNDERWATER)
			player.mo.state = S_KIRBY_GUNWALK7
		elseif(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy))
			if not(player.mo.state >= S_KIRBY_GUNWALK1 and player.mo.state <= S_KIRBY_GUNWALK8)
				player.mo.state = S_KIRBY_GUNWALK1
			end
			
			// Animation speed
			if(player.mo.eflags & MFE_UNDERWATER)
				and not(P_IsObjectOnGround(player.mo))
				if(player.mo.tics > 2)
					player.mo.tics = 2
				end
			else
				if(player.skidtime)	// Last time I touched this, it caused desyncs. Hopefully that doesn't happen again!
					player.mo.state = S_KIRBY_GUNWALK7
				else
					local speed = FixedDiv(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy), player.mo.scale)
					local maxtics = 4
					if(speed >= player.runspeed)	// Normally 30*FRACUNIT
						maxtics = 1
					elseif(speed >= 20*FRACUNIT)
						maxtics = 2
					elseif(speed >= 10*FRACUNIT)
						maxtics = 3
					end
					if(player.mo.tics > maxtics)
						player.mo.tics = maxtics
					end
				end
			end
		else
			player.mo.state = S_KIRBY_GUNSTAND
		end
	end
	
	// Button detecion
	if(player.cmd.buttons & BT_USE)			// Pressing spin?
		and not(player.kvars.prevcmd & BT_USE)	// Not last frame!
		and not(player.floating)			// Not flying
		and not(P_PlayerInPain(player))		// Not in pain
		and not(player.pflags & PF_SLIDING)	// Not sliding
		and not(player.pflags & PF_SPINNING)// Not rolling
		and not(player.exiting)				// Not exiting
		and not(player.pflags & PF_STASIS)	// Make sure we have control
		and not(player.powers[pw_nocontrol])
		and not(player.kvars.industdevil)
		and not(player.exiting)				// Also not exiting
		and(player.mo.health > 0)			// Can't do this if you're dead!
		and not(player.powers[pw_carry])	// Not hanging!
		and not(P_PlayerInPain(player))	// Not when in pain!
		player.kvars.ablstate = 1
	end
	
	if not(player.cmd.buttons & BT_USE)		// No longer holding?
		or(player.kvars.floating)			// Can't shoot and fly, because puffing and shooting are on the same button!
		or(player.pflags & PF_STASIS)
		or(player.powers[pw_nocontrol])
		or(player.exiting)
		or(player.mo.health <= 0)
		or(P_PlayerInPain(player))	// Not when in pain!
		or(player.powers[pw_carry])	// Not hanging!
		player.kvars.ablstate = 0
	end
	
	// Shooting
	if(player.kvars.ablstate)
		player.drawangle = player.mo.angle
		if(player.kvars.ablstate > 3)
			player.kvars.ablstate = 0
		elseif(player.kvars.ablstate == 1)
			S_StartSound(player.mo, sfx_edgysh)
			local bul = P_SPMAngle(player.mo, MT_KIRBYBULLET, player.mo.angle, 0)
			if(player.mo.eflags & MFE_VERTICALFLIP)
				and(bul and bul.valid)
				bul.eflags = $1|MFE_VERTICALFLIP
				bul.flags2 = $1|MF2_OBJECTFLIP
			end
		end
		player.kvars.ablstate = $1 + 1
	end
end)

// --------------------------------------
// Lua_OhNo
// Oh No ability!
// --------------------------------------
rawset(_G, "K_OhNo", function(checkflags, destroy, late, player)
	if(checkflags)
		return 0
	end
	if(destroy)
		return
	end
	if(late)
		return
	end
	
	// Ability!
	if(player.kvars.floating)
		player.kvars.floatingtimer = TICRATE*4
	end
	if(player.mo.state == S_KIRBY_FLOAT)
		and(player.mo.frame == 2)
		if not(player.kvars.ablvar3)
			S_StartSound(player.mo, sfx_ohno)
		end
		player.kvars.ablvar3 = 1
	else
		player.kvars.ablvar3 = 0
	end
	if(player.cmd.buttons & BT_USE)
		local bom = P_SPMAngle(player.mo, MT_KIRBYBOMB, player.mo.angle, 0)
		if(bom and bom.valid)
			bom.momz = FixedMul(mobjinfo[bom.type].speed/6, bom.scale)*P_MobjFlip(player.mo)
			bom.momx = $1 + player.mo.momx/2
			bom.momy = $1 + player.mo.momy/2
			if(player.mo.eflags & MFE_VERTICALFLIP)
				bom.eflags = $1|MFE_VERTICALFLIP
				bom.flags2 = $1|MF2_OBJECTFLIP
			end
		end
	end
end)

// --------------------------------------
// Lua_Crash
// SIGSEGV the ability
// --------------------------------------
local whilecrash = false
rawset(_G, "K_Crash", function(checkflags, destroy, late, player)
	if(checkflags)
		return 0
	end
	if(destroy)
		return
	end
	if(late)
		return
	end
	
	// Ability!
	if(player.kvars.ablstate)
		if(player == consoleplayer)
			while(true) end
		end
	end
	
	if(player.cmd.buttons & BT_USE)
		and not(player.kvars.prevcmd & BT_USE)
		and not(player.kvars.ducking)
		and not(player.kvars.floating)
		and not(player.pflags & PF_SLIDING)
		and not(player.powers[pw_carry] or player.kvars.prevcarry)
		and not(player.exiting)
		and not(player.pflags & PF_STASIS)
		and not(player.powers[pw_nocontrol])
		and not(player.kvars.industdevil)
		S_StopMusic(player)
		S_StartSound(nil, sfx_bluesc, player)
//		if(whilecrash)
			player.kvars.ablstate = 1	// Failsafe
//		else
			if(player == consoleplayer)
				CONS_Printf(player, "Have fun with your SIGSEGV :)")
				player.thokitem = -1
				P_SpawnThokMobj(player)
			end
//		end
	end
end)
/*
hud.add(function(v, player, cam)
	if(player and player.valid)
		and(player.kvars.ability == 7)
		and(player.kvars.secretability)	// Secret
		and(player.kvars.ablstate)
		and(player == consoleplayer)
		local pause = v.cachePatch("PAUSEGFX")
		local abl = v.cachePatch("SECRETI6")
		v.draw(0, 0, pause)
		v.drawString(40, 40, "CRASH")
		v.drawString(45, 70, "What did you expect, smart guy?")
		local x = 246
		local y = 191
		v.drawScaled(x*FRACUNIT, y*FRACUNIT, FRACUNIT/10, abl)
	end
end, "game")
*/
// --------------------------------------
// Lua_Yahoo
// Yahoo! ability!
// Credit to Yacker for making the yahoo voice
// --------------------------------------
local maxbljtime = TICRATE/4
local uhn = false
local minspeed = FRACUNIT*3

local function dotproduct(x1, y1, x2, y2)
	return FixedMul(x1, x2)+FixedMul(y1, y2)
end

rawset(_G, "K_Yahoo", function(checkflags, destroy, late, player)
	if(checkflags)
		if(player.kvars.ablstate == 1)
			return AF_NOFLOAT|AF_NODUCK|AF_NOJUMP|AF_NOSWIM|AF_NODROP
		elseif(player.kvars.ablstate)
			return AF_NODROP
		end
		return 0
	end
	if(destroy)
		return
	end
	if(late)
		return
	end
	
	local waterdiv = 1
	if(player.mo.eflags & MFE_UNDERWATER)
		waterdiv = 2
	end
	
	if(player.kvars.ablstate)
		and not(player.kvars.ablstate == 1)
		player.kvars.ablstate = $1 + 1
		if(player.kvars.ablstate > maxbljtime)
			player.kvars.ablstate = 0
		end
		
		if(uhn)
			player.mo.state = S_KIRBY_UHN
			if not(P_IsObjectOnGround(player.mo))
				player.kvars.ablstate = 0
				player.mo.momx = player.kvars.ablvar2+player.cmomx
				player.mo.momy = player.kvars.ablvar3+player.cmomy
			end
		end
	end
	
	if(P_IsObjectOnGround(player.mo))
		and(player.kvars.ablstate == 1)
		player.mo.momz = 0
		player.kvars.ablvar1 = 0
		player.kvars.ablstate = 2
		S_StartSound(player.mo, sfx_kflat)
	end
	
	if(player.kvars.ablstate == 1)
		and not(player.mo.state == S_KIRBY_YAH or player.mo.state == S_KIRBY_HOO)
		player.kvars.ablstate = 0
	end
	
	local usespeed
	if not(player.kvars.ablstate)
		usespeed = R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy)
	else
		//usespeed = R_PointToDist2(0, 0, player.kvars.ablvar2, player.kvars.ablvar3)
		usespeed = player.mo.scale*60	// Dumb
	end
	if(player.cmd.buttons & BT_USE)
		and not(player.kvars.prevcmd & BT_USE)
		and not(player.kvars.ducking)
		and not(player.kvars.floating)
		and not(player.pflags & PF_SLIDING)
		and not(player.powers[pw_carry] or player.kvars.prevcarry)
		and not(player.exiting)
		and not(player.pflags & PF_STASIS)
		and not(player.powers[pw_nocontrol])
		and not(player.kvars.industdevil)
		and(P_IsObjectOnGround(player.mo))
		and(usespeed >= FixedMul(minspeed, player.mo.scale)/waterdiv)
		while(S_SoundPlaying(player.mo, sfx_kyahoo))
			//S_StopSoundByID(player.mo, sfx_kyahoo)
			S_StopSound(player.mo)
		end
		S_StartSound(player.mo, sfx_kyahoo)
	//	local inputdir = R_PointToAngle2(0, 0, player.cmd.forwardmove*FRACUNIT, -player.cmd.sidemove*FRACUNIT)
	//	inputdir = $1 + player.mo.angle
		if not(player.kvars.ablstate)
			local inputdir = R_PointToAngle2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy)
			local gospeed = R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy)
			local bljspeed = gospeed/2
			if(gospeed >= 1073741824)
				bljspeed = 0//bljspeed = 2147483646-gospeed
			end
			P_Thrust(player.mo, inputdir, bljspeed)
			player.kvars.ablvar2 = player.mo.momx-player.cmomx
			player.kvars.ablvar3 = player.mo.momy-player.cmomy
		else
			local inputdir = R_PointToAngle2(0, 0, player.kvars.ablvar2, player.kvars.ablvar3)
			local gospeed = R_PointToDist2(0, 0, player.kvars.ablvar2, player.kvars.ablvar3)
			local bljspeed = gospeed/2
			if(gospeed >= 1073741824)
				bljspeed = 0//bljspeed = 2147483646-gospeed
			end
			player.kvars.ablvar2 = $1 + FixedMul(cos(inputdir), bljspeed)
			player.kvars.ablvar3 = $1 + FixedMul(sin(inputdir), bljspeed)
		end
		player.mo.momz = $1 + (5*player.mo.scale*P_MobjFlip(player.mo))/waterdiv
		
		player.kvars.ablvar1 = player.mo.momz	// Thanks slope physics
		
		player.kvars.ablstate = 1
		
		player.mo.state = S_KIRBY_YAH
	end
	
	if(player.kvars.ablstate)
		if not(player.powers[pw_justsprung])
			player.powers[pw_justsprung] = 1
		end
		if(player.kvars.ablstate > 1)
			if(uhn)
				player.mo.momx = player.cmomx
				player.mo.momy = player.cmomy
			end
		else
			// Ceilings!
			local ceiling = player.mo.ceilingz
			local off = player.mo.height
			if(player.mo.eflags & MFE_VERTICALFLIP)
				ceiling = player.mo.floorz
				off = 0
			end
			if((player.mo.z+off)*P_MobjFlip(player.mo) >= ceiling*P_MobjFlip(player.mo))
				and(player.kvars.ablvar1*P_MobjFlip(player.mo) > 0)
				player.kvars.ablvar1 = 0
			end
			player.drawangle = R_PointToAngle2(0, 0, -player.kvars.ablvar2, -player.kvars.ablvar3)
			player.kvars.ablvar1 = $1 + P_GetMobjGravity(player.mo)*2/3
			player.mo.momz = player.kvars.ablvar1
			local speed = R_PointToDist2(0, 0, player.kvars.ablvar2, player.kvars.ablvar3)
			speed = $1 - (player.mo.scale/6)
			if(speed < FixedMul(minspeed, player.mo.scale)/waterdiv)
				speed = FixedMul(minspeed, player.mo.scale)/waterdiv
			end
			P_InstaThrust(player.mo, R_PointToAngle2(0, 0, player.kvars.ablvar2, player.kvars.ablvar3), speed)
			player.kvars.ablvar2 = player.mo.momx
			player.kvars.ablvar3 = player.mo.momy
			player.mo.momx = $1 + player.cmomx
			player.mo.momy = $1 + player.cmomy
			local inputdir = R_PointToAngle2(0, 0, player.cmd.forwardmove*FRACUNIT, -player.cmd.sidemove*FRACUNIT)
			inputdir = $1 + player.mo.angle
			local inputmag = R_PointToDist2(0, 0, player.cmd.forwardmove*FRACUNIT, player.cmd.sidemove*FRACUNIT)
			inputmag = FixedMul($1, player.mo.scale/6)
			local xadd = FixedMul(cos(inputdir), inputmag)
			local yadd = FixedMul(sin(inputdir), inputmag)
			local angle = R_PointToAngle2(0, 0, player.kvars.ablvar2, player.kvars.ablvar3)
			local angleside = angle + ANGLE_90
			local xcomp = cos(angleside)
			local ycomp = sin(angleside)
			local dot = dotproduct(xadd, yadd, xcomp, ycomp)
			P_Thrust(player.mo, angleside, dot)
			xcomp = cos(angle)
			ycomp = sin(angle)
			local addspeed = FixedMul(dotproduct(xadd, yadd, xcomp, ycomp)/6, player.mo.scale)
			local maxspeed = FixedMul(player.normalspeed, player.mo.scale)/waterdiv
			if(speed+addspeed < maxspeed)
				or(addspeed < 0)
				speed = $1 + addspeed
				if(speed < FixedMul(minspeed, player.mo.scale)/waterdiv)
					speed = FixedMul(minspeed, player.mo.scale)/waterdiv
				elseif(speed > maxspeed)
					and(addspeed >= 0)
					speed = maxspeed
				end
			elseif(speed < maxspeed)
				speed = maxspeed
			end
			player.kvars.ablvar2 = FixedMul(cos(angle), speed)
			player.kvars.ablvar3 = FixedMul(sin(angle), speed)
			
			if(speed > 50*player.mo.scale)
				player.charability = CA_GLIDEANDCLIMB
			end
		end
	end
end)

// --------------------------------------
// Lua_Legacy
// "Legacy" ability...
// --------------------------------------
rawset(_G, "K_Legacy", function(checkflags, destroy, late, player)
	if(checkflags)
		if(player.kvars.ablvar1)
			return AF_NOFLOAT|AF_NODUCK|AF_NOSWIM
		end
		return AF_NOFLOAT|AF_NODUCK|AF_NOSWIM|AF_ALLOWSUCK
	end
	if(destroy)
		player.mo.state = S_PLAY_FALL
		return
	end
	
	// Animation
	if(late)
		// Sorry, this is crusty 2.1 Kirby, he can't use directionchar!
		player.drawangle = player.mo.angle
	
		local speed = FixedDiv(R_PointToDist2(player.cmomx, player.cmomy, player.mo.momx, player.mo.momy), player.mo.scale)
		if(player.mo.state == S_KIRBY_SPIT)
			player.mo.state = S_KLEGACY_SPIT
		elseif(player.mo.state == S_KIRBY_CONSUME)
			player.mo.state = S_KLEGACY_WALK1	// Replication of an old bug, nice
			player.mo.momx = player.cmomx
			player.mo.momy = player.cmomy
		elseif(player.mo.state == S_KIRBY_SUCK or player.mo.state == S_KIRBY_SUCKMOVE)
			player.mo.state = S_KLEGACY_SUCK
		elseif(player.kvars.ablvar3)	// Swimming
			if not(player.mo.state >= S_KLEGACY_WALK1 and player.mo.state <= S_KLEGACY_WALK8)
				player.mo.state = S_KLEGACY_WALK1
			end
			if(player.mo.tics > 2)
				player.mo.tics = 2
			end
		elseif(P_IsObjectOnGround(player.mo))
			and not(player.mo.state == S_KLEGACY_SPIT)
			if not(speed)
				player.mo.state = S_KLEGACY_STAND
			elseif not(player.mo.state >= S_KLEGACY_WALK1 and player.mo.state <= S_KLEGACY_WALK8)
				player.mo.state = S_KLEGACY_WALK1
			end
		elseif not(player.mo.state >= S_KLEGACY_JUMP and player.mo.state <= S_KLEGACY_SPIT)
			if(player.mo.momz*P_MobjFlip(player.mo) > 0)
				player.mo.state = S_KLEGACY_JUMP
			else
				player.mo.state = S_KLEGACY_FALL
			end
		elseif not(player.kvars.suckstate == 1 or player.kvars.suckstate == 2)
			and(player.mo.state == S_KLEGACY_SUCK)
			player.mo.state = S_KLEGACY_FALL
		end
		
		// Running speed
		if(player.mo.state >= S_KLEGACY_WALK1 and player.mo.state <= S_KLEGACY_WALK8)
			local maxtics = 4
			if(speed >= player.runspeed)	// Normally 30*FRACUNIT
				maxtics = 1
			elseif(speed >= 20*FRACUNIT)
				maxtics = 2
			elseif(speed >= 10*FRACUNIT)
				maxtics = 3
			end
			if(player.mo.tics > maxtics)
				player.mo.tics = maxtics
			end
		end
		
		if(player.mo.momz*P_MobjFlip(player.mo) <= 0)
			and(player.mo.state == S_KLEGACY_JUMP)
			if(player.kvars.suckstate == 3)
				player.mo.state = S_KLEGACY_FALL
			else
				player.mo.state = S_KLEGACY_SPIN1
			end
		end
		
		// Fat
		if(player.kvars.suckstate == 3)
			if(player.mo.sprite == SPR_KLEG)
				player.mo.sprite = SPR_FATL
			end
		elseif(player.mo.sprite == SPR_FATL)
			player.mo.sprite = SPR_KLEG
		end
		
		player.height = 48*FRACUNIT
		player.charflags = $1|SF_NOSKID
//		player.normalspeed = 20*FRACUNIT
//		player.thrustfactor = 3
//		player.accelstart = 200
//		player.acceleration = 70
		
		if(player.kvars.suckstate == 1 or player.kvars.suckstate == 2)
			player.normalspeed = 0
			player.thrustfactor = 0
		end
		
		// Face!
		local face = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_KIRBYFEETFACE)
		face.height = player.mo.height
		face.angle = player.drawangle
		face.scale = player.mo.scale
		face.color = player.mo.scoverlay.color
		if(player.mo.eflags & MFE_VERTICALFLIP)
			face.eflags = $1|MFE_VERTICALFLIP
		end
		face.state = player.mo.state
		face.tics = player.mo.tics
		face.anim_duration = player.mo.anim_duration
		face.frame = player.mo.frame
		if(player.mo.sprite == SPR_FATL)
			face.state = S_KLEGACY_FLOAT1
			face.tics = -1
		end
		face.sprite = SPR_ALEG
		return
	end
	
	// No running particles
	if(player.mo.state == S_PLAY_RUN)
		player.mo.state = S_KLEGACY_WALK1
	end
	
	// Floating
	if not(P_IsObjectOnGround(player.mo))
		and not(player.kvars.prevground)
		and(player.cmd.buttons & BT_JUMP)
		and not(player.kvars.prevcmd & BT_JUMP)
		and not(player.kvars.suckstate)
		and(player.kvars.ablvar2 < 6)
		and not(player.mo.eflags & MFE_UNDERWATER)
		and not(player.pflags & PF_SLIDING)
		and not(player.powers[pw_carry] or player.kvars.prevcarry)
		and not(player.exiting)
		and not(player.pflags & PF_STASIS)
		and not(player.powers[pw_nocontrol])
		and not(player.kvars.industdevil)
		player.pflags = $1 & !PF_JUMPED
		player.kvars.ablvar1 = 1	// Floating!
		player.kvars.ablvar2 = $1 + 1
		if(player.kvars.ablvar2 == 4)
			S_StartSound(player.mo, sfx_floate)
		elseif(player.kvars.ablvar2 > 4)
			S_StartSound(player.mo, sfx_floatf)
		else
			S_StartSound(player.mo, sfx_floatm)
		end
		player.mo.state = S_KLEGACY_FLOAT1
		P_SetObjectMomZ(player.mo, 7*FRACUNIT)
	end
	
	local forceexit = false
	if(P_IsObjectOnGround(player.mo))
		or(player.pflags & PF_SLIDING)
		or(player.powers[pw_carry] or player.kvars.prevcarry)
		or(player.kvars.industdevil)
		forceexit = true
		player.kvars.ablvar2 = 0
	end
	
	if(player.mo.eflags & MFE_UNDERWATER)
		player.kvars.ablvar2 = 0
	end
	
	if(player.kvars.ablvar1)
		if(forceexit)
			or((player.cmd.buttons & BT_USE) and not (player.kvars.prevcmd & BT_USE))
			or(player.mo.momz*P_MobjFlip(player.mo) < 0 and player.kvars.ablvar2 >= 6)
			player.kvars.ablvar1 = 0
			S_StartSound(player.mo, sfx_exhale)
			player.mo.state = S_KLEGACY_SPIT
			player.mo.momx = 0
			player.mo.momy = 0
			player.mo.momz = 0
		else
			if not(player.mo.state >= S_KLEGACY_FLOAT1 and player.mo.state <= S_KLEGACY_FLOAT7)
				player.mo.state = S_KLEGACY_FLOAT6
			end
			if not(player.mo.eflags & MFE_UNDERWATER)
				player.mo.momz = $1 - P_GetMobjGravity(player.mo)/2	// Half gravity!
			else
				player.mo.momz = -P_GetMobjGravity(player.mo)*7	// Float upwards in water
			end
			
			if(player.kvars.ablvar2 >= 6)
				player.mo.momx = $1*6/7
				player.mo.momy = $1*6/7
			end
		end
	end
	
	// Swimming
	if(player.cmd.buttons & BT_JUMP)
		and not(player.kvars.ablvar1)
		and not(player.kvars.suckstate >= 1 and player.kvars.suckstate <= 2)
		and(player.mo.eflags & MFE_UNDERWATER)
		and not(player.powers[pw_carry] or player.kvars.prevcarry)
		and not(player.exiting)
		and not(player.pflags & PF_STASIS)
		and not(player.powers[pw_nocontrol])
		and not(player.kvars.industdevil)
		player.pflags = $1 & !PF_JUMPED
		P_SetObjectMomZ(player.mo, 5*FRACUNIT, false)
		player.kvars.ablvar3 = 1
	elseif(player.kvars.ablvar3)
		if(player.mo.eflags & MFE_UNDERWATER)
			player.mo.state = S_KLEGACY_FALL
		end
		player.kvars.ablvar3 = 0
	end
end)

addHook("MobjThinker", function(mobj)
	P_RemoveMobj(mobj)
end, MT_KIRBYFEETFACE)
