//Freeslots
freeslot("sfx_insts",  
"sfx_vmdjp", 
"S_PLAY_VMPWALK1", 
"S_PLAY_VMPWALK2", 
"S_PLAY_VMPWALK3", 
"S_PLAY_VMPWALK4", 
"S_PLAY_VMPWALK5", 
"S_PLAY_VMPWALK6", 
"S_PLAY_VMPWALK7", 
"S_PLAY_VMPWALK8", 
"S_PLAY_VMPWALK9", 
"S_PLAY_VMPWALK10", 
"S_PLAY_VMPWALK11", 
"S_PLAY_VMPWALK12", 
"S_PLAY_VMPWALK13", 
"S_PLAY_VMPWALK14", 
"S_PLAY_VMPWALK15", 
"S_PLAY_VMPWALK16", 
"S_PLAY_VMPEEL1", 
"S_PLAY_VMPEEL2", 
"S_PLAY_VMPEEL3", 
"S_PLAY_VMPEEL4", 
"S_PLAY_SVMPEEL1", 
"S_PLAY_SVMPEEL2",
"S_PLAY_VMSONICWALLRUN",
"SPR_VMPL")

// States
states[S_PLAY_VMPWALK1] = {SPR_PLAY, SPR2_WALK1, 4, nil, 0, 0, S_PLAY_VMPWALK2}
states[S_PLAY_VMPWALK2] = {SPR_PLAY, SPR2_WALK2, 4, nil, 0, 0, S_PLAY_VMPWALK3}
states[S_PLAY_VMPWALK3] = {SPR_PLAY, SPR2_WALK3, 4, nil, 0, 0, S_PLAY_VMPWALK4}
states[S_PLAY_VMPWALK4] = {SPR_PLAY, SPR2_WALK4, 3, nil, 0, 0, S_PLAY_VMPWALK5}
states[S_PLAY_VMPWALK5] = {SPR_PLAY, SPR2_WALK5, 3, nil, 0, 0, S_PLAY_VMPWALK6}
states[S_PLAY_VMPWALK6] = {SPR_PLAY, SPR2_WALK6, 3, nil, 0, 0, S_PLAY_VMPWALK7}
states[S_PLAY_VMPWALK7] = {SPR_PLAY, SPR2_WALK7, 2, nil, 0, 0, S_PLAY_VMPWALK8}
states[S_PLAY_VMPWALK8] = {SPR_PLAY, SPR2_WALK8, 2, nil, 0, 0, S_PLAY_VMPWALK9}
states[S_PLAY_VMPWALK9] = {SPR_PLAY, SPR2_WALK1, 2, nil, 0, 0, S_PLAY_VMPWALK10}
states[S_PLAY_VMPWALK10] = {SPR_PLAY, SPR2_WALK2, 1, nil, 0, 0, S_PLAY_VMPWALK11}
states[S_PLAY_VMPWALK11] = {SPR_PLAY, SPR2_WALK3, 1, nil, 0, 0, S_PLAY_VMPWALK12}
states[S_PLAY_VMPWALK12] = {SPR_PLAY, SPR2_WALK4, 1, nil, 0, 0, S_PLAY_VMPWALK13}
states[S_PLAY_VMPWALK13] = {SPR_PLAY, SPR2_WALK5, 1, nil, 0, 0, S_PLAY_VMPWALK14}
states[S_PLAY_VMPWALK14] = {SPR_PLAY, SPR2_WALK6, 1, nil, 0, 0, S_PLAY_VMPWALK15}
states[S_PLAY_VMPWALK15] = {SPR_PLAY, SPR2_WALK7, 1, nil, 0, 0, S_PLAY_VMPWALK16}
states[S_PLAY_VMPWALK16] = {SPR_PLAY, SPR2_WALK8, 1, nil, 0, 0, S_PLAY_VMPEEL1}
states[S_PLAY_VMPEEL1] = {SPR_PLAY, SPR2_MACH1, 1, nil, 0, 0, S_PLAY_VMPEEL2}
states[S_PLAY_VMPEEL2] = {SPR_PLAY, SPR2_MACH2, 1, nil, 0, 0, S_PLAY_VMPEEL3}
states[S_PLAY_VMPEEL3] = {SPR_PLAY, SPR2_MACH3, 1, nil, 0, 0, S_PLAY_VMPEEL4}
states[S_PLAY_VMPEEL4] = {SPR_PLAY, SPR2_MACH4, 1, nil, 0, 0, S_PLAY_VMPEEL1}
states[S_PLAY_SVMPEEL1] = {SPR_PLAY, SPR2_MACH1, 1, nil, 0, 0, S_PLAY_SVMPEEL2}
states[S_PLAY_SVMPEEL2] = {SPR_PLAY, SPR2_MACH2, 1, nil, 0, 0, S_PLAY_SVMPEEL1}
states[S_PLAY_VMSONICWALLRUN] = {SPR_PLAY, FF_ANIMATE|SPR2_RUN_, 10, nil, 4, 2, S_PLAY_VMSONICWALLRUN}

