-- Voidy's Stuff --

rawset(_G, "P_IsClimbingValid",function(player, angle)
	local platx, platy
	local glidesector
	local floorz, ceilingz
	local mo = player.mo
	local rover
	platx = P_ReturnThrustX(mo, angle, mo.radius + FixedMul(8*FRACUNIT, mo.scale))
	platy = P_ReturnThrustY(mo, angle, mo.radius + FixedMul(8*FRACUNIT, mo.scale))
	glidesector = R_PointInSubsector(mo.x + platx, mo.y + platy).sector
	floorz = glidesector.floorheight
	ceilingz = glidesector.ceilingheight
	if (glidesector ~= mo.subsector.sector)
		local floorclimb = false
		local topheight, bottomheight
		for rover in glidesector.ffloors()
			if (not (rover.flags & FF_EXISTS) or not (rover.flags & FF_BLOCKPLAYER))
				continue
			end
			topheight = rover.topheight
			bottomheight = rover.bottomheight
			floorclimb = true
			if (mo.eflags & MFE_VERTICALFLIP)
				if ((topheight < mo.z + mo.height) and ((mo.z + mo.height + mo.momz) < topheight))
					floorclimb = true
				end
				if (topheight < mo.z)
					floorclimb = false
				end
				if (bottomheight > mo.z + mo.height - FixedMul(16*FRACUNIT,mo.scale))
					floorclimb = false
				end
			else
				if ((bottomheight > mo.z) and ((mo.z - mo.momz) > bottomheight))
					floorclimb = true
				end
				if (bottomheight > mo.z + mo.height)
					floorclimb = false
				end
				if (topheight < mo.z + FixedMul(16*FRACUNIT,mo.scale))
					floorclimb = false
				end
			end
			if (floorclimb)
				break
			end
		end
		if (mo.eflags & MFE_VERTICALFLIP)
			if ((floorz <= mo.z + mo.height)
				and ((mo.z + mo.height - mo.momz) <= floorz))
				floorclimb = true
			end
			if ((floorz > mo.z)
				and glidesector.floorpic == "F_SKY1")
				return false
			end
			if ((mo.z + mo.height - FixedMul(16*FRACUNIT,mo.scale) > ceilingz)
				or (mo.z + mo.height <= floorz))
				floorclimb = true
			end
		else
			if ((ceilingz >= mo.z)
				and ((mo.z - mo.momz) >= ceilingz))
				floorclimb = true
			end
			if ((ceilingz < mo.z+mo.height)
				and glidesector.ceilingpic == "F_SKY1")
				return false
			end
			if ((mo.z + FixedMul(16*FRACUNIT,mo.scale) < floorz)
				or (mo.z >= ceilingz))
				floorclimb = true
			end
		end
		if (not floorclimb)
			return false
		end
		return true
	else
		return true
	end
	return false
end)
rawset(_G,"PTR_GlideClimbTraverse",function(slidemo,li)
	local checkline = li
	local rover
	local topheight, bottomheight
	local fofline = false
	local checksector = (li.backsector and not P_PointOnLineSide(slidemo.x, slidemo.y, li)) and li.backsector or li.frontsector
	if (checksector.ffloors)
		for rover in checksector.ffloors()
			if (not(rover.flags & FF_EXISTS) or not(rover.flags & FF_BLOCKPLAYER) or ((rover.flags & FF_BUSTUP) and (slidemo.player.charflags & SF_CANBUSTWALLS)))
				continue
			end
			topheight = rover.topheight
			bottomheight = rover.bottomheight
			if (topheight < slidemo.z)
				continue
			end
			if (bottomheight > slidemo.z + slidemo.height)
				continue
			end
			if (rover.master.flags & ML_TFERLINE)
				local linenum = checksector.lines[0]
				checkline = rover.master.frontsector.lines[0] + linenum
				fofline = true
			end
			break
		end
	end
	local canclimb
	local climbangle, climbline
	local whichside = P_PointOnLineSide(slidemo.x, slidemo.y, li)
	climbangle = R_PointToAngle2(li.v1.x, li.v1.y, li.v2.x, li.v2.y)
	climbline = climbangle
	if (whichside)
		climbline = $+ ANGLE_180
	end
	climbangle = $+ (ANGLE_90 * (whichside and -1 or 1))
	canclimb = (li.backsector and P_IsClimbingValid(slidemo.player, climbangle) or true)
	if (((not slidemo.player.climbing and abs((slidemo.angle - ANGLE_90 - climbline)) < ANGLE_45)
	or (slidemo.player.climbing == 1 and abs((slidemo.angle - climbline)) < ANGLE_135))
	and canclimb) 
		return true,climbangle
	end
	return false,0
end)

local function VoidyCheckAndCrumble(mo, sec)
  for fof in sec.ffloors()
    if not (fof.flags & FF_EXISTS) then continue end
    if not (fof.flags & FF_BUSTUP) then continue end
    if mo.z + mo.height < fof.bottomheight then continue end 
    if mo.z > fof.topheight then continue end
    EV_CrumbleChain(fof)
  end
end
local function VoidyCrumbleCollide(mo, line)
	for _, sec in ipairs({line.frontsector, line.backsector})
		VoidyCheckAndCrumble(mo, sec)
	end
end

local function VoidyBlockMap(fuckyou)
	if fuckyou and fuckyou.valid and (fuckyou.flags & (MF_MISSILE|MF_NOBLOCKMAP)) == (MF_MISSILE|MF_NOBLOCKMAP) 
		if fuckyou.type ~= MT_IMPACTSHOCKWAVE
			fuckyou.flags = $ & ~MF_NOBLOCKMAP
		end
	end
end

local function DoLFGain(player, initial)
	if initial == nil
		initial = 1
	end
	if player.lifeforce < player.maxlifeforce
		if player.topazcollected == 1
			player.lifeforce = $ + initial*2
		else
			player.lifeforce = $ + initial
		end
	end
end

local function BasicShredderThink(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_SHOOTABLE and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 1)
				end
			end
			if (found.valid and found.flags & MF_MISSILE)
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				if src.type == MT_PLAYER
					DoLFGain(src.player)
				end
				P_RemoveMobj(found)
			end
			if (found.valid and found.type == MT_EGGSHIELD) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				P_KillMobj(found, mo, src)
			end
			if (found.valid and found.type == MT_METALSONIC_BATTLE) 
			and found.state == found.info.spawnstate
			and not (found.flags2 & MF2_CLASSICPUSH) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
		VoidyCheckAndCrumble(mo, mo.subsector.sector)
	end
end

local function ValidSpikeKiller(mobj)
	if (mobj.type == MT_IMPACTSHOCKWAVE 
	or mobj.type == MT_RIGHTSHREDDER 
	or mobj.type == MT_LEFTSHREDDER 
	or mobj.type == MT_DUALSHREDDER 
	or mobj.type == MT_ENERGYPILLAR 
	or mobj.type == MT_FRENZY_RIGHTSHREDDER 
	or mobj.type == MT_FRENZY_LEFTSHREDDER 
	or mobj.type == MT_FRENZY_DUALSHREDDER 
	or mobj.type == MT_FRENZY_ENERGYPILLAR 
	or mobj.type == MT_VOIDYBLACKHOLE 
	or (mobj.type == MT_FRENZYEXPLOSION and mobj.state == S_FRENZYEXPL7))
		return true
	else
		return false
	end
end
local function VoidyKillSpikes(thing, tmthing)
	if thing and thing.valid and tmthing and tmthing.valid
	and ValidSpikeKiller(tmthing) 
	and thing.z - thing.scale <= tmthing.z + tmthing.height + (tmthing and P_MobjFlip(tmthing) or tmthing.momz)
	and thing.z + thing.height + thing.scale >= tmthing.z + (tmthing and P_MobjFlip(tmthing) or tmthing.momz)
		P_KillMobj(thing, tmthing)
		return true
	end
end

rawset(_G, "VoidyFakeNoClip", function(mo)
	P_SetOrigin(mo, mo.x + mo.momx, mo.y + mo.momy, mo.z + mo.momz)
    return
	true
end)

rawset(_G, "ValidVoidyObject", function(mobj)
	if (mobj.type == MT_RING 
	or mobj.type == MT_FLINGRING 
	or mobj.type == MT_COIN 
	or mobj.type == MT_FLINGCOIN 
	or mobj.type == MT_BLUESPHERE 
	or mobj.type == MT_FLINGBLUESPHERE 
	or mobj.flags & MF_ENEMY 
	or mobj.flags & MF_MONITOR 
	or mobj.flags & MF_MISSILE 
	or mobj.type == MT_PLAYER)
		return true
	else
		return false
	end
end)
rawset(_G, "VoidyAttract", function(mo, target, speed, xoffs, yoffs, zoffs)
	xoffs = $ or 0
	yoffs = $ or 0
	zoffs = $ or 0
	local newx = target.x + xoffs
	local newy = target.y + yoffs
	local newz = target.z + zoffs
	local dist = R_PointToDist2(0, 0, R_PointToDist2(mo.x, mo.y, newx, newy), newz - mo.z)
	if speed < dist
		mo.momx = FixedMul(FixedDiv(newx - mo.x, dist), speed)
		mo.momy = FixedMul(FixedDiv(newy - mo.y, dist), speed)
		mo.momz = FixedMul(FixedDiv(newz - mo.z, dist), speed)
	elseif speed > dist
		mo.momx = 0
		mo.momy = 0
		mo.momz = 0
		P_SetOrigin(mo, newx, newy, newz)
	end
end)

local function FrenzyShredderThink(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_SHOOTABLE and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 2)
				end
			end
			if (found.valid and found.flags & MF_MISSILE)
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				if src.type == MT_PLAYER
					DoLFGain(src.player)
				end
				P_RemoveMobj(found)
			end
			if (found.valid and found.type == MT_EGGSHIELD) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				P_KillMobj(found, mo, src)
			end
			if (found.valid and found.type == MT_METALSONIC_BATTLE) 
			and found.state == found.info.spawnstate
			and not (found.flags2 & MF2_CLASSICPUSH) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
		VoidyCheckAndCrumble(mo, mo.subsector.sector)
		if mo.type == MT_ENERGYTSUNAMI
			if mo.state == S_ENERGYTSUNAMI2 
			or mo.state == S_ENERGYTSUNAMI4
				mo.height = 128*FRACUNIT
			end
			if mo.state == S_ENERGYTSUNAMI3
				mo.height = 192*FRACUNIT
			end
			if mo.state == S_ENERGYTSUNAMI5
				mo.height = 64*FRACUNIT
			end
		end
	end
end

local frenzyspritechange = {}
frenzyspritechange[SPR2_GLID] = SPR2_FGLI
frenzyspritechange[SPR2_JUMP] = SPR2_TAL5
frenzyspritechange[SPR2_FALL] = SPR2_TAL7
frenzyspritechange[SPR2_LAND] = SPR2_FLAN
frenzyspritechange[SPR2_SPNG] = SPR2_TAL6
frenzyspritechange[SPR2_ROLL] = SPR2_TAL4
frenzyspritechange[SPR2_PAIN] = SPR2_TAL3
frenzyspritechange[SPR2_GASP] = SPR2_TAL8
frenzyspritechange[SPR2_RIDE] = SPR2_TALA
frenzyspritechange[SPR2_STND] = SPR2_TAL0
frenzyspritechange[SPR2_WAIT] = SPR2_TAL0
frenzyspritechange[SPR2_WALK] = SPR2_TAL1
frenzyspritechange[SPR2_RUN_] = SPR2_TAL2
frenzyspritechange[SPR2_EDGE] = SPR2_TAL9
frenzyspritechange[SPR2_SPIN] = SPR2_FSPI
frenzyspritechange[SPR2_CLNG] = SPR2_FCLN
frenzyspritechange[SPR2_TIRE] = SPR2_FBFL
frenzyspritechange[SPR2_BLND] = SPR2_FBLD
local frenzyspriterestore = {}
frenzyspriterestore[SPR2_FGLI] = SPR2_GLID
frenzyspriterestore[SPR2_TAL5] = SPR2_JUMP
frenzyspriterestore[SPR2_TAL7] = SPR2_FALL
frenzyspriterestore[SPR2_FLAN] = SPR2_LAND
frenzyspriterestore[SPR2_TAL6] = SPR2_SPNG
frenzyspriterestore[SPR2_TAL4] = SPR2_ROLL
frenzyspriterestore[SPR2_TAL3] = SPR2_PAIN
frenzyspriterestore[SPR2_TAL8] = SPR2_GASP
frenzyspriterestore[SPR2_TALA] = SPR2_RIDE
frenzyspriterestore[SPR2_TAL0] = SPR2_STND
frenzyspriterestore[SPR2_TAL1] = SPR2_WALK
frenzyspriterestore[SPR2_TAL2] = SPR2_RUN_
frenzyspriterestore[SPR2_TAL9] = SPR2_EDGE
frenzyspriterestore[SPR2_FSPI] = SPR2_SPIN
frenzyspriterestore[SPR2_FCLN] = SPR2_CLNG
frenzyspriterestore[SPR2_FBFL] = SPR2_TIRE
frenzyspriterestore[SPR2_FBLD] = SPR2_BLND

local function VoidySuperTrans(player)
    if ((player.mo.state == S_PLAY_SUPER_TRANS1) 
	or (player.mo.state == S_PLAY_SUPER_TRANS2) 
	or (player.mo.state == S_PLAY_SUPER_TRANS3) 
	or (player.mo.state == S_PLAY_SUPER_TRANS4) 
	or (player.mo.state == S_PLAY_SUPER_TRANS5) 
	or (player.mo.state == S_PLAY_SUPER_TRANS6))
        return true
    else
        return false
    end
end

local function VoidySuperCheck(player)
    if not P_IsObjectOnGround(player.mo) and player.rings >= 50 and All7Emeralds(emeralds) and not player.powers[pw_super] and (player.playerstate == PST_LIVE)
    and (skins[player.mo.skin].flags & SF_SUPER)
    and not (player.cmd.buttons & BT_USE)
    and not (player.pflags & PF_THOKKED) and not (mapheaderinfo[gamemap].typeoflevel & TOL_NIGHTS) and not (player.pflags & PF_SHIELDABILITY) and (player.pflags & PF_JUMPED) and not VoidySuperTrans(player)
    and not VoidySuperTrans(player)
    and ((player.powers[pw_shield] == 0) or (player.powers[pw_shield] > 0)) 
	and (player.frenzied == 0)
    then
        return true
    else
        return false
    end
end

local function VoidySuper(player)
    player.pflags = $ & ~PF_JUMPED
    player.charflags = $1 | SF_SUPER
	P_DoSuperTransformation(player, false)
end

