local function driftcheck(p)
	if (p.cmd.buttons & p.driftbutton)
	and (p.cmd.sidemove < -25 or p.cmd.sidemove > 25)
	and p.speed >= skins[p.mo.skin].runspeed
	and not p.powers[pw_underwater]
	and P_IsObjectOnGround(p.mo)
	or p.powers[pw_underwater]
	and (p.cmd.buttons & p.driftbutton)
	and (p.cmd.sidemove < -25 or p.cmd.sidemove > 25)
	and p.speed >= 10*FU
	and P_IsObjectOnGround(p.mo)
		return true
	else
		return false
	end
end

local function driftthings(p)
	local normalspeed = skins[p.mo.skin].normalspeed
	if not S_SoundPlaying(p.mo, sfx_screec)
		S_StartSound(p.mo, sfx_screec)
	end
	if not S_SoundPlaying(p.mo, sfx_drift)
		S_StartSound(p.mo, sfx_drift)
	end
	if not p.powers[pw_underwater]
	and p.dashmode < 3*TICRATE
		P_InstaThrust(p.mo, p.drawangle, normalspeed+15*FU)
	end
	if p.dashmode >= 3*TICRATE
		P_InstaThrust(p.mo, p.drawangle, p.normalspeed)
	end
	if p.powers[pw_underwater]
		P_InstaThrust(p.mo, p.drawangle, p.runspeed-1*FU)
	end
	if p.cmd.sidemove > 25
		p.drawangle = p.mo.angle+ANG15+ANG2
	end
	if p.cmd.sidemove < -25
		p.drawangle = p.mo.angle-ANG15+ANG2
	end
end

local function dust(p)
	local ryx = P_RandomRange(-13, 13)
	local dust = P_SpawnMobj(p.mo.x+ryx*FRACUNIT,p.mo.y+ryx*FRACUNIT,p.mo.z,MT_SPINDUST)
	dust.scale = p.mo.scale
	if (p.powers[pw_underwater] or p.mo.eflags & MFE_TOUCHWATER)
		dust.state = S_MEDIUMBUBBLE
	end
	if dust and dust.valid
		P_SetObjectMomZ(dust, dust.momz+3*FRACUNIT)
	end
end

addHook("PlayerThink", function(p)
	if p.mo.state == S_PLAY_RUN
	and (p.pflags & PF_JUMPED)
		p.mo.state = S_PLAY_JUMP
	end
end)

addHook("PlayerThink", function(p)
	if p.drifting == nil
		p.drifting = 0
		p.holdupwaitaminute = 0
	end
	if p.mo and p.mo.valid
	and driftcheck(p)
	and not p.powers[pw_carry]
	and p.drifting == 0
	and not (p.charflags & SF_NOJUMPSPIN)
	and P_IsValidSprite2(p.mo, SPR2_SPIN)
	and p.playerstate == PST_LIVE
	or p.mo.skin == "adventuresonic" -- I wanna drift with adventerous boi alright?
	and p.mo and p.mo.valid
	and driftcheck(p)
	and not p.powers[pw_carry]
	and p.drifting == 0
	and p.playerstate == PST_LIVE
		P_SetObjectMomZ(p.mo, 3*FU)
		S_StartSound(p.mo, sfx_jump)
		p.mo.state = S_PLAY_ROLL
		p.drifting = 1
	end
	if p.drifting == 1
		p.camerascale = FU-FU/3
		p.charflags = $|SF_RUNONWATER
	end
	if p.drifting > 0
	and (P_PlayerInPain(p) or p.powers[pw_carry] or p.powers[pw_justsprung] or p.playerstate == PST_DEAD)
		p.drifting = 0
		p.camerascale = FU
		p.charflags = skins[p.mo.skin].flags
		S_StopSoundByID(p.mo, sfx_screec)
		S_StopSoundByID(p.mo, sfx_drift)
	end
	if p.drifting == 2
	and not P_IsObjectOnGround(p.mo)
		p.drifting = 0
		p.camerascale = FU
		p.mo.state = S_PLAY_FALL
		p.charflags = skins[p.mo.skin].flags
	end
	if p.drifting == 1
	and (P_IsObjectOnGround(p.mo) or p.mo.eflags & MFE_JUSTHITFLOOR)
	and p.mo.momz == 0
		p.drifting = 2
	end
	if p.drifting == 2
		p.mo.state = S_PLAY_SPINDASH
		driftthings(p)
		dust(p)
		if leveltime%5 == 0
			for i = -1, 1, 2
				local ang = i * ANG10
				local factor = FixedMul(4*p.mo.scale, cos(ang))
				local x = P_ReturnThrustX(p.mo, p.mo.angle + ANGLE_180 + ang, 24*p.mo.scale)
				local y = P_ReturnThrustY(p.mo, p.mo.angle + ANGLE_180 + ang, 24*p.mo.scale)
				local dust = P_SpawnMobjFromMobj(p.mo, x, y, 0, MT_THOK)
				dust.scale = 2*$/3
				dust.angle = R_PointToAngle2(dust.x, dust.y, p.mo.x, p.mo.y)
				dust.state = S_DRIFTDUST
				dust.momx = FixedMul(factor, cos(dust.angle - i*ANGLE_90))
				dust.momy = FixedMul(factor, sin(dust.angle - i*ANGLE_90))
			end
		end
	end
end)

addHook("PlayerThink", function(p)
	if p.mo and p.mo.valid
	and p.drifting == 2
	and not driftcheck(p)
	and p.holdupwaitaminute == 0
		p.holdupwaitaminute = 1
	end
	if p.holdupwaitaminute >= 1
		p.holdupwaitaminute = $1+1
	end
	if driftcheck(p)
		p.holdupwaitaminute = 0
	end
	if p.holdupwaitaminute == 6
		p.holdupwaitaminute = 0
		p.drifting = 0
		p.mo.state = S_PLAY_RUN
		p.camerascale = FU
		S_StopSoundByID(p.mo, sfx_screec)
		S_StopSoundByID(p.mo, sfx_drift)
		p.charflags = skins[p.mo.skin].flags
	end
end)

addHook("SpinSpecial", function(p)
	if p.mo and p.mo.valid
	and p.drifting >= 1
		return true
	end
end)

addHook("JumpSpecial", function(p)
	if p.mo and p.mo.valid
	and p.drifting == 2
		p.drifting = 0
		p.camerascale = FU
		p.holdupwaitaminute = 0
		P_DoJump(p, true)
		S_StopSoundByID(p.mo, sfx_screec)
		S_StopSoundByID(p.mo, sfx_drift)
	end
end)

addHook("PlayerCanDamage", function(p)
	if p.drifting >= 1 then
		return true
	end
end)