states[S_PLAY_MACH4] = {
	sprite = SPR_PLAY,
	frame = SPR2_MACH,
	tics = 1,
	nextstate = S_PLAY_MACH4
}

// Sound captions
sfxinfo[sfx_insts].caption = "Insta-Stop"
sfxinfo[sfx_vmdjp].caption = "Double Jump"
sfxinfo[sfx_mach4].caption = "Enter Mach 4"
sfxinfo[sfx_mc4sb].caption = "Sound barrier broken"

// Cool thok effect by TGTLS
local function thokboosteffectidk(p)
	if p.mo.skin == "vmsonic"
	and not (p.pflags & PF_THOKKED)
	    p.mo.state = S_PLAY_ROLL
		local dashmodering = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_VMDASHMODERING)
		dashmodering.color = SKINCOLOR_WHITE
		dashmodering.angle = p.cmd.angleturn << 16 + R_PointToAngle2(0, 0, p.cmd.forwardmove*FRACUNIT, -p.cmd.sidemove*FRACUNIT) + ANGLE_90
		dashmodering.scale = p.mo.scale
		dashmodering.destscale = p.mo.scale
		dashmodering.tics = 3
	end
end
addHook("AbilitySpecial", thokboosteffectidk)

local function extrathokghost(p)
	if p.mo.skin == "vmsonic"
	and(p.pflags & PF_THOKKED)
	and p.mo.state != S_PLAY_VMSONICWALLRUN
		local thokghost = P_SpawnGhostMobj(p.mo)
		thokghost.colorized = true
		thokghost.fuse = 5
		thokghost.color = p.mo.color
		thokghost.blendmode = AST_ADD
	end
end
addHook("PlayerThink", extrathokghost)

//Wallrun by Jesus.B
addHook("MobjMoveBlocked", function(mobj, thing, line)
	if mobj and mobj.valid and line and line.valid and (mobj.player.cmd.buttons & BT_JUMP)
	and not P_IsObjectOnGround(mobj) and not thing and mobj.skin == "vmsonic" then
		P_SetObjectMomZ(mobj,8*FRACUNIT,false)
		P_InstaThrust(mobj, mobj.angle, 5*FRACUNIT)
		mobj.state = S_PLAY_VMSONICWALLRUN
		mobj.player.pflags = $|PF_NOJUMPDAMAGE
		if not S_SoundPlaying(mobj, sfx_s3k7e)
		S_StartSound(mobj, sfx_s3k7e)
		end
		if mobj.player.cmd.sidemove != 0
		P_InstaThrust(mobj, mobj.angle, 0*FRACUNIT)
		end
	end
end, MT_PLAYER)

addHook("MobjMoveBlocked", function(mobj, thing, line)
	if mobj and mobj.valid and line and line.valid and not (mobj.player.cmd.buttons & BT_JUMP) and not (mobj.eflags & MFE_UNDERWATER)
	and not P_IsObjectOnGround(mobj) and not thing and mobj.state == S_PLAY_VMSONICWALLRUN and mobj.skin == "vmsonic" then
		P_Thrust(mobj, mobj.angle, -20*FRACUNIT)
		P_SetObjectMomZ(mobj,10*FRACUNIT,false)
		mobj.state = S_PLAY_JUMP
		mobj.player.pflags = $ & ~ PF_THOKKED
		mobj.player.pflags = $|PF_JUMPED
		S_StartSound(mobj, sfx_jump)
		mobj.angle = R_PointToAngle2(0, 0, mobj.momx, mobj.momy)
	end
end, MT_PLAYER)