rawset(_G, "saveVoidyData", function(p)
	local array = {
		p.lifeforce,
		p.maxlifeforce,
		p.shard1collected,
		p.shard2collected,
		p.shard3collected,
		p.shard4collected,
		p.selenitecollected,
		p.carneliancollected,
		p.tourmalinecollected,
		p.topazcollected,
		p.garnetcollected,
		p.moonstonecollected,
		p.allupgradesnotif
	}
	local savestring = ""
	for i=1, #array do
		savestring = $ .. tostring(array[i]) .. "\n"
	end
	local save = io.openlocal("client/VoidyChars/voidy_stats.dat", "w+")
	save:write(savestring)
	save:flush()
	save:close()
end)
local function loadVoidyData(p)
	local array = {}
	local save = io.openlocal("client/VoidyChars/voidy_stats.dat", "r+")
	for line in save:lines() do
		table.insert(array, tonumber(line))
	end
	p.lifeforce = array[1]
	p.maxlifeforce = array[2]
	p.shard1collected = array[3]
	p.shard2collected = array[4]
	p.shard3collected = array[5]
	p.shard4collected = array[6]
	p.selenitecollected = array[7]
	p.carneliancollected = array[8]
	p.tourmalinecollected = array[9]
	p.topazcollected = array[10]
	p.garnetcollected = array[11]
	p.moonstonecollected = array[12]
	p.allupgradesnotif = array[13]
	save:close()
end

local function VoidyVariableReset(player, health)
	if (player.voidyvars == nil)
		player.voidyvars = {}
	end
	player.impacttimer = 0
	player.dodgeroll = 0
	player.attackcount = 0
	player.attacktimer = 0
	player.finishertimer = 0
	player.voidycharge = 0
	player.stilltimer = 0
	player.dancercount = 0
	player.attacking = 0
	player.transforming = 0
	player.frenzied = 0
	player.frenzyfallframe = 0
	player.frenzyrollframe = 0
	player.frenzystandframe = 0
	player.frenzywalkframe = 0
	player.frenzyrunframe = 0
	player.frenzyedgeframe = 0
	player.chasertimer = 0
	player.guardtimer = 0
	player.diveconfirm = false
	player.airconfirm = false
	player.spinconfirm = false
	player.slash1spawned = false
	player.slash2spawned = false
	player.succconfirm = false
	player.chargedairconfirm = false
	player.spawnedclone = false
	player.cloneconfirm = false
	player.rocksspawned = false
	player.didaircombo = false
	player.diduppercut = false
	player.spawnedpillar = false
	player.tsunamispawned = false
	player.blastspawned = false
	player.frenzymusic = 1
	player.lifeforce = 0
	player.maxlifeforce = 80
	player.shard1collected = 0
	player.shard2collected = 0
	player.shard3collected = 0
	player.shard4collected = 0
	player.selenitecollected = 0
	player.carneliancollected = 0
	player.tourmalinecollected = 0
	player.topazcollected = 0
	player.garnetcollected = 0
	player.moonstonecollected = 0
	player.allupgradesnotif = 0
	player.battlewait = false
	player.activatedstance = false
	player.stanced = false
	player.stancetimer = 0
	player.shotpulse = false
	player.shotstream = false
	player.hadrings = false
	player.nailtimer = 0
	if io and player == consoleplayer
		local file1 = io.openlocal("client/VoidyChars/voidy_music.dat", "r+")
		if file1
			player.frenzymusic = file1:read("*n")
			file1:close()
		end
		local file2 = io.openlocal("client/VoidyChars/voidy_stats.dat", "r+")
		if file2
			loadVoidyData(player)
		end
	end
end
addHook("MapLoad", function()
	for player in players.iterate
		VoidyVariableReset(player, false)
	end
end)

addHook("JumpSpecial", function(player)
	local mo = player.mo
	if mo.skin == "voidy"
		if player.powers[pw_super] and player.pflags & PF_THOKKED
			P_SetObjectMomZ(mo, 0*FRACUNIT)
		end
	end
end)

addHook("SpinSpecial", function(player)
	local mo = player.mo
	if mo.skin == "voidy"
		if player.powers[pw_super] and player.pflags & PF_JUMPED
			P_SetObjectMomZ(mo, 10*FRACUNIT)
			mo.state = S_PLAY_JUMP
		end
	end
end)

addHook("AbilitySpecial", function(player)
	local mo = player.mo
	if mo.skin == "voidy"
		if not player.powers[pw_super] 
		and not (player.mo.eflags & MFE_GOOWATER) 
		and not (srb2p and server.P_BattleStatus and player.P_party and server.P_BattleStatus[player.P_party].running)
			mo.state = S_PLAY_GLIDE
			return true
		end
	end
end)

local function VoidyFrameStuff(mo)
	if mo.state == S_BASIC_GROUNDRIGHT2 
	or mo.state == S_BASIC_AIRRIGHT2 
	or mo.state == S_FRENZY_GROUNDRIGHT2 
	or mo.state == S_FRENZY_AIRRIGHT2
		mo.frame = B
	end
	if mo.state == S_BASIC_GROUNDRIGHT3
	or mo.state == S_BASIC_AIRRIGHT3 
	or mo.state == S_FRENZY_GROUNDRIGHT3 
	or mo.state == S_FRENZY_AIRRIGHT3
		mo.frame = C
	end
	if mo.state == S_BASIC_GROUNDLEFT2 
	or mo.state == S_BASIC_AIRLEFT2 
	or mo.state == S_FRENZY_GROUNDLEFT2 
	or mo.state == S_FRENZY_AIRLEFT2
		mo.frame = E
	end
	if mo.state == S_BASIC_GROUNDLEFT3 
	or mo.state == S_BASIC_AIRLEFT3 
	or mo.state == S_FRENZY_GROUNDLEFT3 
	or mo.state == S_FRENZY_AIRLEFT3
		mo.frame = F
	end
	if mo.state == S_BASIC_GROUNDFINISHA2
	or mo.state == S_BASIC_AIRFINISHA2 
	or mo.state == S_FRENZY_GROUNDFINISHA2 
	or mo.state == S_FRENZY_AIRFINISHA2
		mo.frame = H
	end
	if mo.state == S_BASIC_GROUNDFINISHA3 
	or mo.state == S_BASIC_AIRFINISHA3 
	or mo.state == S_FRENZY_GROUNDFINISHA3 
	or mo.state == S_FRENZY_AIRFINISHA3 
	or mo.state == S_BASIC_ENTERSTANCE 
	or mo.state == S_FRENZY_ENTERSTANCE
		mo.frame = I
	end
	if mo.state == S_PLAY_EARTHSPIKER1 
	or mo.state == S_PLAY_CRESCENTDANCER1 
	or mo.state == S_PLAY_EARTHSCORCHER1 
	or mo.state == S_PLAY_CRESCENTREAPER1
		mo.frame = J
	end
	if mo.state == S_PLAY_EARTHSPIKER2 
	or mo.state == S_PLAY_CRESCENTDANCER2 
	or mo.state == S_PLAY_EARTHSCORCHER2 
	or mo.state == S_PLAY_CRESCENTREAPER2
		mo.frame = K
	end
	if mo.state == S_PLAY_EARTHSPIKER3 
	or mo.state == S_PLAY_CRESCENTDANCER3 
	or mo.state == S_PLAY_EARTHSCORCHER3 
	or mo.state == S_PLAY_CRESCENTREAPER3
		mo.frame = L
	end
	if mo.state == S_PLAY_CRESCENTDANCER4 
	or mo.state == S_PLAY_VACUUMGULLET1 
	or mo.state == S_PLAY_VACUUMREVERT3 
	or mo.state == S_PLAY_CRESCENTREAPER4 
	or mo.state == S_PLAY_VORTEXGULLET1 
	or mo.state == S_PLAY_VORTEXREVERT3
		mo.frame = M
	end
	if mo.state == S_PLAY_VACUUMGULLET2 
	or mo.state == S_PLAY_VACUUMREVERT2 
	or mo.state == S_PLAY_VORTEXGULLET2 
	or mo.state == S_PLAY_VORTEXREVERT2 
	or mo.state == S_BASIC_AIRFINISHB1 
	or mo.state == S_FRENZY_AIRFINISHB1
		mo.frame = N
	end
	if mo.state == S_PLAY_VACUUMGULLET3 
	or mo.state == S_PLAY_VACUUMGULLET4 
	or mo.state == S_PLAY_VACUUMREVERT1 
	or mo.state == S_PLAY_VORTEXGULLET3 
	or mo.state == S_PLAY_VORTEXGULLET4 
	or mo.state == S_PLAY_VORTEXREVERT1 
	or mo.state == S_BASIC_AIRFINISHB2 
	or mo.state == S_FRENZY_AIRFINISHB2
		mo.frame = O
	end
	if mo.state == S_BASIC_AIRFINISHB3 
	or mo.state == S_FRENZY_AIRFINISHB3
		mo.frame = P
	end
	if mo.state == S_BASIC_GROUNDFINISHB1 
	or mo.state == S_FRENZY_GROUNDFINISHB1
		mo.frame = Q
	end
	if mo.state == S_BASIC_GROUNDFINISHB2 
	or mo.state == S_FRENZY_GROUNDFINISHB2
		mo.frame = R
	end
	if mo.state == S_BASIC_GROUNDFINISHB3 
	or mo.state == S_FRENZY_GROUNDFINISHB3
		mo.frame = S
	end
end

COM_AddCommand("voidy_frenzymusic", function(p, arg)
	if p.mo and p.mo.valid then
		if p.mo.skin == "voidy" then
			if p.frenzied == 0 then
				if arg ~= nil
					arg = arg:lower()
					if arg == "0" 
					or arg == "off" 
					or arg == "false"
					or arg == "no"
						p.frenzymusic = 0
						if io and p == consoleplayer
							local file = io.openlocal("client/VoidyChars/voidy_music.dat", "w+")
							file:write(p.frenzymusic)
							file:close()
						end
					elseif arg == "1" 
					or arg == "on" 
					or arg == "true" 
					or arg == "yes"
						p.frenzymusic = 1
						if io and p == consoleplayer
							local file = io.openlocal("client/VoidyChars/voidy_music.dat", "w+")
							file:write(p.frenzymusic)
							file:close()
						end
					else
						CONS_Printf(p, "Invalid input.")
					end
				else
					CONS_Printf(p, "Determines if special music plays during Frenzy Install. Options are:")
					CONS_Printf(p, "1 / on / true / yes")
					CONS_Printf(p, "0 / off / false / no")
				end
			else
				CONS_Printf(p, "You must be out of Frenzy Install to use this command.")
			end
		else
			CONS_Printf(p, "You must be Voidy to use this command.")
		end
	else
		CONS_Printf(p, "This can only be done in a level.")
	end
end)

local function DoFrenzyMusic(player)
	local music = S_MusicName()
	if player.frenzymusic == 1 and not mapheaderinfo[gamemap].nofrenzymusic
		if player.frenzied == 1 and leveltime >= 10
			if music != "_drown"
				S_ChangeMusic("FRENZY", true, player)
			end
		end
	end
end

rawset(_G, "VoidyTrail", function(mo)
	local trail = P_SpawnGhostMobj(mo)
	trail.colorized = true
	trail.blendmode = AST_ADD
	trail.color = mo.color
end)

addHook("PlayerThink", function(player)
	if player.mo and player.mo.skin == "voidy"
		if (player.voidyvars == nil)
			VoidyVariableReset(player, true)
		end
		if player.followmobj and player.followmobj.valid
			player.followmobj.target = player.mo
		end
		VoidyFrameStuff(player.mo)
		DoFrenzyMusic(player)
		player.powers[pw_spacetime] = 0
		if player.powers[pw_super]
			player.charability = CA_FLOAT
			player.charflags = $|SF_MULTIABILITY
			player.powers[pw_shield] = SH_NONE|SH_PROTECTWATER
			player.exhaustmeter = FRACUNIT
		else
			player.charability = CA_NONE
			player.charflags = $ & ~SF_MULTIABILITY
		end
		if (player.mo.state == S_PLAY_GLIDE) and not (player.mo.eflags & MFE_GOOWATER)	
			VoidyTrail(player.mo)
			player.pflags = $|PF_THOKKED
			player.powers[pw_nocontrol] = 1
			if not srb2p
				player.powers[pw_strong] = STR_ANIM|STR_HEAVY|STR_SPRING|STR_SPIKE|STR_ATTACK
			end
			P_InstaThrust(player.mo, player.drawangle, 50*FRACUNIT)
			P_SetObjectMomZ(player.mo, -20*FRACUNIT)
			player.diveconfirm = true
		elseif player.diveconfirm and (P_IsObjectOnGround(player.mo) or player.mo.eflags & MFE_GOOWATER)
			if not (player.playerstate == PST_DEAD)
				player.mo.state = S_PLAY_IMPACTLAND
			end
			player.powers[pw_nocontrol] = 1
			player.mo.momx = 0*FRACUNIT
			player.mo.momy = 0*FRACUNIT
			P_StartQuake(10*FRACUNIT, TICRATE*1/3)
			player.impacttimer = $+1
			S_StartSound(player.mo, sfx_s3k9b)
			for vx = player.mo.x, player.mo.x + player.mo.radius, player.mo.radius
				for vy = player.mo.y, player.mo.y + player.mo.radius, player.mo.radius
					local ss = R_PointInSubsector(vx,vy)
					for fof in ss.sector.ffloors()
						if (fof.flags & FF_BUSTUP) and (fof.flags & FF_EXISTS)
							EV_CrumbleChain(ss.sector, fof)
						end
					end
				end
			end
			if player.impacttimer == 1
				if player.powers[pw_shield] == SH_ARMAGEDDON
					P_BlackOw(player)
				else
					if player.frenzied == 0
						for i = 1, 5
							player.wave = P_SPMAngle(player.mo, MT_IMPACTSHOCKWAVE, player.mo.angle-ANG10*i, 0)
							player.wave = P_SPMAngle(player.mo, MT_IMPACTSHOCKWAVE, player.mo.angle, 0)
							player.wave = P_SPMAngle(player.mo, MT_IMPACTSHOCKWAVE, player.mo.angle+ANG10*i, 0)
						end
					else
						for i = 1, 50
							player.wave = P_SPMAngle(player.mo, MT_IMPACTSHOCKWAVE, player.mo.angle-ANG10*i, 0)
							player.wave = P_SPMAngle(player.mo, MT_IMPACTSHOCKWAVE, player.mo.angle, 0)
							player.wave = P_SPMAngle(player.mo, MT_IMPACTSHOCKWAVE, player.mo.angle+ANG10*i, 0)
						end
					end
				end
			end
			if player.impacttimer <= 50
				player.diveconfirm = false
				player.impacttimer = 0
			end
		end
		if (player.mo.eflags & MFE_SPRUNG)
			player.diveconfirm = false
			player.airconfirm = false
			player.dancercount = 0
		end
		if not (player.exiting or srb2p or PSO or player.battlewait or player.transforming == 1)
			if not (P_PlayerInPain(player) or player.playerstate == PST_DEAD)
				if ((player.powers[pw_carry] == CR_NONE) and not (player.pflags & PF_SPINNING))
					if (player.cmd.buttons & BT_USE)
						player.spintapping = true
						player.spintapready = false
					elseif player.spintapping
						player.spintapready = true
						player.spintapping = false
					else
						player.spintapready = false
					end
					if player.spintapready and player.mo.state == S_PLAY_IMPACTLAND and not player.airconfirm
						player.spinconfirm = true
					end
					if player.spinconfirm and not player.weapondelay and player.impacttimer == 0
						player.mo.state = S_PLAY_ROLL
						player.pflags = $|PF_SPINNING
						S_StartSound(player.mo, sfx_zoom)
						local circle = P_SpawnMobjFromMobj(player.mo, 0, 0, player.mo.scale * 19, MT_REBOUND)
						circle.angle = player.mo.angle + ANGLE_90
						circle.scale = 0
						circle.destscale = 10*FRACUNIT
						circle.scalespeed = FRACUNIT*1/5
						circle.color = player.mo.color
						circle.colorized = true
						P_InstaThrust(player.mo, player.mo.angle, 30*FRACUNIT)
						circle.fuse = 10
						player.weapondelay = TICRATE*1
						player.dodgeroll = 1
					end
					if player.spintapping 
					and not (player.diveconfirm or player.spinconfirm) 
					and not player.powers[pw_super] 
					and player.dancercount < 3
						player.voidycharge = $ + 1
					end
					if player.spintapready
						if (player.moonstonecollected == 0 and player.voidycharge < 50) 
						or (player.moonstonecollected == 1 and player.voidycharge < 10)
							player.voidycharge = 0
						end
					end
					if player.spintapready 
					and not (player.diveconfirm or player.spinconfirm or player.airconfirm) 
					and not player.powers[pw_super]
						if P_IsObjectOnGround(player.mo)
							if player.voidycharge >= 50
								if not player.succconfirm
									if player.frenzied == 0
										player.mo.state = S_PLAY_EARTHSPIKER1
										P_StartQuake(10*FRACUNIT, TICRATE*1/3)
										S_StartSound(player.mo, sfx_pstop)
										S_StartSound(player.mo, sfx_s255)
										player.spike = P_SpawnMobjFromMobj(player.mo, FixedMul(150*FRACUNIT, cos(player.drawangle)), FixedMul(150*FRACUNIT, sin(player.drawangle)), 0, MT_VOIDYSPIKE)
										player.spike.target = player.mo
									else
										player.mo.state = S_PLAY_EARTHSCORCHER1
										P_StartQuake(40*FRACUNIT, TICRATE*1/3)
										S_StartSound(player.mo, sfx_pstop)
										S_StartSound(player.mo, sfx_brakrx)
										player.spike = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_EARTHSCORCHER)
										player.spike.target = player.mo
										player.spike.angle = player.drawangle
										P_InstaThrust(player.spike, player.drawangle, 30*FRACUNIT)
									end
									player.attacktimer = 20
								else
									if player.frenzied == 1
										player.mo.state = S_PLAY_VORTEXREVERT1
									else
										player.mo.state = S_PLAY_VACUUMREVERT1
									end
									player.attacktimer = 20
									player.succconfirm = false
								end
								player.stilltimer = 0
								player.voidycharge = 0
							else
								if player.attackcount == 0 and (player.attacktimer == 0)		
									if player.frenzied == 1
										player.mo.state = S_FRENZY_GROUNDRIGHT1
									else
										player.mo.state = S_BASIC_GROUNDRIGHT1
									end
									player.attacktimer = 20
								elseif player.attackcount == 1 and (player.attacktimer > 0 and player.attacktimer <= 10)
									if player.frenzied == 1
										player.mo.state = S_FRENZY_GROUNDLEFT1
									else
										player.mo.state = S_BASIC_GROUNDLEFT1
									end
									player.attacktimer = 20
								elseif player.attackcount == 2 and (player.attacktimer > 0 and player.attacktimer <= 10)	
									if player.frenzied == 0	
										player.mo.state = S_BASIC_GROUNDFINISHA1
										S_StartSound(player.mo, sfx_claw2)
										player.shredder = P_SPMAngle(player.mo, MT_DUALSHREDDER, player.mo.angle, 0)
									else
										player.mo.state = S_FRENZY_GROUNDFINISHA1
										S_StartSound(player.mo, sfx_claw2)
										player.shredder = P_SpawnMobjFromMobj(player.mo, 0, 0, 0, MT_FRENZY_DUALSHREDDER)
										player.shredder.target = player.mo
										P_StartQuake(20*FRACUNIT, TICRATE*1/3)
									end
									player.attacktimer = 20
								elseif player.carneliancollected == 1
									if not player.didaircombo	
										if player.attackcount == 3 and (player.attacktimer > 0 and player.attacktimer <= 10)	
											if player.frenzied == 1
												player.mo.state = S_FRENZY_GROUNDFINISHB1
											else
												player.mo.state = S_BASIC_GROUNDFINISHB1
											end
											S_StartSound(player.mo, sfx_kc68)
											player.attacktimer = 20
										end
									else
										if player.attackcount == 3 and (player.attacktimer > 0 and player.attacktimer <= 10)	
											if player.frenzied == 1
												player.mo.state = S_FRENZY_AIRFINISHB1
												player.chasertimer = 20
											else
												player.mo.state = S_BASIC_AIRFINISHB1
											end
											S_StartSound(player.mo, sfx_upper)
											player.attacktimer = 20
										end
									end
								end
							end
						else
							if player.voidycharge >= 50
								player.airconfirm = true
								player.chargedairconfirm = true
								player.voidycharge = 0
							else
								if player.attackcount == 0 and (player.attacktimer == 0)
									if player.frenzied == 1
										player.mo.state = S_FRENZY_AIRRIGHT1
									else	
										player.mo.state = S_BASIC_AIRRIGHT1
									end
									player.attacktimer = 20
								elseif player.attackcount == 1 and (player.attacktimer > 0 and player.attacktimer <= 10)
									if player.frenzied == 1
										player.mo.state = S_FRENZY_AIRLEFT1
									else
										player.mo.state = S_BASIC_AIRLEFT1
									end
									player.attacktimer = 20
								elseif player.attackcount == 2 and (player.attacktimer > 0 and player.attacktimer <= 10)
									if player.frenzied == 1
										player.mo.state = S_FRENZY_AIRFINISHA1
									else
										player.mo.state = S_BASIC_AIRFINISHA1
									end
									player.attacktimer = 20
								end
							end
						end
						if player.moonstonecollected == 1
							if player.voidycharge >= 10 and player.voidycharge < 50
								player.cloneconfirm = true
							end
							player.voidycharge = 0
						end
					end
					if player.weapondelay
						player.spinconfirm = false
					end
					if player.attacktimer > 0
						if player.carneliancollected != 1 
						or (player.carneliancollected == 1 and not player.airconfirm) 
							player.attacktimer = $-1
						end
						if player.moonstonecollected == 1 and player.voidycharge >= 10
							player.attacktimer = 10
						end
					end
					if player.attacktimer <= 0
						player.attackcount = 0
						player.attacktimer = 0
						player.slash1spawned = false
						player.slash2spawned = false
						player.spawnedclone = false
						player.rocksspawned = false
						player.didaircombo = false
						player.tsunamispawned = false
					end
					if player.mo.state == S_BASIC_GROUNDRIGHT1 
					or player.mo.state == S_BASIC_AIRRIGHT1 
					or player.mo.state == S_FRENZY_GROUNDRIGHT1 
					or player.mo.state == S_FRENZY_AIRRIGHT1
						player.mo.frame = A
						player.attackcount = 1
						if not player.slash1spawned	
							if player.frenzied == 0
								S_StartSound(player.mo, sfx_claw1)
								player.shredder = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_RIGHTSHREDDER)
								player.shredder.target = player.mo
								if player.cloneconfirm
									player.dream = P_SpawnMobjFromMobj(player.mo, FixedMul(100*FRACUNIT, cos(player.drawangle)), FixedMul(100*FRACUNIT, sin(player.drawangle)), 0, MT_VOIDYCLONE)
									player.dream.target = player.mo
									player.dream.skin = "voidy"
								end
							else
								S_StartSound(player.mo, sfx_xclaw1)
								player.shredder = P_SpawnMobjFromMobj(player.mo, FixedMul(100*FRACUNIT, cos(player.drawangle)), FixedMul(100*FRACUNIT, sin(player.drawangle)), -100*FRACUNIT, MT_FRENZY_RIGHTSHREDDER)
								player.shredder.target = player.mo
								P_StartQuake(10*FRACUNIT, TICRATE*1/3)
								if player.cloneconfirm
									player.nightmare = P_SpawnMobjFromMobj(player.mo, FixedMul(150*FRACUNIT, cos(player.drawangle)), FixedMul(150*FRACUNIT, sin(player.drawangle)), 0, MT_VOIDYCLONE)
									player.nightmare.target = player.mo
									player.nightmare.skin = "voidy"
								end
							end
							player.slash1spawned = true
							player.cloneconfirm = false
						end
					end
					if player.mo.state == S_BASIC_GROUNDLEFT1 
					or player.mo.state == S_BASIC_AIRLEFT1 
					or player.mo.state == S_FRENZY_GROUNDLEFT1 
					or player.mo.state == S_FRENZY_AIRLEFT1
						player.mo.frame = D
						player.attackcount = 2
						if not player.slash2spawned	
							if player.frenzied == 0
								S_StartSound(player.mo, sfx_claw1)
								player.shredder = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_LEFTSHREDDER)
								player.shredder.target = player.mo
								if player.cloneconfirm
									player.dream = P_SpawnMobjFromMobj(player.mo, FixedMul(100*FRACUNIT, cos(player.drawangle)), FixedMul(100*FRACUNIT, sin(player.drawangle)), 0, MT_VOIDYCLONE)
									player.dream.target = player.mo
									player.dream.skin = "voidy"
								end
							else
								S_StartSound(player.mo, sfx_xclaw1)
								player.shredder = P_SpawnMobjFromMobj(player.mo, FixedMul(100*FRACUNIT, cos(player.drawangle)), FixedMul(100*FRACUNIT, sin(player.drawangle)), -100*FRACUNIT, MT_FRENZY_LEFTSHREDDER)
								player.shredder.target = player.mo
								P_StartQuake(10*FRACUNIT, TICRATE*1/3)
								if player.cloneconfirm
									player.nightmare = P_SpawnMobjFromMobj(player.mo, FixedMul(150*FRACUNIT, cos(player.drawangle)), FixedMul(150*FRACUNIT, sin(player.drawangle)), 0, MT_VOIDYCLONE)
									player.nightmare.target = player.mo
									player.nightmare.skin = "voidy"
								end
							end
							player.slash2spawned = true
							player.cloneconfirm = false
						end
					end
					if player.mo.state == S_BASIC_GROUNDFINISHA1 
					or player.mo.state == S_BASIC_AIRFINISHA1 
					or player.mo.state == S_FRENZY_GROUNDFINISHA1 
					or player.mo.state == S_FRENZY_AIRFINISHA1
						player.mo.frame = G
						player.attackcount = 3
					end
					if player.mo.state == S_BASIC_GROUNDFINISHA1 
					or player.mo.state == S_FRENZY_GROUNDFINISHA1
						if player.cloneconfirm and not player.spawnedclone
							player.dream = P_SpawnMobjFromMobj(player.mo, FixedMul(100*FRACUNIT, cos(player.drawangle)), FixedMul(100*FRACUNIT, sin(player.drawangle)), 0, MT_VOIDYCLONE)
							player.dream.target = player.mo
							player.dream.skin = "voidy"
							player.spawnedclone = true
						end
					end
					if player.mo.state == S_FRENZY_GROUNDFINISHA1
						player.olddraw = player.drawangle
					end
					if player.mo.state == S_FRENZY_GROUNDFINISHA2
						player.drawangle = $ + ANGLE_45
					end
					if player.mo.state == S_FRENZY_GROUNDFINISHA3
						player.drawangle = player.olddraw
					end
					if player.mo.state == S_BASIC_GROUNDFINISHB1 
					or player.mo.state == S_BASIC_AIRFINISHB1 
					or player.mo.state == S_FRENZY_GROUNDFINISHB1 
					or player.mo.state == S_FRENZY_AIRFINISHB1
						player.attackcount = 4
					end
					if player.mo.state == S_BASIC_AIRRIGHT1 
					or player.mo.state == S_BASIC_AIRRIGHT2 
					or player.mo.state == S_BASIC_AIRRIGHT3 
					or player.mo.state == S_BASIC_AIRLEFT1 
					or player.mo.state == S_BASIC_AIRLEFT2 
					or player.mo.state == S_BASIC_AIRLEFT3 
					or player.mo.state == S_FRENZY_AIRRIGHT1 
					or player.mo.state == S_FRENZY_AIRRIGHT2 
					or player.mo.state == S_FRENZY_AIRRIGHT3 
					or player.mo.state == S_FRENZY_AIRLEFT1 
					or player.mo.state == S_FRENZY_AIRLEFT2 
					or player.mo.state == S_FRENZY_AIRLEFT3
						player.mo.momx = 0*FRACUNIT
						player.mo.momy = 0*FRACUNIT
						player.mo.momz = 0*FRACUNIT
					end
					if player.mo.state == S_BASIC_AIRFINISHA1 
					or player.mo.state == S_FRENZY_AIRFINISHA1
						P_SetObjectMomZ(player.mo, 5*FRACUNIT)
						player.mo.momx = 0*FRACUNIT
						player.mo.momy = 0*FRACUNIT
						player.airconfirm = true
					end
					if player.mo.state == S_BASIC_AIRFINISHA2 
					or player.mo.state == S_BASIC_AIRFINISHA3 
					or player.mo.state == S_FRENZY_AIRFINISHA2 
					or player.mo.state == S_FRENZY_AIRFINISHA3
						P_SetObjectMomZ(player.mo, -30*FRACUNIT)
						player.mo.momx = 0*FRACUNIT
						player.mo.momy = 0*FRACUNIT
						VoidyTrail(player.mo)
					end
					if player.airconfirm
						if not player.chargedairconfirm
							if P_IsObjectOnGround(player.mo)
								if not (player.playerstate == PST_DEAD)
									player.mo.state = S_PLAY_FINISHERLAND
								end
								player.powers[pw_nocontrol] = 1
								player.mo.momx = 0*FRACUNIT
								player.mo.momy = 0*FRACUNIT
								player.finishertimer = $+1
								for vx = player.mo.x, player.mo.x + player.mo.radius, player.mo.radius
									for vy = player.mo.y, player.mo.y + player.mo.radius, player.mo.radius
										local ss = R_PointInSubsector(vx,vy)
										for fof in ss.sector.ffloors()
											if (fof.flags & FF_BUSTUP) and (fof.flags & FF_EXISTS)
												EV_CrumbleChain(ss.sector, fof)
											end
										end
									end
								end
								if player.frenzied == 0
									if player.finishertimer == 1
										player.pillar = P_SpawnMobjFromMobj(player.mo, FixedMul(100*FRACUNIT, cos(player.drawangle)), FixedMul(100*FRACUNIT, sin(player.drawangle)), 0, MT_ENERGYPILLAR)
										player.pillar.target = player.mo
										S_StartSound(player.mo, sfx_kc40)
										P_StartQuake(10*FRACUNIT, TICRATE*1/3)
									elseif player.finishertimer == 10
										player.pillar = P_SpawnMobjFromMobj(player.mo, FixedMul(150*FRACUNIT, cos(player.drawangle)), FixedMul(150*FRACUNIT, sin(player.drawangle)), 0, MT_ENERGYPILLAR)
										player.pillar.target = player.mo
										S_StartSound(player.mo, sfx_kc40)
										P_StartQuake(10*FRACUNIT, TICRATE*1/3)
									elseif player.finishertimer == 20
										player.pillar = P_SpawnMobjFromMobj(player.mo, FixedMul(200*FRACUNIT, cos(player.drawangle)), FixedMul(200*FRACUNIT, sin(player.drawangle)), 0, MT_ENERGYPILLAR)
										player.pillar.target = player.mo
										S_StartSound(player.mo, sfx_kc40)
										P_StartQuake(10*FRACUNIT, TICRATE*1/3)
									end
								else
									if player.finishertimer == 1
										for i = 1,6	
											player.ball = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 5*FRACUNIT, MT_FRENZY_ENERGYBALL)
											player.ball.target = player.mo
											P_InstaThrust(player.ball, player.mo.angle+ANG60*i, 18*FRACUNIT)
											P_SetObjectMomZ(player.ball, 4*FRACUNIT)
										end
										S_StartSound(player.mo, sfx_bexpld)
										S_StartSound(player.mo, sfx_xfinsh)
										P_StartQuake(20*FRACUNIT, TICRATE*1/3)
									end
								end
								if player.finishertimer == 1 and player.cloneconfirm
									player.clone = P_SpawnMobjFromMobj(player.mo, FixedMul(-200*FRACUNIT, cos(player.drawangle)), FixedMul(-200*FRACUNIT, sin(player.drawangle)), 200*FRACUNIT, MT_VOIDYCLONE)
									player.clone.target = player.mo
									player.clone.skin = "voidy"
								end
							end
							if not srb2p
								player.powers[pw_strong] = STR_ANIM|STR_HEAVY|STR_SPRING
							end
							if player.carneliancollected == 1
								player.didaircombo = true
							end
						else
							player.finishertimer = $+1
							if player.finishertimer == 1
								player.dancercount = $ + 1
								if player.frenzied == 1
									player.mo.state = S_PLAY_CRESCENTREAPER1
									player.reaper = P_SPMAngle(player.mo, MT_CRESCENTREAPER, player.mo.angle)
									S_StartSound(player.mo, sfx_rail1)
									P_StartQuake(40*FRACUNIT, TICRATE*1/3)
								else
									player.mo.state = S_PLAY_CRESCENTDANCER1
									player.crescent = P_SPMAngle(player.mo, MT_CRESCENTDANCER, player.mo.angle)
									S_StartSound(player.mo, sfx_cdance)
								end
								P_SetObjectMomZ(player.mo, 0*FRACUNIT)
							elseif player.finishertimer == 2
								P_SetObjectMomZ(player.mo, 10*FRACUNIT)
								if player.frenzied == 1
									P_InstaThrust(player.mo, player.mo.angle, -20*FRACUNIT)
								end
							elseif player.finishertimer == 20
								if player.frenzied == 1
									player.mo.state = S_PLAY_CRESCENTREAPER1
									player.reaper = P_SPMAngle(player.mo, MT_CRESCENTREAPER, player.mo.angle)
									S_StartSound(player.mo, sfx_rail1)
									P_StartQuake(40*FRACUNIT, TICRATE*1/3)
								else
									player.mo.state = S_PLAY_CRESCENTDANCER1
									player.crescent = P_SPMAngle(player.mo, MT_CRESCENTDANCER, player.mo.angle)
									S_StartSound(player.mo, sfx_cdance)
								end
								P_SetObjectMomZ(player.mo, 0*FRACUNIT)
							elseif player.finishertimer == 21
								P_SetObjectMomZ(player.mo, 10*FRACUNIT)
								if player.frenzied == 1
									P_InstaThrust(player.mo, player.mo.angle, -20*FRACUNIT)
								end
							end
						end
						if player.finishertimer >= 21
							player.airconfirm = false
							player.chargedairconfirm = false
							player.finishertimer = 0
							player.cloneconfirm = false
						end
					end
					if not (player.cmd.buttons & BT_CUSTOM1)
						player.cust1tapready = true
						player.cust1tapping = false
					elseif player.cust1tapready
						player.cust1tapping = true
						player.cust1tapready = false
					else
						player.cust1tapping = false
					end
					if player.lifeforce >= 80
						if P_IsObjectOnGround(player.mo) 
						and not player.powers[pw_super] 
						and player.attacking == 0 
						and player.transforming == 0
						and player.frenzied == 0 
						and player.cust1tapping
							if not (player.mo.state == S_PLAY_FRENZY_INTRO1)	
								player.mo.state = S_PLAY_FRENZY_INTRO1
							end
							S_StartSound(player.mo, sfx_frenzy)
							if player.frenzymusic == 1 
							and not mapheaderinfo[gamemap].nofrenzymusic
								S_StopMusic(player)
							end
						end
					end
					if (player.cmd.buttons & BT_CUSTOM2)
						player.cust2tapready = true
						player.cust2tapping = false
					elseif player.cust2tapready
						player.cust2tapping = true
						player.cust2tapready = false
					else
						player.cust2tapping = false
					end
					if player.tourmalinecollected == 1 
					and P_IsObjectOnGround(player.mo) 
					and not player.powers[pw_super] 
					and not player.succconfirm 
					and player.transforming == 0 
					and player.guardtimer == 0 
					and not player.stanced
					and player.cust2tapping
						if player.frenzied == 1
							if player.mo.state == S_FRENZY_WINGGUARD_FIN
								player.mo.state = S_FRENZY_WINGGUARD_FIN
								player.mo.frame = C
							else
								player.mo.state = S_FRENZY_WINGGUARD
							end
						else
							if player.mo.state == S_BASIC_WINGGUARD_FIN
								player.mo.state = S_BASIC_WINGGUARD_FIN
								player.mo.frame = C
							else
								player.mo.state = S_BASIC_WINGGUARD
							end
						end
						local ang = player.mo.angle
						local circle = P_SpawnMobjFromMobj(player.mo, FixedMul(30*FRACUNIT, cos(player.drawangle)), FixedMul(30*FRACUNIT, sin(player.drawangle)), player.mo.scale * 49, MT_REBOUND)
						circle.angle = ang + ANGLE_90
						circle.scale = 0
						circle.destscale = 10*FRACUNIT
						circle.color = SKINCOLOR_WHITE
						circle.colorized = true
						S_StartSound(player.mo, sfx_s255)
						circle.fuse = 9
						player.guardtimer = 20
					end
				end
			end
		end
		if player.mo.state == S_BASIC_GROUNDFINISHB1 
		or player.mo.state == S_BASIC_GROUNDFINISHB2 
		or player.mo.state == S_BASIC_GROUNDFINISHB3 
		or player.mo.state == S_FRENZY_GROUNDFINISHB1 
		or player.mo.state == S_FRENZY_GROUNDFINISHB2 
		or player.mo.state == S_FRENZY_GROUNDFINISHB3 
		or player.mo.state == S_BASIC_WINGGUARD 
		or player.mo.state == S_BASIC_WINGGUARD_FIN 
		or player.mo.state == S_FRENZY_WINGGUARD 
		or player.mo.state == S_FRENZY_WINGGUARD_FIN
			player.pflags = $|PF_FULLSTASIS
		end
		if player.mo.state == S_BASIC_GROUNDFINISHB3 
		and not player.rocksspawned
			S_StartSound(player.mo, sfx_crumbl)
			for i = 1, 2
				player.rock = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 5*FRACUNIT, MT_VOIDYROCK)
				player.rock.target = player.mo
				P_InstaThrust(player.rock, player.mo.angle, P_RandomRange(10, 30)*FRACUNIT)
				P_SetObjectMomZ(player.rock, P_RandomRange(4, 9)*FRACUNIT)
				player.rock.fuse = 40
				player.rock2 = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 5*FRACUNIT, MT_VOIDYROCK)
				player.rock2.target = player.mo
				P_InstaThrust(player.rock2, player.mo.angle-ANG10, P_RandomRange(10, 30)*FRACUNIT)
				P_SetObjectMomZ(player.rock2, P_RandomRange(4, 9)*FRACUNIT)
				player.rock2.fuse = 40
				player.rock3 = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 5*FRACUNIT, MT_VOIDYROCK)
				player.rock3.target = player.mo
				P_InstaThrust(player.rock3, player.mo.angle+ANG10, P_RandomRange(10, 30)*FRACUNIT)
				P_SetObjectMomZ(player.rock3, P_RandomRange(4, 9)*FRACUNIT)
				player.rock3.fuse = 40
			end
			player.rocksspawned = true
		end
		if player.mo.state == S_FRENZY_GROUNDFINISHB2 
		and not player.tsunamispawned
			S_StartSound(player.mo, sfx_ewatr)
			for i = 1, 3
				player.tide = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_ENERGYTSUNAMI)
				player.tide.target = player.mo
				P_InstaThrust(player.tide, player.mo.angle, P_RandomRange(10, 90)*FRACUNIT)
				player.tide2 = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_ENERGYTSUNAMI)
				player.tide2.target = player.mo
				P_InstaThrust(player.tide2, player.mo.angle-ANG20, P_RandomRange(10, 90)*FRACUNIT)
				player.tide3 = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_ENERGYTSUNAMI)
				player.tide3.target = player.mo
				P_InstaThrust(player.tide3, player.mo.angle+ANG20, P_RandomRange(10, 90)*FRACUNIT)
			end
			player.tsunamispawned = true
		end
		if player.mo.state == S_BASIC_AIRFINISHB2
			P_SetObjectMomZ(player.mo, 20*FRACUNIT)
			VoidyTrail(player.mo)
			if not player.spawnedpillar
				player.pillar = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_ENERGYPILLAR)
				player.pillar.target = player.mo
				player.spawnedpillar = true
			end
		end
		if player.mo.state == S_BASIC_AIRFINISHB3
			VoidyTrail(player.mo)
			player.diduppercut = true
			player.spawnedpillar = false
		end
		if player.mo.state == S_FRENZY_AIRFINISHB2
			VoidyTrail(player.mo)
			if player.chasertimer == 20	
				player.autoaim = P_LookForEnemies(player, true, true)
			end
			if player.chasertimer > 0
				if player.autoaim and player.autoaim.valid
					P_HomingAttack(player.mo, player.autoaim)
					player.powers[pw_strong] = STR_ANIM|STR_HEAVY|STR_SPRING|STR_SPIKE|STR_GUARD
					player.powers[pw_nocontrol] = 1
					if leveltime%9 == 0
						player.chasertimer = $ - 1
					end
				else
					P_SetObjectMomZ(player.mo, 20*FRACUNIT)
					P_InstaThrust(player.mo, player.drawangle, 20*FRACUNIT)
					player.chasertimer = $ - 1
				end
			else
				player.mo.state = S_FRENZY_AIRFINISHB3
			end
			player.diduppercut = true
		end
		if player.mo.state == S_FRENZY_AIRFINISHB3
			P_SetObjectMomZ(player.mo, 20*FRACUNIT)
		end
		if ((player.mo.state == S_PLAY_FALL) or (player.mo.state == S_PLAY_ROLL)) and player.diduppercut
			player.pflags = $|PF_JUMPED
			player.diduppercut = false
		end
		if P_IsObjectOnGround(player.mo)
			player.dancercount = 0
		end
		if player.dodgeroll == 1 and (player.pflags & PF_SPINNING)
			VoidyTrail(player.mo)
		elseif player.dodgeroll == 1 and not (player.pflags & PF_SPINNING)
			player.dodgeroll = 0
		end
		if player.voidycharge == 10
			if not player.chrggfxspawned
				S_StartSound(player.mo, sfx_aschrg)
				player.aura = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_VOIDYCHARGEAURA)
				player.aura.target = player.mo
				player.aura.scale = 5*FRACUNIT
				player.aura.destscale = 0*FRACUNIT
				player.aura.scalespeed = FRACUNIT*1/8
				player.aura.color = SKINCOLOR_NEON
				player.aura.colorized = true
				player.chrggfxspawned = true
			end
		end
		if player.voidycharge >= 10 
		and P_IsObjectOnGround(player.mo) 
		and player.speed == 0
			player.stilltimer = $ + 1
			if player.stilltimer < 50
				player.mo.state = S_PLAY_CHARGESTAND
			end
		else
			player.stilltimer = 0
		end
		if player.voidycharge == 0 or player.voidycharge >= 50
			S_StopSoundByID(player.mo, sfx_aschrg)
			player.chrggfxspawned = false
		end
		if player.voidycharge == 50
			S_StartSound(player.mo, sfx_s3k5c)
			S_StartSound(player.mo, sfx_aschgd)
			player.flash = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_VOIDYCHARGEFLASH)
			player.flash.target = player.mo
			player.flash.scale = 3*FRACUNIT
			player.flash.color = SKINCOLOR_NEON
			player.flash.colorized = true
		end
		if player.stilltimer == 50
			if player.frenzied == 1
				player.mo.state = S_PLAY_VORTEXGULLET1
			else
				player.mo.state = S_PLAY_VACUUMGULLET1
			end
			player.hitbox = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_VACCHITBOX)
			player.hitbox.target = player.mo
			player.succconfirm = true
		end
		if player.stilltimer >= 50
			player.mo.momx = 0*FRACUNIT
			player.mo.momy = 0*FRACUNIT
			player.pflags = $|PF_JUMPSTASIS
			if player.mo.eflags & MFE_UNDERWATER	
				player.powers[pw_shield] = SH_NONE|SH_PROTECTWATER
				P_RestoreMusic(player)
			end
			if player.mo.state == S_PLAY_VACUUMGULLET4 
			or player.mo.state == S_PLAY_VORTEXGULLET4
				if player.frenzied == 0
					player.succ = P_SpawnMobj(player.mo.x + FixedMul(500*FRACUNIT, cos(player.drawangle)), player.mo.y + FixedMul(500*FRACUNIT, sin(player.drawangle)), player.mo.z, MT_SUCCFX)
					player.succ.target = player.mo
					player.succ.fuse = 24
					player.succ.scale = 4*FRACUNIT
					player.succ.destscale = 1*FRACUNIT
					player.succ.scalespeed = FRACUNIT*1/7
					S_StartSound(player.mo, sfx_s3ka0)
					P_InstaThrust(player.succ, player.mo.angle, -20*FRACUNIT)
					player.succ.angle = player.mo.angle + ANGLE_90
				else
					player.succ = P_SpawnMobjFromMobj(player.mo, 0, 0, 550*FRACUNIT, MT_FRENZY_SUCCFX)
					player.succ.target = player.mo
					player.succ.fuse = 21
					player.succ.scale = 8*FRACUNIT
					player.succ.destscale = 1*FRACUNIT
					player.succ.scalespeed = FRACUNIT*1/3
					P_SetObjectMomZ(player.succ, -5*FRACUNIT)
				end
				player.succ.color = SKINCOLOR_NEON
				player.succ.colorized = true
			end
			if player.frenzied == 1
				P_StartQuake(30*FRACUNIT, TICRATE*1/3)
				if (leveltime%13 == 0)
					S_StartSound(player.mo, sfx_succ)
				end
			end
			if player.lifeforce < player.maxlifeforce
			and (leveltime%17 == 0)
				player.lifeforce = $ + 1
			end
		end
		if player.mo.state == S_PLAY_VACUUMREVERT1 
		or player.mo.state == S_PLAY_VACUUMREVERT2 
		or player.mo.state == S_PLAY_VACUUMREVERT3 
		or player.mo.state == S_PLAY_VORTEXREVERT1 
		or player.mo.state == S_PLAY_VORTEXREVERT2 
		or player.mo.state == S_PLAY_VORTEXREVERT3
			player.pflags = $|PF_FULLSTASIS
			if player.mo.eflags & MFE_UNDERWATER	
				player.powers[pw_shield] = SH_NONE
			end
		end
		if player.lifeforce >= player.maxlifeforce
		or player.powers[pw_super]
			player.lifeforce = player.maxlifeforce
		end
		if player.lifeforce >= 80
			if player.frenzied == 0 
			and not player.frenzynotified
				S_StartSound(player.mo, sfx_fready)
				player.frenzynotified = true
			end
		else
			player.frenzynotified = false
		end
		if player.attacktimer > 0 
		or player.voidycharge > 0 
		or (player.mo.state == S_PLAY_IMPACTLAND or player.mo.state == S_PLAY_FINISHERLAND)
			player.attacking = 1
		else
			player.attacking = 0
		end
		if player.mo.state == S_PLAY_FRENZY_INTRO1 
		or player.mo.state == S_PLAY_FRENZY_INTRO2 
		or player.mo.state == S_PLAY_FRENZY_TRANS1 
		or player.mo.state == S_PLAY_FRENZY_TRANS2 
		or player.mo.state == S_PLAY_FRENZY_TRANS3 
		or player.mo.state == S_PLAY_FRENZY_TRANS4 
		or player.mo.state == S_PLAY_FRENZY_TRANS5 
		or player.mo.state == S_PLAY_FRENZY_TRANS6 
		or player.mo.state == S_PLAY_SUPER_INTRO1 
		or player.mo.state == S_PLAY_SUPER_INTRO2 
		or player.mo.state == S_PLAY_SUPER_INTRO3 
		or player.mo.state == S_PLAY_SUPER_TRANS1 
		or player.mo.state == S_PLAY_SUPER_TRANS2 
		or player.mo.state == S_PLAY_SUPER_TRANS3 
		or player.mo.state == S_PLAY_SUPER_TRANS4 
		or player.mo.state == S_PLAY_SUPER_TRANS5 
		or player.mo.state == S_PLAY_SUPER_TRANS6 
			player.transforming = 1
			player.powers[pw_nocontrol] = 1
			player.mo.momx = 0*FRACUNIT
			player.mo.momy = 0*FRACUNIT
		else
			player.transforming = 0
		end
		if player.mo.state == S_PLAY_FRENZY_TRANS1 and player.garnetcollected == 1
			if not player.blastspawned
				player.blast = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_FRENZYEXPLOSION)
				player.blast.target = player.mo
				player.blast.color = SKINCOLOR_NEON
				player.blast.blendmode = AST_ADD
				if player.lifeforce == 100
					player.blast.scale = 4*FRACUNIT
					player.camerascale = 3*FRACUNIT
				else
					player.blast.scale = 2*FRACUNIT
				end
				player.blastspawned = true
			end
		end
		if player.transforming == 0 and player.camerascale == 3*FRACUNIT
			player.camerascale = 1*FRACUNIT
		end
		if player.mo.state == S_PLAY_FRENZY_TRANS3
			player.frenzied = 1
			S_StartSound(player.mo, sfx_s3k4e)
			P_StartQuake(50*FRACUNIT, TICRATE*1/3)
		end
		if player.frenzied == 1
			if player.transforming == 0
				if (player.selenitecollected == 0 and (leveltime%17/2 == 0)) 
				or (player.selenitecollected == 1 and (leveltime%17 == 0))
					player.lifeforce = $ - 1
				end
			end
			if P_PlayerInPain(player)
				player.mo.momx = 0
				player.mo.momy = 0
				if player.tourmalinecollected == 1
					player.mo.state = S_PLAY_FALL
				end
			end
			if player.lifeforce <= 0 
			or player.playerstate == PST_REBORN
				player.frenzied = 0
				player.blastspawned = false
				if player.frenzymusic == 1 
				and not mapheaderinfo[gamemap].nofrenzymusic
					P_RestoreMusic(player)
				end
				if player.mo.state == S_PLAY_STND 
				or player.mo.state == S_PLAY_WAIT
					player.mo.state = S_PLAY_STND
				end
				if player.mo.state == S_PLAY_EDGE
					player.mo.state = S_PLAY_EDGE
				end
			end	
		end
		if player.exiting == 3
			saveVoidyData(player)
			player.frenzied = 0
		end
		if (All7Emeralds(emeralds)) and not player.voidynotified
			player.voidynotified = true
			S_StartSound(player.mo, sfx_s3k68)
		end
		if not G_EnoughPlayersFinished()
			if not player.powers[pw_super]
				player.charflags = $ & ~SF_SUPER
			end
			if (player.cmd.buttons & BT_CUSTOM1) and VoidySuperCheck(player) and player.transforming == 0
				if not (player.mo.state == S_PLAY_SUPER_INTRO1)	
					player.mo.state = S_PLAY_SUPER_INTRO1
				end
				S_StartSound(player.mo, sfx_void)
				if not mapheaderinfo[gamemap].nossmusic
					S_StopMusic(player)
				end
			end
			if (P_PlayerTouchingSectorSpecial(player, 4, 6) or mapheaderinfo[gamemap].lvlttl == "Dimension Warp") 
			and All7Emeralds(emeralds) and not player.powers[pw_super] then
				player.rings = 50
				VoidySuper(player)
			end
        end
		if player.mo.state == S_PLAY_SUPER_INTRO1 
		or player.mo.state == S_PLAY_SUPER_INTRO2 
		or player.mo.state == S_PLAY_SUPER_INTRO3
			P_SetObjectMomZ(player.mo, 0*FRACUNIT)
		end
		if player.mo.state == S_PLAY_SUPER_INTRO3
			VoidySuper(player)
		end
		if player.mo.state == S_PLAY_SUPER_TRANS3
			player.blackhole = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_VOIDYBLACKHOLE)
			player.blackhole.target = player.mo
			player.blackhole.destscale = 5*FRACUNIT
			player.blackhole.scalespeed = FRACUNIT*1/3
			player.blackhole.color = SKINCOLOR_BLACK
			S_StartSound(player.mo, sfx_bhole)
		end
		if player.powers[pw_super] 
		or (player.stilltimer >= 50 and player.frenzied == 1)
			local m = player.realmo
			local range = 1000*FRACUNIT
			local range2 = range - (64*FRACUNIT)
			m.target = player.mo
			searchBlockmap("objects", function(ref, found)
				if ValidVoidyObject(found) and found.health then
					if R_PointToDist2(m.x, m.y, found.x, found.y) <= range2 then
						if found.type == MT_RING or found.type == MT_COIN or found.type == MT_BLUESPHERE then
							found.tracer = m
						end
						local dist = R_PointToDist2(m.x, m.y, found.x, found.y)
						if dist < FRACUNIT then
							dist = FRACUNIT
						end
						local PullForce = range/dist * 3
						if PullForce > 30 then
							PullForce = 30
						end
						PullForce = $ * FRACUNIT
						if found != m
							if found.type == MT_PLAYER
								m.frenzysuccangle = R_PointToAngle2(m.x, m.y, found.x, found.y)
								P_Thrust(found, m.frenzysuccangle+ANGLE_180, FRACUNIT*2)
							else
								VoidyAttract(found, m, PullForce)
							end
						end
					end
				end
				if found.flags & MF_BOSS
					if R_PointToDist2(m.x, m.y, found.x, found.y) <= range2 then
						P_DamageMobj(found, player.mo, player.mo, 1)
					end
				end
				if (found.valid and found.type == MT_EGGSHIELD)
					if R_PointToDist2(m.x, m.y, found.x, found.y) <= range2 then
						P_KillMobj(found, player.mo, player.mo)
					end
				end
				if (found.valid and found.flags & MF_MISSILE)
					if R_PointToDist2(m.x, m.y, found.x, found.y) <= range2 then
						DoLFGain(player)
						P_RemoveMobj(found)
					end
				end
				if (found.valid and found.type == MT_METALSONIC_BATTLE) 
				and found.state == found.info.spawnstate 
				and not (found.flags2 & MF2_CLASSICPUSH)
					if R_PointToDist2(m.x, m.y, found.x, found.y) <= range2 then
						found.flags2 = $ | MF2_CLASSICPUSH
					end
				end
			end, m, m.x-range, m.x+range, m.y-range, m.y+range)
		end
		if (player.mo.state == S_PLAY_FLOAT or player.mo.state == S_PLAY_FLOAT_RUN) 
		and not player.powers[pw_super]
			P_ResetPlayer(player)
			player.mo.state = S_PLAY_FALL
		end
		if player.tourmalinecollected == 1 and P_PlayerInPain(player)
			player.mo.momx = 0
			player.mo.momy = 0
		end
		if player.guardtimer > 0
			player.guardtimer = $-1
		end
		if player.guardtimer > 0 
		or ((player.mo.state == S_BASIC_WINGGUARD_FIN or player.mo.state == S_FRENZY_WINGGUARD_FIN) and player.guardtimer == 0)
			player.guarding = true
		else
			player.guarding = false
		end
		if player.stanced
			player.mo.momx = 0*FRACUNIT
			player.mo.momy = 0*FRACUNIT
			if P_PlayerInPain(player) or player.attacktimer > 0
				player.stanced = false
				player.activatedstance = false
				player.stancetimer = 0
			end
		end
		if player.mo.state == S_PLAY_BATTLELAND
			player.nailtimer = $+1
			player.powers[pw_nocontrol] = 1
			player.mo.momx = 0*FRACUNIT
			player.mo.momy = 0*FRACUNIT
			if player.frenzied == 0
				if player.nailtimer == 1
					P_StartQuake(10*FRACUNIT, TICRATE*1/2)
					S_StartSound(player.mo, sfx_pstop)
					S_StartSound(player.mo, sfx_s255)
					player.spike = P_SpawnMobjFromMobj(player.mo, FixedMul(150*FRACUNIT, cos(player.drawangle)), FixedMul(150*FRACUNIT, sin(player.drawangle)), 0, MT_VOIDYSPIKE)
					player.spike.target = player.mo
				elseif player.nailtimer == 6
					S_StartSound(player.mo, sfx_s255)
					player.spike = P_SpawnMobjFromMobj(player.mo, FixedMul(150*FRACUNIT, cos(player.drawangle+ANGLE_90)), FixedMul(150*FRACUNIT, sin(player.drawangle+ANGLE_90)), 0, MT_VOIDYSPIKE)
					player.spike.target = player.mo
				elseif player.nailtimer == 12
					S_StartSound(player.mo, sfx_s255)
					player.spike = P_SpawnMobjFromMobj(player.mo, FixedMul(-150*FRACUNIT, cos(player.drawangle+ANGLE_90)), FixedMul(-150*FRACUNIT, sin(player.drawangle+ANGLE_90)), 0, MT_VOIDYSPIKE)
					player.spike.target = player.mo
				elseif player.nailtimer == 18
					S_StartSound(player.mo, sfx_s255)
					player.spike = P_SpawnMobjFromMobj(player.mo, FixedMul(-150*FRACUNIT, cos(player.drawangle)), FixedMul(-150*FRACUNIT, sin(player.drawangle)), 0, MT_VOIDYSPIKE)
					player.spike.target = player.mo
				end
			else
				if player.nailtimer == 1
					P_StartQuake(40*FRACUNIT, TICRATE*1/2)
					S_StartSound(player.mo, sfx_pstop)
					S_StartSound(player.mo, sfx_brakrx)
					player.spike1 = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_EARTHSCORCHER)
					player.spike1.target = player.mo
					player.spike1.angle = player.drawangle
					P_InstaThrust(player.spike1, player.drawangle, 30*FRACUNIT)
					player.spike2 = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_EARTHSCORCHER)
					player.spike2.target = player.mo
					player.spike2.angle = player.drawangle+ANG30
					P_InstaThrust(player.spike2, player.drawangle+ANG30, 30*FRACUNIT)
					player.spike3 = P_SpawnMobjFromMobj(player.mo, FixedMul(50*FRACUNIT, cos(player.drawangle)), FixedMul(50*FRACUNIT, sin(player.drawangle)), 0, MT_EARTHSCORCHER)
					player.spike3.target = player.mo
					player.spike3.angle = player.drawangle-ANG30
					P_InstaThrust(player.spike3, player.drawangle-ANG30, 30*FRACUNIT)
				end
			end
		else
			player.nailtimer = 0
		end
	end