addHook("MobjMoveBlocked", function(mobj, thing, line)
	if mobj and mobj.valid and line and line.valid and not (mobj.player.cmd.buttons & BT_JUMP) and (mobj.eflags & MFE_UNDERWATER)
	and not P_IsObjectOnGround(mobj) and not thing and mobj.state == S_PLAY_VMSONICWALLRUN and mobj.skin == "vmsonic" then
		P_Thrust(mobj, mobj.angle, -10*FRACUNIT)
		P_SetObjectMomZ(mobj,5*FRACUNIT,false)
		mobj.state = S_PLAY_JUMP
		mobj.player.pflags = $ & ~ PF_THOKKED
		mobj.player.pflags = $|PF_JUMPED
		S_StartSound(mobj, sfx_jump)
		mobj.angle = R_PointToAngle2(0, 0, mobj.momx, mobj.momy)
	end
end, MT_PLAYER)

addHook ("PlayerThink",function(player)
if player.mo.skin == "vmsonic"
and player.mo.state == S_PLAY_VMSONICWALLRUN
and not S_SoundPlaying(player.mo, sfx_s3k7e)

player.mo.state = S_PLAY_FALL
end
end)

// Dash mode effects by TGTLS
local function dashmodering(p)
	if p.mo.skin == "vmsonic" --put your skin in these p.mo.skin boxes
	and p.dashmode > 3*TICRATE
	and p.canspawnthering == true
		local dashmodering = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_VMDASHMODERING)
		dashmodering.color = p.mo.color
		dashmodering.angle = p.cmd.angleturn << 16 + R_PointToAngle2(0, 0, p.cmd.forwardmove*FRACUNIT, -p.cmd.sidemove*FRACUNIT) + ANGLE_90
		dashmodering.scale = p.mo.scale
		dashmodering.destscale = p.mo.scale
		dashmodering.tics = 3
		p.canspawnthering = false
	end
end

addHook("PlayerThink", dashmodering)

local function givememyringbackplease(p)
	if p.mo.skin == "vmsonic"
	and p.dashmode < 3*TICRATE
		p.canspawnthering = true
	end
end

local function dashmodeghost(p)
	if p.mo.skin == "vmsonic"
	and p.dashmode > 3*TICRATE
		local ghost = P_SpawnGhostMobj(p.mo)
		ghost.colorized = true
		ghost.fuse = 5
		ghost.color = p.mo.color
		ghost.blendmode = AST_ADD
	end
end

addHook("PlayerThink", dashmodeghost)

//Insta-Stop by Jesus.B
addHook("PlayerThink", function(player)
if player.mo.skin == "vmsonic"
and player.playerstate == PST_LIVE
and not P_IsObjectOnGround(player.mo)
and (player.pflags & PF_JUMPED)
and not (player.pflags & PF_THOKKED)
and not P_PlayerInPain(player)
and (player.cmd.buttons & BT_CUSTOM3)
and not player.powers[pw_shield]

P_SetObjectMomZ(player.mo, 0*FRACUNIT, false)
P_InstaThrust(player.mo, player.mo.angle, 0*FRACUNIT)
player.pflags = $|PF_THOKKED
player.pflags = $|PF_NOJUMPDAMAGE
S_StartSound(player.mo, sfx_insts)
player.mo.state = S_PLAY_FALL
end
end)