end)

addHook("ThinkFrame", function()
	for player in players.iterate
		if not(player.mo and player.mo.valid and(player.mo.skin == "voidy"))
			continue
		end
		if (player.frenzied == 1) and (player.mo.sprite == SPR_PLAY)
			if (frenzyspritechange[player.mo.sprite2])
				player.mo.sprite2 = frenzyspritechange[$1]
			end
			if (player.mo.sprite2 == SPR2_TAL7)
				if (player.mo.tics == 1)
					player.frenzyfallframe = ($1 + 1)%2
				end
				player.mo.frame = player.frenzyfallframe
			else
				player.frenzyfallframe = 0
			end
			if (player.mo.sprite2 == SPR2_TAL4)
				if (player.mo.tics == 1)
					player.frenzyrollframe = ($1 + 1)%4
				end
				player.mo.frame = player.frenzyrollframe
			else
				player.frenzyrollframe = 0
			end
			if (player.mo.sprite2 == SPR2_TAL0)
				if (leveltime%7 == 0)
					player.frenzystandframe = ($1 + 1)%4
				end
				player.mo.frame = player.frenzystandframe
			else
				player.frenzystandframe = 0
			end
			if (player.mo.sprite2 == SPR2_TAL1)
				if (player.mo.tics == 1)
					player.frenzywalkframe = ($1 + 1)%8
				end
				player.mo.frame = player.frenzywalkframe
			else
				player.frenzywalkframe = 0
			end
			if (player.mo.sprite2 == SPR2_TAL2)
				if (player.mo.tics == 1)
					player.frenzyrunframe = ($1 + 1)%8
				end
				player.mo.frame = player.frenzyrunframe
			else
				player.frenzyrunframe = 0
			end
			if (player.mo.sprite2 == SPR2_TAL9)
				if (leveltime%12 == 0)
					player.frenzyedgeframe = ($1 + 1)%2
				end
				player.mo.frame = player.frenzyedgeframe
			else	
				player.frenzyedgeframe = 0
			end
		elseif (frenzyspriterestore[player.mo.sprite2])
			player.mo.sprite2 = frenzyspriterestore[player.mo.sprite2]
		end
	end
end)