// Super peelout by MotdSpork
addHook("ThinkFrame", do
	for player in players.iterate
		if not player.mo return end
			if player.mo and player.mo.skin == "vmsonic"
			//CONS_Printf(player, player.mo.peelouttimer)
				player.actionspd = player.normalspeed + 10*FRACUNIT
				if player.mo.state == S_PLAY_STND
					player.normalspeed = 36*FRACUNIT
				end
				if player.mo.peelouttimer == nil
					player.mo.peelouttimer = 0
				end
				if player.mo.peelout == nil
					player.mo.peelout = 0
				end
				if player.mo.peeloutrun == nil
					player.mo.peeloutrun = 0
				end
				if player.mo.peelsound == nil
					player.mo.peelsound = 0
				end
				if player.mo.peelsound2 == nil
					player.mo.peelsound2 = 0
				end
				if player.pflags & PF_SPINNING
					player.mo.peelouttimer = 0
				end
				if (P_PlayerInPain(player))
				or (player.playerstate == PST_DEAD)
					player.normalspeed = 36*FRACUNIT
					player.mo.peelouttimer = 0
					player.mo.peelout = 0
					player.mo.peeloutrun = 0
					player.mo.peelsound = 0
					player.mo.peeloutsound = 0
				end
				if P_IsObjectOnGround(player.mo)
				and player.speed == 0
				and not (player.pflags & PF_SPINNING)
				and player.cmd.buttons & BT_CUSTOM1
			    and not (player.playerstate == PST_DEAD)
					if player.mo.peelsound == 0
						S_StartSound(player.mo, sfx_cdfm11)
						player.mo.peelsound = 1
						
					end
					if player.mo.peelouttimer < 60
						player.mo.peelouttimer = $1 + 1
					end
					player.normalspeed = 0
					player.pflags = $1|PF_STASIS
					if player.drawangle ~= player.mo.angle
						local diff = 0
						local factor = 0
						diff = player.mo.angle - player.drawangle
						factor = 8
						if diff > ANGLE_180
							diff = InvAngle(InvAngle(diff)/(factor or 1))
						else
							diff = $ / (factor or 1)
						end
						player.drawangle = $ + diff
					
					end
					if not (player.mo.eflags & MFE_GOOWATER) then
						for i=(leveltime%7)/2,(leveltime%7) do
							local particle = P_SpawnMobj(player.mo.x, player.mo.y,
							player.mo.z + ((player.mo.eflags & MFE_VERTICALFLIP)/MFE_VERTICALFLIP * (player.mo.height - mobjinfo[MT_SPINDUST].height)),
							MT_SPINDUST)
							if (player.powers[pw_shield] == SH_ELEMENTAL and not (player.mo.eflags & MFE_TOUCHWATER or player.mo.eflags & MFE_UNDERWATER)) then
								particle.state = S_SPINDUST_FIRE1
								particle.bubble = false
							elseif (player.mo.eflags & MFE_TOUCHWATER or player.mo.eflags & MFE_UNDERWATER) then
								particle.state = S_SPINDUST_BUBBLE1
								particle.bubble = true
							else
								particle.state = S_SPINDUST1
								particle.bubble = false
							end
					
							particle.target = player.mo
							particle.eflags = $1 | (player.mo.eflags & MFE_VERTICALFLIP)
							particle.scale = player.mo.scale*2/3
							P_SetObjectMomZ(particle, player.mo.peelouttimer*FRACUNIT/50+P_RandomByte()<<10, false)
							P_InstaThrust(particle, player.mo.angle+(P_RandomRange(-ANG30/FRACUNIT, ANG30/FRACUNIT)*FRACUNIT), FixedMul(-player.mo.peelouttimer*FRACUNIT/12-1*FRACUNIT-P_RandomByte()<<11, player.mo.scale))
							P_TryMove(particle, particle.x+particle.momx, particle.y+particle.momy, true)
						end
					end
				end
			if not (player.cmd.buttons & BT_CUSTOM1) 
				if ((player.mo.peelouttimer >= 1) and (player.mo.peelouttimer <= 35) and not (player.powers[pw_super]))
				or ((player.mo.peelouttimer >= 1) and (player.mo.peelouttimer <= 14) and (player.powers[pw_super]))
					player.normalspeed = 36*FRACUNIT
					player.mo.state = 14
					player.mo.peelouttimer = 0
					player.mo.peelsound = 0
				end
			end
			
			if player.powers[pw_super] == 0
				if player.mo.peelouttimer >= 1
				and player.mo.peelouttimer <= 30
					if not (player.mo.state >= S_PLAY_VMPWALK1)
					and (player.mo.state <= S_PLAY_VMPWALK16)
						player.mo.state = S_PLAY_VMPWALK1
					end
				end
				if player.mo.peelouttimer >= 31
					if not ((player.mo.state >= S_PLAY_VMPEEL1) and (player.mo.state <= S_PLAY_VMPEEL4))
					or ((player.mo.state >= S_PLAY_VMPWALK1) and (player.mo.state <= S_PLAY_VMPWALK16))
						player.mo.state = S_PLAY_VMPEEL1
					end
				end
			else
				if player.mo.peelouttimer >= 1
				and player.mo.peelouttimer <= 14
					if not (player.mo.state >= S_PLAY_VMPWALK8)
					and (player.mo.state <= S_PLAY_VMPWALK16)
						player.mo.state = S_PLAY_VMPWALK8
					end
				end
				if player.mo.peelouttimer >= 15
					if not (player.mo.state >= S_PLAY_SVMPEEL1)
					and (player.mo.state <= S_PLAY_SVMPEEL2)
						player.mo.state = S_PLAY_SVMPEEL1
					end
				end
			end
			if not (player.cmd.buttons & BT_CUSTOM1)
				if ((player.mo.peelouttimer >= 31) and not (player.powers[pw_super]))
				or ((player.mo.peelouttimer >= 15) and (player.powers[pw_super]))
					if player.mo.peelsound == 1
						player.mo.state = S_PLAY_RUN
						S_StartSound(player.mo, sfx_cdfm01)
						player.mo.peelsound = 0
						player.mo.peelout = 1
					end
					P_InstaThrust(player.mo, player.mo.angle, FixedMul(60*FRACUNIT, player.mo.scale))
					player.mo.peelouttimer = 0
					player.drawangle = player.mo.angle
				end
				
			end
			if player.speed > 45*FRACUNIT
			and player.mo.peelout == 1
				player.dashmode = 3*TICRATE
				player.mo.peeloutrun = 1
				player.normalspeed = 60*FRACUNIT
			end
			if player.speed <= 45*FRACUNIT
			and player.mo.peeloutrun == 1
				player.mo.peelout = 0
				player.mo.peeloutrun = 0
				player.normalspeed = 36*FRACUNIT
			end
			if player.mo.peelout == 1
				player.charflags = $1|SF_RUNONWATER
			else
				player.charflags = $1 & ~SF_RUNONWATER
			end
			if player.pflags & PF_JUMPED
				if ((player.mo.state >= S_PLAY_VMPWALK1) and (player.mo.state <= S_PLAY_VMPWALK16))
				or ((player.mo.state >= S_PLAY_VMPEEL1) and (player.mo.state <= S_PLAY_VMPEEL4))
				or ((player.mo.state >= S_PLAY_SVMPEEL1) and (player.mo.state <= S_PLAY_SVMPEEL2))
					player.mo.state = S_PLAY_ROLL
				end
				if player.normalspeed == 0*FRACUNIT
					player.normalspeed = 36*FRACUNIT
				end
				player.mo.peelouttimer = 0
				player.mo.peelsound = 0
				player.mo.peelsound2 = 0
			end
		end
	end
end)