addHook("MobjMoveBlocked", function(mo,mobj,line)
	if mo and mo.valid and not (mobj and mobj.valid and mobj.flags & (MF_MONITOR|MF_ENEMY|MF_BOSS))
		if line and line.valid
			if PTR_GlideClimbTraverse(mo,line)
			and mo.player and mo.player.valid 
			and mo.skin == "voidy"
				local real,ang,sec = PTR_GlideClimbTraverse(mo,line)
				if P_IsClimbingValid(mo.player,ang) and (mo.state == S_PLAY_GLIDE) and not (mo.eflags & MFE_GOOWATER)
					mo.angle = ang
					P_BounceMove(mo)
					P_SetObjectMomZ(mo, 20*FRACUNIT)
					mo.player.drawangle = ang + ANGLE_180
					mo.state = S_PLAY_ROLL
					local circle = P_SpawnMobjFromMobj(mo, 0, 0, mo.scale * 19, MT_REBOUND)
					circle.angle = ang + ANGLE_90
					circle.scale = 0
					circle.destscale = 10*FRACUNIT
					circle.color = mo.color
					circle.colorized = true
					P_StartQuake(5*FRACUNIT, TICRATE*1/3)
					S_StartSound(mo, sfx_vowall)
					circle.fuse = 9
				end
			end
		elseif mobj and mobj.valid
			if mo.player and mo.player.valid 
			and mo.skin == "voidy"
				local ang = R_PointToAngle2(mo.x,mo.y,mobj.x,mobj.y)
				if (mo.state == S_PLAY_GLIDE) and not (mo.eflags & MFE_GOOWATER)
					mo.angle = ang
					P_BounceMove(mo)
					P_SetObjectMomZ(mo, 20*FRACUNIT)
					mo.player.drawangle = ang + ANGLE_180
					mo.state = S_PLAY_ROLL
					local circle = P_SpawnMobjFromMobj(mo, 0, 0, mo.scale * 19, MT_REBOUND)
					circle.angle = ang + ANGLE_90
					circle.scale = 0
					circle.destscale = 10*FRACUNIT
					circle.color = mo.color
					circle.colorized = true
					P_StartQuake(5*FRACUNIT, TICRATE*1/3)
					S_StartSound(mo, sfx_vowall)
					circle.fuse = 9
				end
			end
		end
	end
end, MT_PLAYER)

addHook("PlayerCanDamage", function(player, mohit)
	if player.mo.skin == "voidy"
		if player.mo.state == S_PLAY_GLIDE 
		or (player.mo.state == S_BASIC_AIRFINISHB2 or player.mo.state == S_BASIC_AIRFINISHB3) 
		or (player.mo.state == S_FRENZY_AIRFINISHB3) 
		or player.mo.state == S_PLAY_BATTLEFALL 
		or (player.stilltimer >= 50 and player.frenzied == 1)
		or player.powers[pw_super]
			if mohit.flags & MF_ENEMY
			or mohit.flags & MF_MONITOR
			or mohit.flags & MF_SHOOTABLE
			or mohit.flags & MF_BOSS
				return true
			end
		end
		if player.mo.state == S_FRENZY_AIRFINISHB2
			if mohit.flags & MF_MONITOR
				return true
			end
		end
	end
end)

addHook("ShouldDamage", function(mo, inf, src, dmg, dmgt)
	if (mo and (mo.skin == "voidy") and mo.player)
		if ((inf and inf.valid) or (src and src.valid))
			if mo.state == S_PLAY_GLIDE 
			or mo.player.dodgeroll == 1 
			or mo.state == S_BASIC_AIRFINISHA2 
			or mo.state == S_BASIC_AIRFINISHA3 
			or mo.state == S_BASIC_AIRFINISHB2 
			or mo.state == S_BASIC_AIRFINISHB3 
			or mo.state == S_FRENZY_AIRFINISHA2 
			or mo.state == S_FRENZY_AIRFINISHA3 
			or mo.state == S_FRENZY_AIRFINISHB2 
			or mo.state == S_FRENZY_AIRFINISHB3 
			or mo.state == S_PLAY_BATTLEFALL 
			or mo.state == S_BASIC_ENTERSTANCE 
			or mo.state == S_FRENZY_ENTERSTANCE 
			or mo.player.transforming == 1 
			or (mo.player.succconfirm and mo.player.frenzied == 1)
				return false
			end
		end
	end
end, MT_PLAYER)

local function VoidyPerfectGuard(mo)
	P_InstaThrust(mo, mo.angle, -10*FRACUNIT)
	S_StartSound(mo, sfx_s259)
	mo.player.guardtimer = 0
	if mo.player.frenzied == 1
		if mo.state == S_FRENZY_WINGGUARD_FIN
			mo.state = S_FRENZY_WINGGUARD_FIN
			mo.frame = C
		else
			mo.state = S_FRENZY_WINGGUARD
		end
	else
		if mo.state == S_BASIC_WINGGUARD_FIN
			mo.state = S_BASIC_WINGGUARD_FIN
			mo.frame = C
		else
			mo.state = S_BASIC_WINGGUARD
		end
	end
end
local function VoidyGuardDamage(tgt, inf, src)
	if tgt and tgt.valid
		if tgt.skin == "voidy"
			if inf and inf.valid and tgt.player.guarding
				VoidyPerfectGuard(tgt)
				if (inf.flags & MF_ENEMY)
					P_InstaThrust(inf, inf.angle, -20*FRACUNIT)
					if inf.type == MT_GOLDBUZZ or inf.type == MT_REDBUZZ
						inf.tics = $+8
					end
				end
				return true
			end
			if tgt.player.tourmalinecollected == 1 and tgt.player.frenzied == 1 and tgt.player.rings > 0
				P_DoPlayerPain(tgt.player)
				P_RemoveShield(tgt.player)
				P_SetObjectMomZ(tgt, 0*FRACUNIT)
				S_StartSound(tgt, sfx_nghurt)
				if tgt.player.rings > 1
					P_PlayerRingBurst(tgt.player, tgt.player.rings/2)
					P_GivePlayerRings(tgt.player, -tgt.player.rings/2)
				else
					P_PlayerRingBurst(tgt.player, 1)
					P_GivePlayerRings(tgt.player, -1)
				end
				S_StartSound(tgt, sfx_altow1)
				return true
			end
		end
	end
end
addHook("MobjDamage", VoidyGuardDamage, MT_PLAYER)

local function VoidyAttackCollide(thing, tmthing)
	if thing and thing.valid and tmthing and tmthing.valid
	and thing.z - thing.scale <= tmthing.z + tmthing.height + (tmthing and P_MobjFlip(tmthing) or tmthing.momz)
	and thing.z + thing.height + thing.scale >= tmthing.z + (tmthing and P_MobjFlip(tmthing) or tmthing.momz) 
	and (thing.state == S_FRENZY_AIRFINISHB2 or thing.player.guarding)
		if thing.state == S_FRENZY_AIRFINISHB2 and (tmthing.flags & MF_SHOOTABLE)
			thing.momx = 0*FRACUNIT
			thing.momy = 0*FRACUNIT
			local stabby = P_SpawnMobjFromMobj(thing, 0, 0, -80*FRACUNIT, MT_STABEXPL)
			S_StartSound(thing, sfx_rail2)
			P_StartQuake(30*FRACUNIT, TICRATE*1/3)
			stabby.target = thing
			stabby.scale = FRACUNIT*2
			stabby.fuse = 20
			thing.player.chasertimer = 0
		end
		if thing.player.guarding and ((tmthing.flags & MF_PAIN) or (tmthing.flags & MF_MISSILE))
			VoidyPerfectGuard(thing)
		end
		return true
	end
end
addHook("MobjCollide", VoidyAttackCollide, MT_PLAYER)

addHook("MobjLineCollide", VoidyCrumbleCollide, MT_RIGHTSHREDDER)
addHook("MobjThinker", BasicShredderThink, MT_RIGHTSHREDDER)
addHook("MobjLineCollide", VoidyCrumbleCollide, MT_LEFTSHREDDER)
addHook("MobjThinker", BasicShredderThink, MT_LEFTSHREDDER)
addHook("MobjLineCollide", VoidyCrumbleCollide, MT_DUALSHREDDER)
addHook("MobjThinker", BasicShredderThink, MT_DUALSHREDDER)
addHook("MobjMoveBlocked", VoidyFakeNoClip, MT_DUALSHREDDER)
addHook("MobjLineCollide", VoidyCrumbleCollide, MT_ENERGYPILLAR)
addHook("MobjThinker", BasicShredderThink, MT_ENERGYPILLAR)
addHook("MobjLineCollide", VoidyCrumbleCollide, MT_VOIDYROCK)
addHook("MobjThinker", BasicShredderThink, MT_VOIDYROCK)
addHook("MobjMoveCollide", function(mo, mohit)
	if not mo.valid 
	and not mohit.valid 
	or mo.z > mohit.z + mohit.height 
	or mohit.z > mo.z + mo.height
		return
	end
	if mohit == mo.target
		return
	end
	if (mohit.flags & MF_SHOOTABLE)
		return false
	end
end, MT_VOIDYROCK)

addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		if (src.eflags & MFE_VERTICALFLIP)
			P_SetOrigin(mo, src.x, src.y, src.z - 10*FRACUNIT)
		else
			P_SetOrigin(mo, src.x, src.y, src.z + 50*FRACUNIT)
		end
		if src.player.voidycharge == 0 or src.player.voidycharge == 50
			mo.state = S_NULL
		end
	end
end, MT_VOIDYCHARGEAURA)

addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		if (src.eflags & MFE_VERTICALFLIP)
			P_SetOrigin(mo, src.x, src.y, src.z - 70*FRACUNIT)
		else
			P_SetOrigin(mo, src.x, src.y, src.z - 10*FRACUNIT)
		end
	end
end, MT_VOIDYCHARGEFLASH)

addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_SHOOTABLE and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 2)
				end
			end
			if (found.valid and found.type == MT_EGGSHIELD) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				P_KillMobj(found, mo, src)
			end
			if (found.valid and found.type == MT_METALSONIC_BATTLE) 
			and found.state == found.info.spawnstate
			and not (found.flags2 & MF2_CLASSICPUSH) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
	end
end, MT_VOIDYSPIKE)

addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		if src.type == MT_PLAYER
			P_SetObjectMomZ(mo, -40*FRACUNIT)
		end
	end
end, MT_CRESCENTDANCER)
addHook("MobjMoveCollide", function(mo, mohit)
	if not mo.valid 
	and not mohit.valid 
	or mo.z > mohit.z + mohit.height 
	or mohit.z > mo.z + mo.height
		return
	end
	if not (mohit.flags & MF_SHOOTABLE)
	or mohit.health <= 0
		return
	end
	if mohit == mo.target
		return
	end
	P_DamageMobj(mohit, mo, mo.target, 2)
end, MT_CRESCENTDANCER)

addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		mo.color = SKINCOLOR_NEON
		mo.colorized = true
		if mo.scale >= 3*FRACUNIT
			if (src.eflags & MFE_VERTICALFLIP)
				mo.z = src.z - 200*FRACUNIT
			else	
				mo.z = src.z + 15*FRACUNIT
			end
		elseif mo.scale > 2*FRACUNIT
			if (src.eflags & MFE_VERTICALFLIP)
				mo.z = src.z - 150*FRACUNIT
			else	
				mo.z = src.z + 20*FRACUNIT
			end
		elseif mo.scale > 1*FRACUNIT
			if (src.eflags & MFE_VERTICALFLIP)
				mo.z = src.z - 85*FRACUNIT
			else
				mo.z = src.z + 25*FRACUNIT
			end
		elseif mo.scale == 1*FRACUNIT
			if (mo.eflags & MFE_VERTICALFLIP)
				mo.z = src.z - 80*FRACUNIT
			else
				mo.z = src.z + 30*FRACUNIT
			end
		end
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_BOSS and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 1)
				end
				if ValidVoidyObject(found) and found.health
					if R_PointToDist2(src.x, src.y, found.x, found.y)
						if found.type == MT_RING or found.type == MT_COIN or found.type == MT_BLUESPHERE
							found.tracer = src
						end
						local range = 700*FRACUNIT
						local dist = R_PointToDist2(src.x, src.y, found.x, found.y)
						if dist < FRACUNIT
							dist = FRACUNIT
						end
						local PullForce = range/dist * 3
						if PullForce > 30
							PullForce = 30
						end
						PullForce = $ * FRACUNIT
						if found != src
							if found.type == MT_PLAYER
								P_Thrust(found, src.angle+ANGLE_180, FRACUNIT*1/5)
							else
								VoidyAttract(found, src, PullForce)
							end
						end
					end
				end
			end
			if (found.valid and found.type == MT_EGGSHIELD) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				P_KillMobj(found, mo, src)
			end
			if (found.valid and found.flags & MF_MISSILE) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				P_RemoveMobj(found)
			end
			if (found.valid and found.type == MT_METALSONIC_BATTLE) 
			and found.state == found.info.spawnstate
			and not (found.flags2 & MF2_CLASSICPUSH) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
	end
end, MT_SUCCFX)
addHook("MobjMoveBlocked", VoidyFakeNoClip, MT_SUCCFX)

addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		if src.type == MT_PLAYER
			if src.player.frenzied == 0
				P_SetOrigin(mo, src.x + FixedMul(80*FRACUNIT, cos(src.angle)), src.y + FixedMul(80*FRACUNIT, sin(src.angle)), src.z)
			else
				P_SetOrigin(mo, src.x, src.y, src.z)
			end
			if not src.player.succconfirm
				mo.state = S_NULL
			end
		else
			if src.frenzied == 0
				P_SetOrigin(mo, src.x + FixedMul(80*FRACUNIT, cos(src.angle)), src.y + FixedMul(80*FRACUNIT, sin(src.angle)), src.z)
			else
				P_SetOrigin(mo, src.x, src.y, src.z)
			end
			if not src.succconfirm
				mo.state = S_NULL
			end
		end
	end
end, MT_VACCHITBOX)
addHook("MobjMoveBlocked", VoidyFakeNoClip, MT_VACCHITBOX)
addHook("MobjMoveCollide", function(mo, mohit)
	if not mo.valid 
	and not mohit.valid 
	or mo.z > mohit.z + mohit.height 
	or mohit.z > mo.z + mo.height
		return
	end
	if not (mohit.flags & MF_SHOOTABLE)
	or mohit.health <= 0
		return
	end
	if mohit == mo.target
		return
	end
	if (mohit.flags & MF_ENEMY) 
	or (mohit.flags & MF_MONITOR) 
	or (mohit.type == MT_PLAYER)
		P_DamageMobj(mohit, mo, mo.target, 999, DMG_INSTAKILL)
	end
end, MT_VACCHITBOX)

addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		mo.color = SKINCOLOR_NEON
		mo.scale = FRACUNIT*3/2
		if src.type == MT_PLAYER
			if src.state == S_PLAY_FRENZY_TRANS3
				mo.state = S_FRENZYAURA1
				mo.auraactive = true
			end
			if src.player.frenzied == 0
			or src.player.powers[pw_super]
				mo.state = S_INVISIBLE
				mo.auraactive = false
			end
		else
			A_OverlayThink(mo, 0, 0)
			if src.type == MT_VOIDY2
				if not mo.auraactive and src.health != 0
					mo.state = S_FRENZYAURA1
					mo.auraactive = true
				end
			end
			if src.type == MT_VOIDY3
				if src.state == S_VOIDY3_FRENZYTRANS9
					mo.state = S_FRENZYAURA1
					mo.auraactive = true
				end
				if src.frenzied == 0
					mo.state = S_INVISIBLE
					mo.auraactive = false
				end
			end
		end
		if mo.auraactive
			if (leveltime%70 == 0)
				S_StartSound(mo, sfx_drkaur)
			end
		else
			S_StopSound(mo)
		end
	end