// Double Jump by Jesus.B
addHook("PlayerThink", function(player)
if player.mo.skin == "vmsonic"
and (player.cmd.buttons & BT_CUSTOM1) 
and not P_IsObjectOnGround(player.mo) 
and not (player.pflags & PF_THOKKED) 
and (player.pflags & PF_JUMPED)

S_StartSound(player.mo, sfx_vmdjp)
P_SpawnThokMobj(player)
P_SetObjectMomZ(player.mo, 10*FRACUNIT, false)
player.mo.state = S_PLAY_JUMP
player.pflags = $|PF_THOKKED
for i = 1, 6
local dust = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_SPINDUST)
dust.angle = ANG60*i
P_InstaThrust(dust, dust.angle, 15*FRACUNIT)
end
end
end)

// Light dash by MIDIMan (modified by tedvin11, then FlyNickNick77 to light dash on blue spheres)
local MAXMOVE = 60*FRACUNIT/NEWTICRATERATIO

local function P_FDLightDash(source, enemy) // Home in on your target
	if not (source and source.valid
	and enemy and enemy.valid)
		return
	end
	
	local dist
	local dest
	
	if not (source.tracer and source.tracer.valid)
		return // Nothing to home in on!
	end
	
	// adjust direction
	dest = source.tracer
	
	if not dest
		return
	end
	
	// change angle
	source.angle = R_PointToAngle2(source.x, source.y, enemy.x, enemy.y)
	if source.player and source.player.valid
		source.player.drawangle = source.angle
	end
	
	// change slope
	dist = P_AproxDistance(P_AproxDistance(dest.x - source.x, dest.y - source.y), dest.z - source.z)
	
	if dist < 1
		dist = 1
	end
	
	local playerdistx = FixedDiv((dest.x - source.x), dist)
	local playerdisty = FixedDiv((dest.y - source.y), dist)
	local playerdistz = FixedDiv((dest.z - source.z), dist)
	
	local maxMoveScaled = FixedMul(MAXMOVE, source.scale)
	
	source.momx = FixedTrunc(FixedMul(playerdistx, maxMoveScaled))
	source.momy = FixedTrunc(FixedMul(playerdisty, maxMoveScaled))
	source.momz = FixedTrunc(FixedMul(playerdistz, maxMoveScaled))