end, MT_FRENZYAURA)

addHook("MobjLineCollide", VoidyCrumbleCollide, MT_FRENZY_RIGHTSHREDDER)
addHook("MobjThinker", FrenzyShredderThink, MT_FRENZY_RIGHTSHREDDER)
addHook("MobjLineCollide", VoidyCrumbleCollide, MT_FRENZY_LEFTSHREDDER)
addHook("MobjThinker", FrenzyShredderThink, MT_FRENZY_LEFTSHREDDER)
addHook("MobjLineCollide", VoidyCrumbleCollide, MT_FRENZY_DUALSHREDDER)
addHook("MobjThinker", FrenzyShredderThink, MT_FRENZY_DUALSHREDDER)

addHook("MobjLineCollide", VoidyCrumbleCollide, MT_FRENZY_ENERGYBALL)
addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid	
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_SHOOTABLE and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 2)
				end
			end
			if (found.valid and found.type == MT_METALSONIC_BATTLE) 
			and found.state == found.info.spawnstate
			and not (found.flags2 & MF2_CLASSICPUSH) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
		VoidyCheckAndCrumble(mo, mo.subsector.sector)
		if mo.state == S_FRENZY_ENERGYBALLEXPL1
			mo.laser = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_FRENZY_ENERGYPILLAR)
			mo.laser.target = src
			mo.laser.scale = 3*FRACUNIT
			mo.laser.color = SKINCOLOR_NEON
			mo.laser.blendmode = AST_ADD
			S_StartSound(mo, sfx_s3k54)
			P_StartQuake(30*FRACUNIT, TICRATE*1/3)
		end
	end
end, MT_FRENZY_ENERGYBALL)
addHook("MobjMoveCollide", function(mo, mohit)
	if not mo.valid 
	and not mohit.valid 
	or mo.z > mohit.z + mohit.height 
	or mohit.z > mo.z + mo.height
		return
	end
	if mohit == mo.target
		return
	end
	if not (mohit.flags & MF_SHOOTABLE)
		return false
	end
end, MT_FRENZY_ENERGYBALL)

addHook("MobjLineCollide", VoidyCrumbleCollide, MT_FRENZY_ENERGYPILLAR)
addHook("MobjThinker", FrenzyShredderThink, MT_FRENZY_ENERGYPILLAR)
addHook("MobjMoveBlocked", VoidyFakeNoClip, MT_FRENZY_ENERGYPILLAR)
addHook("MobjLineCollide", VoidyCrumbleCollide, MT_ENERGYTSUNAMI)
addHook("MobjThinker", FrenzyShredderThink, MT_ENERGYTSUNAMI)
addHook("MobjMoveBlocked", VoidyFakeNoClip, MT_ENERGYTSUNAMI)
addHook("MobjDamage", function(target, attack, attacker)
	if target and target.valid
		if attacker and attacker.valid and attacker.skin == "voidy"
			if attacker.state == S_FRENZY_AIRFINISHB3
				if target.flags & MF_SHOOTABLE
					P_DamageMobj(target, attacker, 2)
				end
			end
		end
	end
end)
addHook("MobjLineCollide", VoidyCrumbleCollide, MT_STABEXPL)
addHook("MobjThinker", FrenzyShredderThink, MT_STABEXPL)
addHook("MobjMoveBlocked", VoidyFakeNoClip, MT_STABEXPL)

addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		if P_IsObjectOnGround(mo) and (leveltime%2 == 0)
			mo.flame = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_EARTHSCORCHER_FLAME)
			mo.flame.scale = 5*FRACUNIT
			mo.flame.destscale = FRACUNIT*3/2
			mo.flame.scalespeed = FRACUNIT*1/5
			mo.flame.target = src
		end
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_SHOOTABLE and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 4)
				end
			end
			if (found.valid and found.type == MT_METALSONIC_BATTLE) 
			and found.state == found.info.spawnstate
			and not (found.flags2 & MF2_CLASSICPUSH) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
	end
end, MT_EARTHSCORCHER)
addHook("MobjMoveCollide", function(mo, mohit)
	if not mo.valid 
	and not mohit.valid 
	or mo.z > mohit.z + mohit.height 
	or mohit.z > mo.z + mo.height
		return
	end
	if mohit == mo.target
		return
	end
	if (mohit.flags & MF_SHOOTABLE)
		return false
	end
end, MT_EARTHSCORCHER)
addHook("MobjRemoved", function(mo)
	local src = mo.target
	if src and src.valid
		if P_IsObjectOnGround(mo)
			mo.flame = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_EARTHSCORCHER_FLAME)
			mo.flame.target = src
			mo.flame.scale = 5*FRACUNIT
			mo.flame.destscale = FRACUNIT*3/2
			mo.flame.scalespeed = FRACUNIT*1/5
		end
	end
end, MT_EARTHSCORCHER)

addHook("MobjMoveCollide", function(mo, mohit)
	if not mo.valid 
	and not mohit.valid 
	or mo.z > mohit.z + mohit.height 
	or mohit.z > mo.z + mo.height
		return
	end
	if not (mohit.flags & MF_SHOOTABLE)
	or mohit.health <= 0
		return
	end
	if mohit == mo.target
		return
	end
	P_DamageMobj(mohit, mo, mo.target, 2)
end, MT_EARTHSCORCHER_FLAME)

addHook("MobjSpawn", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		if (src.eflags & MFE_VERTICALFLIP)	
			mo.z = src.z - 150*FRACUNIT
		else
			mo.z = src.z - 100*FRACUNIT
		end
	end
end, MT_CRESCENTREAPER)
addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_SHOOTABLE and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 4)
				end
			end
			if (found.valid and found.type == MT_EGGSHIELD) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				P_KillMobj(found, mo, src)
			end
			if (found.valid and found.type == MT_METALSONIC_BATTLE) 
			and found.state == found.info.spawnstate
			and not (found.flags2 & MF2_CLASSICPUSH) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
	end
end, MT_CRESCENTREAPER)

addHook("MobjLineCollide", VoidyCrumbleCollide, MT_VOIDYBLACKHOLE)
addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid	
		if (src.eflags & MFE_VERTICALFLIP)
			P_SetOrigin(mo, src.x, src.y, src.z - 150*FRACUNIT)
		else
			P_SetOrigin(mo, src.x, src.y, src.z - 70*FRACUNIT)
		end
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_ENEMY) 
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 999, DMG_INSTAKILL)
				end
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
		VoidyCheckAndCrumble(mo, mo.subsector.sector)
		if not src.player.powers[pw_super]
			S_StopSound(mo)
			mo.state = S_NULL
		end
	end
end, MT_VOIDYBLACKHOLE)
addHook("MobjMoveCollide", function(mo, mohit)
	if not mo.valid 
	and not mohit.valid 
	or mo.z > mohit.z + mohit.height 
	or mohit.z > mo.z + mo.height
		return
	end
	if (mohit.flags & MF_MONITOR)
		P_DamageMobj(mohit, mo, mo.target, 999, DMG_INSTAKILL)
	end
end, MT_VOIDYBLACKHOLE)

local function CloneThink(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		mo.angle = src.angle
		if src.state == S_BASIC_GROUNDRIGHT1 
		or src.state == S_FRENZY_GROUNDRIGHT1
			mo.state = S_TWIN_GROUNDRIGHT1
		end
		if src.state == S_BASIC_GROUNDLEFT1 
		or src.state == S_FRENZY_GROUNDLEFT1
			mo.state = S_TWIN_GROUNDLEFT1
		end
		if src.state == S_BASIC_AIRRIGHT1 
		or src.state == S_FRENZY_AIRRIGHT1
			mo.state = S_TWIN_AIRRIGHT1
		end
		if src.state == S_BASIC_AIRLEFT1 
		or src.state == S_FRENZY_AIRLEFT1
			mo.state = S_TWIN_AIRLEFT1
		end
		if src.state == S_BASIC_GROUNDRIGHT1 
		or src.state == S_BASIC_AIRRIGHT1 
		or src.state == S_FRENZY_GROUNDRIGHT1 
		or src.state == S_FRENZY_AIRRIGHT1
			if not mo.slash1spawned	
				if src.player.frenzied == 0
					S_StartSound(mo, sfx_claw1)
					mo.shredder = P_SpawnMobjFromMobj(mo, FixedMul(50*FRACUNIT, cos(mo.angle)), FixedMul(50*FRACUNIT, sin(mo.angle)), 0, MT_RIGHTSHREDDER)	
					mo.shredder.target = src
				else
					S_StartSound(mo, sfx_xclaw1)
					mo.shredder = P_SpawnMobjFromMobj(mo, FixedMul(100*FRACUNIT, cos(mo.angle)), FixedMul(100*FRACUNIT, sin(mo.angle)), -100*FRACUNIT, MT_FRENZY_RIGHTSHREDDER)
					P_StartQuake(10*FRACUNIT, TICRATE*1/3)
					mo.shredder.target = src
				end
				mo.slash1spawned = true
			end
		end
		if src.state == S_BASIC_GROUNDLEFT1 
		or src.state == S_BASIC_AIRLEFT1 
		or src.state == S_FRENZY_GROUNDLEFT1 
		or src.state == S_FRENZY_AIRLEFT1
			if not mo.slash2spawned	
				if src.player.frenzied == 0
					S_StartSound(mo, sfx_claw1)
					mo.shredder = P_SpawnMobjFromMobj(mo, FixedMul(50*FRACUNIT, cos(mo.angle)), FixedMul(50*FRACUNIT, sin(mo.angle)), 0, MT_LEFTSHREDDER)	
					mo.shredder.target = src
				else
					S_StartSound(mo, sfx_xclaw1)
					mo.shredder = P_SpawnMobjFromMobj(mo, FixedMul(100*FRACUNIT, cos(mo.angle)), FixedMul(100*FRACUNIT, sin(mo.angle)), -100*FRACUNIT, MT_FRENZY_LEFTSHREDDER)
					P_StartQuake(10*FRACUNIT, TICRATE*1/3)
					mo.shredder.target = src
				end
				mo.slash2spawned = true
			end
		end
		if src.state == S_BASIC_GROUNDFINISHA1 
		or src.state == S_FRENZY_GROUNDFINISHA1
			mo.state = S_TWIN_DASH1
		end
		if mo.state == S_TWIN_DASH2 and not mo.starteddash
			mo.starteddash = true
			if src.player.frenzied == 1
				P_InstaThrust(mo, src.player.olddraw, 50*FRACUNIT)
				S_StartSound(mo, sfx_clndsh)
				if not mo.spawnedaura
					mo.spawnedaura = true
					mo.aura = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_DASHAURA)
					mo.aura.scale = FRACUNIT
					mo.aura.destscale = 3*FRACUNIT
					mo.aura.scalespeed = FRACUNIT*1/5
					mo.aura.color = SKINCOLOR_NEON
					mo.aura.target = mo
					mo.aura.tracer = src
				end
			else
				S_StartSound(mo, sfx_zoom)
				P_InstaThrust(mo, mo.angle, 30*FRACUNIT)
			end
		end
		if src.player.finishertimer > 0
			if not P_IsObjectOnGround(mo)
				mo.state = S_TWIN_GLIDE
				P_InstaThrust(mo, mo.angle, 50*FRACUNIT)
				P_SetObjectMomZ(mo, -20*FRACUNIT)
			else
				mo.state = S_TWIN_LAND
				mo.momx = 0*FRACUNIT
				mo.momy = 0*FRACUNIT
				P_SetObjectMomZ(mo, 0*FRACUNIT)
				if not mo.spawnedwave	
					mo.spawnedwave = true
					P_StartQuake(10*FRACUNIT, TICRATE*1/3)
					S_StartSound(mo, sfx_s3k9b)
					if src.player.frenzied == 0
						for i = 1, 5
							mo.wave = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_IMPACTSHOCKWAVE)
							mo.wave.target = src
							P_InstaThrust(mo.wave, mo.angle, 60*FRACUNIT)
							mo.wave2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_IMPACTSHOCKWAVE)
							mo.wave2.target = src
							P_InstaThrust(mo.wave2, mo.angle-ANG10*i, 60*FRACUNIT)
							mo.wave3 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_IMPACTSHOCKWAVE)
							mo.wave3.target = src
							P_InstaThrust(mo.wave3, mo.angle+ANG10*i, 60*FRACUNIT)
						end
					else
						for i = 1, 50
							mo.wave = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_IMPACTSHOCKWAVE)
							mo.wave.target = src
							P_InstaThrust(mo.wave, mo.angle, 60*FRACUNIT)
							mo.wave2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_IMPACTSHOCKWAVE)
							mo.wave2.target = src
							P_InstaThrust(mo.wave2, mo.angle-ANG10*i, 60*FRACUNIT)
							mo.wave3 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_IMPACTSHOCKWAVE)
							mo.wave3.target = src
							P_InstaThrust(mo.wave3, mo.angle+ANG10*i, 60*FRACUNIT)
						end
					end
				end
			end
		end
		if mo.state == S_TWIN_GROUNDRIGHT1
			mo.frame = A
		end
		if mo.state == S_TWIN_GROUNDRIGHT2
			mo.frame = B
		end
		if mo.state == S_TWIN_GROUNDRIGHT3
			mo.frame = C
		end
		if mo.state == S_TWIN_GROUNDLEFT1
			mo.frame = D
		end
		if mo.state == S_TWIN_GROUNDLEFT2
			mo.frame = E
		end
		if mo.state == S_TWIN_GROUNDLEFT3
			mo.frame = F
		end
		if mo.state == S_TWIN_DASH1
			mo.frame = G
		end
		if mo.state == S_TWIN_DASH2
			mo.frame = H
		end
		if mo.state == S_TWIN_DASH3
			mo.frame = I
		end
		if mo.state == S_TWIN_AIRRIGHT1
			mo.frame = J
		end
		if mo.state == S_TWIN_AIRRIGHT2
			mo.frame = K
		end
		if mo.state == S_TWIN_AIRRIGHT3
			mo.frame = L
		end
		if mo.state == S_TWIN_AIRLEFT1
			mo.frame = M
		end
		if mo.state == S_TWIN_AIRLEFT2
			mo.frame = N
		end
		if mo.state == S_TWIN_AIRLEFT3
			mo.frame = O
		end
		if mo.state == S_TWIN_GLIDE
			mo.frame = P
		end
		if mo.state == S_TWIN_LAND
			mo.frame = Q
		end
		if mo.state == S_TWIN_DASH2 
		or mo.state == S_TWIN_DASH3 
		or mo.state == S_TWIN_GLIDE
			local fx = mo.x
			local fy = mo.y
			local fr = mo.radius
			searchBlockmap("objects", function(mo, found)
				if found.valid
					if (found.flags & MF_SHOOTABLE and found != src)
					and found.z - found.scale <= mo.z + mo.height
					and found.z + found.height + found.scale >= mo.z
						P_DamageMobj(found, mo, src, 1)
					end
				end
				if (found.valid and found.type == MT_METALSONIC_BATTLE) 
				and found.state == found.info.spawnstate
				and not (found.flags2 & MF2_CLASSICPUSH) 
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					found.flags2 = $ | MF2_CLASSICPUSH
				end
			end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
		end
	end
end
addHook("MobjThinker", CloneThink, MT_VOIDYCLONE)
local function DashAuraThink(mo)
	local src = mo.tracer
	if mo and mo.valid and src and src.valid
		mo.angle = src.angle
		A_OverlayThink(mo, 0, 0)
		if (leveltime%5 == 0)
			mo.flags2 = $|MF2_DONTDRAW
		else
			mo.flags2 = $ & ~MF2_DONTDRAW
		end
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_SHOOTABLE and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src, 2)
				end
			end
			if (found.valid and found.type == MT_METALSONIC_BATTLE) 
			and found.state == found.info.spawnstate
			and not (found.flags2 & MF2_CLASSICPUSH) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
	end