end

local function P_LookForRings(player)
	local found = false
	
	player.mo.target = nil
	player.mo.tracer = nil
	
	searchBlockmap("objects", function(pmo, mo)
		if mo.health <= 0 or mo.state == S_NULL
			return
		end
		
		if not (mo.type == MT_RING or mo.type == MT_COIN or mo.type == MT_BLUESPHERE or mo.info.fdadvRing)
			return
		end
		
		if P_AproxDistance(P_AproxDistance(pmo.x-mo.x, pmo.y-mo.y),
			pmo.z-mo.z) > 192*pmo.scale
			return
		end
		
		if not P_CheckSight(pmo, mo)
			return
		end
		
		if pmo.target and P_AproxDistance(P_AproxDistance(pmo.x-mo.x,
			pmo.y-mo.y), pmo.z-mo.z) > 
			P_AproxDistance(P_AproxDistance(pmo.x-pmo.target.x,
			pmo.y-pmo.target.y), pmo.z-pmo.target.z)
			return
		end
		
		found = true
		pmo.target = mo
		pmo.tracer = mo
	end, player.mo,
	player.mo.x - 192*player.mo.scale, player.mo.x + 192*player.mo.scale,
	player.mo.y - 192*player.mo.scale, player.mo.y + 192*player.mo.scale)
	
	if found
		P_ResetPlayer(player)
		player.fdhoming = 0
		player.mo.state = S_PLAY_GLIDE
		P_ResetScore(player)
		P_FDLightDash(player.mo, player.mo.target)
		return
	end
	player.mo.momx = $/2
	player.mo.momy = $/2
	player.mo.momz = $/2
	player.fdlightdash = false
end

local function P_RingNearby(player) 
	local closest = nil

	searchBlockmap("objects", function(pmo, mo)
		if mo.health <= 0 or mo.state == S_NULL
			return
		end
		
		if not (mo.type == MT_RING or mo.type == MT_COIN or mo.type == MT_BLUESPHERE or mo.info.fdadvRing)
			return
		end
		
		if P_AproxDistance(P_AproxDistance(pmo.x-mo.x, pmo.y-mo.y),
			pmo.z-mo.z) > 192*pmo.scale // Out of range
			return
		end
		
		if not P_CheckSight(pmo, mo) // Out of sight
			return
		end
		
		if closest and P_AproxDistance(P_AproxDistance(pmo.x-mo.x, pmo.y-mo.y),
			pmo.z-mo.z) > P_AproxDistance(P_AproxDistance(pmo.x-closest.x,
			pmo.y-closest.y), pmo.z-closest.z)
			return
		end
		
		// Found a target
		closest = mo
	end, player.mo,
	player.mo.x - 192*player.mo.scale, player.mo.x + 192*player.mo.scale,
	player.mo.y - 192*player.mo.scale, player.mo.y + 192*player.mo.scale)
	
	if closest
		return true
	end
	
	return false
end

addHook("PlayerThink", function(player)
	if player.mo.skin == "vmsonic" and (player.cmd.buttons & BT_TOSSFLAG) then
		if P_RingNearby(player) then
			if player.mo.state != S_PLAY_DEAD or player.mo.state != S_PLAY_HURT then
				player.fdlightdash = TICRATE
			end
		end
	end
	if player.fdlightdash > 0 then
		P_LookForRings(player)
		player.fdlightdash = player.fdlightdash - 1
	end
	if not P_RingNearby(player) then
		player.fdlightdash = 0
	end
	if player.mo.state == S_PLAY_HURT then
		player.fdlightdash = 0
	end
end)
addHook("TouchSpecial", function(special, toucher)
	if not (special and special.valid
	and toucher and toucher.valid
	and toucher.player and toucher.player.valid)
		return
	end
	
	if special.type == MT_RING
	or special.type == MT_COIN
	or special.type == MT_BLUESPHERE
		if toucher.player.fdlightdash
			toucher.player.fdlightdash = TICRATE
		end
	end
end)