end
addHook("MobjThinker", DashAuraThink, MT_DASHAURA)

addHook("MobjLineCollide", VoidyCrumbleCollide, MT_FRENZYEXPLOSION)
addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid	
		if mo.state == S_FRENZYEXPL7
			local fx = mo.x
			local fy = mo.y
			local fr = mo.radius
			searchBlockmap("objects", function(mo, found)
				if found.valid
					if (found.flags & MF_SHOOTABLE and found != src)
					and found.z - found.scale <= mo.z + mo.height
					and found.z + found.height + found.scale >= mo.z
						if found.type == MT_PLAYER
							P_KillMobj(found, mo, src)
						else
							P_DamageMobj(found, mo, src, 4)
						end
					end
				end
				if (found.valid and found.flags & MF_MISSILE)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_RemoveMobj(found)
				end
				if (found.valid and found.type == MT_EGGSHIELD) 
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_KillMobj(found, mo, src)
				end
				if (found.valid and found.type == MT_METALSONIC_BATTLE) 
				and found.state == found.info.spawnstate
				and not (found.flags2 & MF2_CLASSICPUSH) 
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					found.flags2 = $ | MF2_CLASSICPUSH
				end
			end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
			VoidyCheckAndCrumble(mo, mo.subsector.sector)
		end
	end
end, MT_FRENZYEXPLOSION)
addHook("MobjMoveBlocked", VoidyFakeNoClip, MT_FRENZYEXPLOSION)

addHook("MobjThinker", function(mo)
	if mo and mo.valid
		mo.colorized = true
		mo.color = SKINCOLOR_NEON
		mo.scale = FRACUNIT*2
		mo.trail = P_SpawnGhostMobj(mo)
		mo.trail.colorized = true
		mo.trail.color = SKINCOLOR_NEON
		mo.trail.blendmode = AST_ADD
	end
end, MT_QUASARPULSE)

addHook("MobjThinker", function(mo)
	local src = mo.target
	if mo and mo.valid and src and src.valid
		mo.colorized = true
		mo.color = SKINCOLOR_NEON
		mo.blendmode = AST_ADD
		mo.trail = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_STREAMTRAIL)
		mo.trail.target = src
		mo.trail.tracer = mo
		mo.trail.tics = 20
	end
end, MT_QUASARSTREAM)
addHook("MobjMoveCollide", function(mo, mohit)
	if not mo.valid 
	and not mohit.valid 
	or mo.z > mohit.z + mohit.height 
	or mohit.z > mo.z + mo.height
		return
	end
	if mohit == mo.target
		return
	end
	if (mohit.flags & MF_SHOOTABLE)
		return false
	end
end, MT_QUASARSTREAM)
addHook("MobjRemoved", function(mo)
	if mo and mo.valid
		P_StartQuake(50*FRACUNIT, TICRATE*1/2)
		S_StartSound(mo, sfx_s3k5e)
		mo.xpld = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSEXPLODE)
		mo.xpld.scale = 3*FRACUNIT
		for i = 1, 5
			mo.xpld2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSEXPLODE)
			mo.xpld2.scale = 3*FRACUNIT
			P_SetObjectMomZ(mo.xpld2, P_RandomRange(1, 5)*FRACUNIT)
		end
	end
end, MT_QUASARSTREAM)

addHook("MobjThinker", function(mo)
	local src = mo.target
	local trc = mo.tracer
	if mo and mo.valid and src and src.valid	
		mo.colorized = true
		mo.color = SKINCOLOR_NEON
		mo.blendmode = AST_ADD
		if trc and trc.valid
			if not mo.moved
				mo.momx = trc.momx/3
				mo.momy = trc.momy/3
				mo.momz = trc.momz/3
				mo.moved = true
			end
		else
			mo.momx = 0
			mo.momy = 0
			mo.momz = 0
		end
		local fx = mo.x
		local fy = mo.y
		local fr = mo.radius
		searchBlockmap("objects", function(mo, found)
			if found.valid
				if (found.flags & MF_SHOOTABLE and found != src)
				and found.z - found.scale <= mo.z + mo.height
				and found.z + found.height + found.scale >= mo.z
					P_DamageMobj(found, mo, src)
				end
			end
			if (found.valid and found.type == MT_METALSONIC_BATTLE) 
			and found.state == found.info.spawnstate
			and not (found.flags2 & MF2_CLASSICPUSH) 
			and found.z - found.scale <= mo.z + mo.height
			and found.z + found.height + found.scale >= mo.z
				found.flags2 = $ | MF2_CLASSICPUSH
			end
		end, mo, fx-fr, fx+fr, fy-fr, fy+fr)
	end
end, MT_STREAMTRAIL)

addHook("MobjCollide", VoidyKillSpikes, MT_SPIKE)
addHook("MobjCollide", VoidyKillSpikes, MT_WALLSPIKE)

addHook("MobjSpawn", VoidyBlockMap)

addHook("MobjDeath", function(target, attack, attacker)
	if target and target.valid
		if attacker 
		and attacker.valid 
		and attacker.player 
		and attacker.skin == "voidy"
			if (target.type == MT_FLINGRING 
			or target.type == MT_FLINGCOIN 
			or target.type == MT_FLINGBLUESPHERE) 
			and attacker.player.succconfirm
				DoLFGain(attacker.player)
			end
			if target.type == MT_RING 
			or target.type == MT_COIN 
			or target.type == MT_BLUESPHERE
				DoLFGain(attacker.player, 2)
			end
			if target.flags & MF_ENEMY
				DoLFGain(attacker.player, 4)
			end
			if target.flags & MF_BOSS
				DoLFGain(attacker.player, 8)
			end
			if target.flags & MF_MONITOR and attacker.state == S_FRENZY_AIRFINISHB2
				attacker.momx = 0*FRACUNIT
				attacker.momy = 0*FRACUNIT
				local stabby = P_SpawnMobjFromMobj(attacker, 0, 0, -80*FRACUNIT, MT_STABEXPL)
				S_StartSound(attacker, sfx_rail2)
				P_StartQuake(30*FRACUNIT, TICRATE*1/3)
				stabby.target = attacker
				stabby.scale = FRACUNIT*2
				stabby.fuse = 20
				attacker.player.chasertimer = 0
			end
			if target.type == MT_PLAYER
				DoLFGain(attacker.player, 10)
			end
		end
	end
end)

hud.add(function(v, player)
	if player.mo == nil or player.mo.skin ~= "voidy" or srb2p or PSO
		return
	end
	local zoomtop = v.cachePatch("VDYZOTOP")
	local zoomleft = v.cachePatch("VDYZOLEFT")
	local zoomright = v.cachePatch("VDYZORIGT")
	local zoombottom = v.cachePatch("VDYZOBOT")
	if player.mo.state == S_PLAY_GLIDE 
	or player.mo.state == S_PLAY_FRENZY_INTRO1 
	or player.mo.state == S_PLAY_SUPER_INTRO1
		v.draw(0, 0, zoomtop, V_SNAPTOTOP|V_PERPLAYER|V_50TRANS, v.getColormap(nil,SKINCOLOR_WHITE))
		v.draw(0, 0, zoomleft, V_SNAPTOLEFT|V_PERPLAYER|V_50TRANS, v.getColormap(nil,SKINCOLOR_WHITE))
		v.draw(220, 0, zoomright, V_SNAPTORIGHT|V_PERPLAYER|V_50TRANS, v.getColormap(nil,SKINCOLOR_WHITE))
		v.draw(0, 100, zoombottom, V_SNAPTOBOTTOM|V_PERPLAYER|V_50TRANS, v.getColormap(nil,SKINCOLOR_WHITE))
	end
	local huddisplay = v.cachePatch("VDYHUD1")
	local frenzysleep = v.cachePatch("VDYHUD2")
	local iconflash = v.cachePatch("VDYHUD3")
	local frenzyactive = v.cachePatch("VDYHUD4")
	local voidinstall = v.cachePatch("VDYHUD5")
	local hudbg1 = v.cachePatch("VDYHUD6")
	local hudbg2 = v.cachePatch("VDYHUD7")
	local hudbg3 = v.cachePatch("VDYHUD8")
	local hudbg4 = v.cachePatch("VDYHUD9")
	local hudbg5 = v.cachePatch("VDYHUDA")
	if leveltime >= 50
		if player.maxlifeforce == 80	
			v.draw(150, 135, hudbg1, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER, v.getColormap(nil,player.mo.color))
		elseif player.maxlifeforce == 85
			v.draw(150, 135, hudbg2, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER, v.getColormap(nil,player.mo.color))
		elseif player.maxlifeforce == 90
			v.draw(150, 135, hudbg3, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER, v.getColormap(nil,player.mo.color))
		elseif player.maxlifeforce == 95
			v.draw(150, 135, hudbg4, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER, v.getColormap(nil,player.mo.color))
		elseif player.maxlifeforce == 100
			v.draw(150, 135, hudbg5, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER, v.getColormap(nil,player.mo.color))
		end
		v.drawFill(191, 165, player.maxlifeforce, 8, 31|V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		v.drawFill(191, 165, player.lifeforce, 8, 163|V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		if player.lifeforce >= 80 and player.frenzied == 0
			if not (player.exiting) 
			and not (P_PlayerInPain(player) or player.playerstate == PST_DEAD) 
			and ((player.powers[pw_carry] == CR_NONE) and not (player.pflags & PF_SPINNING)) 
			and (P_IsObjectOnGround(player.mo)) 
			and not (player.powers[pw_super]) 
			and (player.attacking == 0) 
			and (player.transforming == 0)
				v.drawString(195, 166, "Ready! (Custom 1)", V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER|V_INVERTMAP, "thin")
			else
				v.drawString(195, 166, "Ready! (Custom 1)", V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER|V_INVERTMAP|V_50TRANS, "thin")
			end
		end
		if player.maxlifeforce >= 85
			v.drawFill(271, 165, 1, 8, 1|V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		end
		v.draw(130, 135, huddisplay, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER, v.getColormap(nil,player.mo.color))
		if player.powers[pw_super]
			v.draw(130, 135, voidinstall, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		else
			if player.frenzied == 1
				v.draw(130, 135, frenzyactive, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
			else
				v.draw(130, 135, frenzysleep, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
			end
		end
		if player.mo.state == S_PLAY_FRENZY_TRANS1 
		or player.mo.state == S_PLAY_FRENZY_TRANS2 
		or player.mo.state == S_PLAY_FRENZY_TRANS3 
		or player.mo.state == S_PLAY_SUPER_TRANS1 
		or player.mo.state == S_PLAY_SUPER_TRANS2 
		or player.mo.state == S_PLAY_SUPER_TRANS3
			v.draw(130, 135, iconflash, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER)
		end
		if player.mo.state == S_PLAY_FRENZY_TRANS4 
		or player.mo.state == S_PLAY_SUPER_TRANS4
			v.draw(130, 135, iconflash, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER|V_40TRANS)
		end
		if player.mo.state == S_PLAY_FRENZY_TRANS5 
		or player.mo.state == S_PLAY_SUPER_TRANS5
			v.draw(130, 135, iconflash, V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_PERPLAYER|V_80TRANS)
		end
	end
	local emerdudes3 = v.cachePatch('VHUDA0')
	if (All7Emeralds(emeralds))
		if (leveltime > 0) and (leveltime < 150)
			v.draw(70, 60, emerdudes3, V_PERPLAYER)
			v.drawString(5, 150, "Voidy can now transform into Abyssal Voidy", V_PERPLAYER)
			v.drawString(50, 160, "by pressing Custom 1 in midair!", V_PERPLAYER)
		end
	end
end)

hud.add(function(v)
	local p = displayplayer
	if p.mo == nil or p.mo.skin ~= "voidy" or srb2p or PSO
		return
	end
	local eudialyte = v.cachePatch("EUDIA1")
	local selenite = v.cachePatch("SELEN1")
	local carnelian = v.cachePatch("CARNE1")
	local tourmaline = v.cachePatch("TOURM1")
	local topaz = v.cachePatch("TOPAZ1")
	local garnet = v.cachePatch("GARNE1")
	local moonstone = v.cachePatch("MOONS1")
	local no_eudialyte = v.cachePatch("EUDIA2")
	local no_selenite = v.cachePatch("SELEN2")
	local no_carnelian = v.cachePatch("CARNE2")
	local no_tourmaline = v.cachePatch("TOURM2")
	local no_topaz = v.cachePatch("TOPAZ2")
	local no_garnet = v.cachePatch("GARNE2")
	local no_moonstone = v.cachePatch("MOONS2")
	if p.shard1collected == 1
		v.draw(150, 40, eudialyte, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(150, 40, no_eudialyte, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	end
	if p.shard2collected == 1
		v.draw(170, 20, eudialyte, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(170, 20, no_eudialyte, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	end
	if p.shard3collected == 1
		v.draw(125, 20, eudialyte, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(125, 20, no_eudialyte, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	end
	if p.shard4collected == 1
		v.draw(145, 40, eudialyte, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(145, 40, no_eudialyte, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	end
	if p.selenitecollected == 1
		v.draw(120, 60, selenite, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(120, 60, no_selenite, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	end
	if p.carneliancollected == 1
		v.draw(120, 95, carnelian, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(120, 95, no_carnelian, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	end
	if p.tourmalinecollected == 1
		v.draw(120, 130, tourmaline, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(120, 130, no_tourmaline, V_SNAPTOLEFT|V_SNAPTOTOP|V_PERPLAYER)
	end
	if p.topazcollected == 1
		v.draw(165, 60, topaz, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(165, 60, no_topaz, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	end
	if p.garnetcollected == 1
		v.draw(165, 95, garnet, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(165, 95, no_garnet, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	end
	if p.moonstonecollected == 1
		v.draw(165, 130, moonstone, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	else
		v.draw(165, 130, no_moonstone, V_SNAPTORIGHT|V_SNAPTOTOP|V_PERPLAYER)
	end
end, "scores")