//Dropdash fix for Super form by Jesus.B
addHook ("PlayerThink",function(player)
if player.mo.skin != "vmsonic" return end
if player.mo
and not P_IsObjectOnGround(player.mo)
and player.cmd.buttons & BT_SPIN
and player.powers[pw_super]

player.charability = CA_NONE
else
player.charability = CA_THOK
end
end)

//Paper Peelout by [REDACTED]

addHook("MobjThinker", function(mobj)
	if mobj and mobj.valid and mobj.target and mobj.target.valid and (mobj.target.skin == "vmsonic" or mobj.target.skin == "vmamy")
	   mobj.target.player.vmpeelghosts = mobj
	   mobj.target.player.vmpeelghosts.fuse = mobj.fuse
	end
end, MT_GHOST)

addHook("ThinkFrame", do
	for player in players.iterate
		if (player and player.mo and player.mo.valid) and (player.mo.skin == "vmsonic" or player.mo.skin == "vmamy")
			if player.mo.state == S_PLAY_MACH4 or (player.mo.state >= S_PLAY_VMPEEL1 and player.mo.state <= S_PLAY_SVMPEEL2)
			and not player.powers[pw_super]
				for i = -40, 40
					
					local force = i*FRACUNIT/3
					local angle = ANGLE_90

					local shiftx = FixedMul(cos(player.drawangle + angle), force)
					local shifty = FixedMul(sin(player.drawangle + angle), force)
					
					local shiftx2 = FixedMul(cos(player.drawangle), FRACUNIT)
					local shifty2 = FixedMul(sin(player.drawangle), FRACUNIT)
					
					if i > 20
					or i < -20
						local peelout = P_SpawnMobjFromMobj(player.mo, shiftx2 + shiftx, shifty2 + shifty, 0, MT_OVERLAY)
						peelout.target = player.mo
						peelout.fuse = 1
						peelout.sprite = SPR_VMPL
						if i < 0
							if player.mo.frame == A
								peelout.frame = A
							elseif player.mo.frame == B
								peelout.frame = B
							elseif player.mo.frame == C
								peelout.frame = C
							elseif player.mo.frame == D
								peelout.frame = D
							end
							peelout.angle = player.drawangle + ANGLE_90/6
						else
							if player.mo.frame == A
								peelout.frame = C
							elseif player.mo.frame == B
								peelout.frame = D
							elseif player.mo.frame == C
								peelout.frame = A
							elseif player.mo.frame == D
								peelout.frame = B
							end
							peelout.angle = player.drawangle - ANGLE_90/6
						end
						peelout.renderflags = RF_PAPERSPRITE
						peelout.scale = player.mo.scale/2
						if player.mo.eflags & MFE_VERTICALFLIP
							peelout.eflags = $ | MFE_VERTICALFLIP
							peelout.z = player.mo.z + player.mo.height - peelout.height
						end
						if player.vmpeelghosts and player.vmpeelghosts.valid and player.vmpeelghosts.fuse and not player.powers[pw_super]
						local ghostpeel = P_SpawnMobjFromMobj(player.vmpeelghosts, shiftx2 + shiftx, shifty2 + shifty, 0, MT_GHOST)
						ghostpeel.fuse = player.vmpeelghosts.fuse
						ghostpeel.sprite = SPR_VMPL
						if i < 0
							if player.mo.frame == A
								ghostpeel.frame = A
							elseif player.mo.frame == B
								ghostpeel.frame = B
							elseif player.mo.frame == C
								ghostpeel.frame = C
							elseif player.mo.frame == D
								ghostpeel.frame = D
							end
							ghostpeel.angle = player.drawangle + ANGLE_90/6
						else
							if player.mo.frame == A
								ghostpeel.frame = C
							elseif player.mo.frame == B
								ghostpeel.frame = D
							elseif player.mo.frame == C
								ghostpeel.frame = A
							elseif player.mo.frame == D
								ghostpeel.frame = B
							end
							ghostpeel.angle = player.drawangle - ANGLE_90/6
						end
						ghostpeel.renderflags = RF_PAPERSPRITE
						ghostpeel.scale = player.mo.scale/2
						if player.mo.eflags & MFE_VERTICALFLIP
							ghostpeel.eflags = $ | MFE_VERTICALFLIP
							ghostpeel.z = player.mo.z + player.mo.height - ghostpeel.height
						end
						end
					end					
				end
			end
		end
	end
end)