freeslot(
	"S_PLAY_DRIP", --OVERWHELMING POWER
	"S_PLAY_JANA_ROCK",
	"SPR_JCHG",
	"S_PLAY_FKIK",
	"SPR_FKIK",
	"SPR_JPOG",
	"SPR_JEBL",
	"SPR_JAUR",
	"SPR_JNFX",
	"SPR_JCRC",
	"MT_JANACIRCLE",
	"S_JANACIRCLE",
	"SPR2_DRIP",
	"sfx_skpdbl",
	"sfx_rchrg",
	"MT_JANA_ENERGYBALL",
	"MT_JANA_BADASSAURA",
	"S_JANA_BADASSAURA",
	"S_JANA_ENERGYBALL",
	"MT_JANA_CHARGEFULL",
	"MT_JANA_DESPACITOSPIDER",
	"S_JANA_CHARGEFULL",
	"MT_JANA_LASER",
	"MT_JANA_LASER_FIRE",
	"S_JANA_LASER",
	"S_PLAY_JANA_LAND",
	"S_PLAY_JANA_MONKEFLIP",
	"SFX_JADRIP",
	"SFX_JADASH",
	"SFX_JWLJMP",
	"SFX_REKOHA",
	"SFX_REKJMP",
	"MT_STUPIDFUCKIGNJANNEROBJEKT",
	"SPR2_SHIT"
)

sfxinfo[sfx_jwljmp].caption = "Wall Jump" //Spork saves the day #5
sfxinfo[sfx_rekjmp].caption = "Flip"
sfxinfo[sfx_jadash].caption = "Dashing"
sfxinfo[sfx_jadrip].caption = "Immense Power"
sfxinfo[sfx_rekoha].caption = "Rekkouha"
sfxinfo[sfx_rchrg].caption = "Charge"


	
local function janasupercircle(mobj, mobjtype, scale, ns, vertical, vertangle) --im using this fuckin function again and you can't stop me
	local i = 0	while i < 40
		local fa = (i*(ANGLE_180/20))
		local mo = P_SpawnMobjFromMobj(mobj, 0, 0, -5*FRACUNIT*P_MobjFlip(mobj)*mobj.scale, mobjtype)
		if mo and mo.valid
			if mobjtype == MT_PARTICLE
				mo.state = S_SPINDUST1
				mo.source = mobj
				mo.target = mobj
				mo.scale = 1*scale
				mo.fuse = 8
				mo.destscale = 1*scale + 1*scale/3
				--if mobj.player.powers[pw_super]
				--	mo.color = mobj.color
				--	mo.colorized = true
				--end
			end
			if vertical
				mo.momz = FixedMul(sin(fa),ns)/2
				P_InstaThrust(mo, vertangle+ANGLE_90,
				FixedMul(cos(fa),ns)/2)
			else
				mo.momx = mo.source.momx+FixedMul(sin(fa),ns)/2
				mo.momy = mo.source.momy+FixedMul(cos(fa),ns)/2
			end
		end
		i = $+1
	end
end
mobjinfo[MT_STUPIDFUCKIGNJANNEROBJEKT] = {
	doomednum = -1,
	spawnstate = S_NULL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
mobjinfo[MT_JANA_DESPACITOSPIDER] = {
	doomednum = -1,
	spawnstate = S_INVISIBLE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 1*FRACUNIT,
	height = 1*FRACUNIT,
	deathsound = sfx_ncspec
}
mobjinfo[MT_JANA_ENERGYBALL] = {
	doomednum = -1,
	spawnstate = S_JANA_ENERGYBALL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_JANA_ENERGYBALL] = {
	sprite = SPR_JCHG,
	frame = FF_FULLBRIGHT|FF_ANIMATE,
	var1 = 2,
	var2 = 2
}
mobjinfo[MT_JANA_LASER] = {
	doomednum = -1,
	spawnstate = S_JANA_LASER,
	flags = MF_NOGRAVITY|MF_NOCLIPHEIGHT,
	speed = 1,
	radius = 32*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
mobjinfo[MT_JANA_LASER_FIRE] = {
	doomednum = -1,
	spawnstate = S_LASERFLAME1,
	flags = MF_NOGRAVITY|MF_NOCLIPHEIGHT,
	speed = 1,
	radius = 1*FRACUNIT,
	height = 1*FRACUNIT
}
states[S_JANA_LASER] = {
	sprite = SPR_JNFX,
	frame = FF_FULLBRIGHT|FF_ANIMATE,
	var1 = 1,
	var2 = 1
}
mobjinfo[MT_JANA_CHARGEFULL] = {
	doomednum = -1,
	spawnstate = S_JANA_CHARGEFULL,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP,
	dispoffset = 4,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_JANA_CHARGEFULL] = {
	sprite = SPR_JPOG,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS30,
	var1 = 5,
	var2 = 1
}
mobjinfo[MT_JANA_BADASSAURA] = {
	doomednum = -1,
	spawnstate = S_JANA_BADASSAURA,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP,
	dispoffset = -4,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT,
	deathsound = sfx_ncspec
}
states[S_JANA_BADASSAURA] = {
	sprite = SPR_JAUR,
	frame = FF_FULLBRIGHT|FF_ANIMATE,
	var1 = 3,
	var2 = 3
}
mobjinfo[MT_JANACIRCLE] = {
	doomednum = -1,
	spawnstate = S_JANACIRCLE,
	flags = MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP,
	dispoffset = -4,
	radius = 5*FRACUNIT,
	height = 30*FRACUNIT
}
states[S_JANACIRCLE] = {
	sprite = SPR_JCRC,
	frame = FF_FULLBRIGHT|FF_ANIMATE|TR_TRANS40,
	var1 = 5,
	var2 = 2
}

local function janaghost(mobj)
	local colorghost = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_STUPIDFUCKIGNJANNEROBJEKT)
		colorghost.skin = mobj.skin
		colorghost.state = mobj.state
		colorghost.angle = mobj.player.drawangle
		colorghost.fuse = 4
		colorghost.colorized = true
		colorghost.color = SKINCOLOR_BLUEAFTERIMG
		colorghost.frame = mobj.frame | TR_TRANS60
		colorghost.tics = -1
		colorghost.scale = mobj.scale
		colorghost.destscale = 0
		colorghost.scalespeed = mobj.scale/10 
		if gametyperules & GTR_TEAMS and mobj.color == SKINCOLOR_RED --i wish ringslinger didn't exist :)
			colorghost.color = SKINCOLOR_REDAFTERIMG
		end
		if mobj.player.powers[pw_super]
			colorghost.color = SKINCOLOR_PURPLEAFTERIMG
		end
end
local function inputangle(player) 
	if (twodlevel or player.mo.flags2 & MF2_TWOD)
		return player.mo.angle
	else
		return (player.cmd.angleturn<<16 + R_PointToAngle2(0, 0, player.cmd.forwardmove*FRACUNIT, -player.cmd.sidemove*FRACUNIT))
	end
end	
local function janadust(player)
	if player.mo and player.mo.valid and player.mo.skin == "jana"
		for i = 1, 16 
			local dust = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z + (player.mo.eflags & MFE_VERTICALFLIP and 4*player.mo.scale or 0), player.mo.eflags & (MFE_UNDERWATER | MFE_TOUCHWATER) and MT_MEDIUMBUBBLE or MT_PARTICLE)
			dust.fuse = TICRATE/4
			dust.scale = player.mo.scale
			dust.destscale = player.mo.scale/8
			dust.eflags = player.mo.eflags & MFE_VERTICALFLIP
			P_InstaThrust(dust, i*ANGLE_22h, 6*player.mo.scale)
			dust.momz = -2*P_MobjFlip(player.mo)*player.mo.scale
			dust.frame = $|TR_TRANS60
		end
	end
end
--baby's first lua attempt, thank you bloops c:


/*addHook("AbilitySpecial", function(p)
	if p.mo and p.mo.valid and p.mo.skin == "jana"
		if not (p.pflags & PF_THOKKED) 
			P_SetObjectMomZ(p.mo, 10*FRACUNIT, false) 
			p.mo.state = S_PLAY_ROLL
			S_StartSound(p.mo, sfx_skpdbl)
			p.pflags = $ | PF_THOKKED
			return true
		end
	end
end)*/

--set up jana's vars
addHook("PreThinkFrame", function(p)
	for p in players.iterate
		if not p.jana
			local jana = {
				drippin = false,
				rockin = false,
				c1down = false,
				dashing = 0,
				walltouch = 0,
				jumpdown = false,
				throwangle = 0,
				forcedang = 0,
				divemomz = 0,
				diving = false,
				killspin = false,
				dtapcooldown = 0,
				dtapped = 0,
				dtaphelper = false,
				dtapdash = false,
				controllock = 0,
				dankmemes = false,
				lastframe = 0
			}

			if p.mo and p.mo.valid and p.mo.skin == "jana"
				p.jana = jana
			else
				p.jana = nil
			end
		end
	end
end)
addHook("ShouldDamage", function(target, inflictor, source) //Spork saves the day #6
	if target and target.valid
	and target.player
	and target.skin == "jana" 
	and target.player.jana.diving == true
	and inflictor and inflictor.valid
	and inflictor.flags & (MF_ENEMY|MF_BOSS)
		return false
	end
end)

addHook("PlayerCanDamage", function(player, thing)
	if player.mo and player.mo.valid
		if player.mo.skin == "jana" 
		and player.jana.diving == true
			if thing.flags & MF_ENEMY
			or thing.flags & MF_BOSS
			or thing.flags & MF_MONITOR
				return true
			end
		end
	end
end)
addHook("MobjMoveCollide", function(mobj, spring) //Spork saves the day #9 although there is likely an easier/better way to do this :V
	if spring and spring.valid
	if (spring.flags & MF_SPRING)
			if (mobj.z <= spring.z + spring.height)
			and (spring.z <= mobj.z + mobj.height)
			and (mobj.skin == "jana")
				if mobj.player.jana.diving == true
					mobj.player.springheight = spring.info.mass
					S_StartSound(mobj, sfx_sprong)
					mobj.player.jana.diving = false
				end
			end
		end
		if (spring.type == MT_SPRINGSHELL and spring.health > 0) then
			local tmz = (spring.eflags & MFE_VERTICALFLIP and -((mobj.z + mobj.height) or 1) or mobj.z)
			local tmznext = (spring.eflags & MFE_VERTICALFLIP and -mobj.momz or mobj.momz) + tmz
			local thzh = (spring.eflags & MFE_VERTICALFLIP and -(spring.z or 1) or spring.z + spring.height)
			local sprarea = FixedMul(8*FRACUNIT, spring.scale) * P_MobjFlip(spring)
			if (((tmznext <= thzh) and (tmz > thzh)) or ((tmznext > thzh - sprarea) and (tmznext < thzh)))
			and (mobj.skin == "jana")
				if mobj.player.jana.diving == true
					mobj.player.springheight = spring.info.mass
					S_StartSound(mobj, sfx_sprong)
					mobj.player.jana.diving = false
				end
			end
		end
	end
end, MT_PLAYER)

addHook("AbilitySpecial", function(p)
	if p.mo and p.mo.health and p.mo.skin == "jana" and p.jana.walltouch == 0 and p.jana.diving == false
		if not (p.powers[pw_super] == 1)
			if (p.pflags & PF_THOKKED)
				if not P_IsObjectInGoop(p.mo)
					p.jana.diving = true
					p.jana.divemomz = 6*FRACUNIT
					S_StartSound(p.mo, sfx_rekjmp)
				end
			else
				p.pflags = $|PF_THOKKED|PF_STARTJUMP
				P_SetObjectMomZ(p.mo, 8*FRACUNIT, false)
				S_StartSound(p.mo, sfx_skpdbl)
				janadust(p)
				p.mo.state = S_PLAY_JANA_MONKEFLIP
			end
		end
	end
end)
addHook("PlayerSpawn", function(p)
	if p.mo and p.mo.valid and p.mo.health and p.mo.skin == "jana"
		if not (p.powers[pw_carry] == CR_NIGHTSMODE)
			p.mo.state = $
		end
		if p.jana
			p.jana.drippin = false
			p.jana.rockin = false
			p.jana.c1down = false
			p.jana.dashing = 0
			p.jana.walltouch = 0
			p.jana.jumpdown = false
			p.jana.throwangle = 0
			p.jana.forcedang = 0
			p.jana.divemomz = 0
			p.jana.diving = false
			p.jana.killspin = false
			p.jana.controllock = 0
		end
		p.thrustfactor = skins[p.mo.skin].thrustfactor
		p.acceleration = skins[p.mo.skin].acceleration
	end
end)
addHook("ShieldSpecial", function(p)
	if p.mo and p.mo.valid and p.mo.health and p.mo.skin == "jana" and p.jana and (p.jana.diving or p.jana.walltouch > 0)
		return true
	end
end)
local clockval = 25
addHook("PlayerThink", function(p)
	if p.mo and p.mo.valid and p.mo.skin ~= "jana"
		if p.jana //Spork saves the day #3 
			if p.jana.drippin
			or p.jana.rockin
				p.jana.drippin = false
				p.jana.rockin = false
				P_RestoreMusic(p)
				p.mo.state = S_PLAY_WALK
			end
		end
	end
	if p.mo and p.mo.health and p.mo.valid
		if p.mo.rockmusicfan == nil
			p.mo.rockmusicfan = 0
		end
	end
	if p.mo and p.mo.valid and p.mo.health and p.mo.skin == "jana"
		--soup or janna oar uh
		if p.powers[pw_super]
			if not (p.janasuperaura and p.janasuperaura.valid)
				local aura = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_JANA_BADASSAURA)
				aura.scale = p.mo.scale+p.mo.scale/2
				aura.target = p.mo
				p.janasuperaura = aura
			end
		end
		if p.powers[pw_super] == 1
		or P_PlayerInPain(p)
			p.jana.diving = false
		end
		if p.springheight 
			P_SetObjectMomZ(p.mo, p.springheight+5*FRACUNIT, false)
			p.jana.diving = false
			p.springheight = 0
		end
		--dive thingie
		if p.jana.diving --and not P_IsObjectOnGround(p.mo)
			p.panim = PA_DASH
			if P_IsObjectInGoop(p.mo) or p.powers[pw_super] == 1
				p.jana.diving = false
			end
			P_SetObjectMomZ(p.mo, p.jana.divemomz, false)				
			if p.jana.divemomz <= 0 
				p.jana.divemomz  = $ - FRACUNIT - FRACUNIT/2
				if p.mo.state != S_PLAY_BOUNCE
					p.mo.state = S_PLAY_BOUNCE
				end
					local spawndir = (leveltime % 17) * ANG20
					local xdist = FixedMul(p.mo.scale, FixedMul(15*FRACUNIT, cos(spawndir)))
					local ydist = FixedMul(p.mo.scale, FixedMul(15*FRACUNIT, sin(spawndir)))
					local spark1 = P_SpawnMobjFromMobj(p.mo, 0+xdist,0+ydist, 0+(20*p.mo.scale), MT_JANA_ENERGYBALL)
					local spark2 = P_SpawnMobjFromMobj(p.mo, 0-xdist, 0-ydist, 0+(20*p.mo.scale), MT_JANA_ENERGYBALL)
					spark1.target = p.mo
					spark1.scale = p.mo.scale*2
					spark1.fuse = 10
					spark1.destscale = 0
					--spark1.momz = p.mo.momz/4
					--P_InstaThrust(spark1, R_PointToAngle2(p.mo.x, p.mo.y, spark1.x, spark2.y), 3*FRACUNIT)
					spark2.target = p.mo
					spark2.scale = p.mo.scale*2
					spark2.fuse = 10
					spark2.destscale = 0
					--spark2.momz = p.mo.momz/4
					--P_InstaThrust(spark2, R_PointToAngle2(p.mo.x, p.mo.y, spark1.x, spark2.y), 3*FRACUNIT)

				if p.jana.divemomz <= -39*FRACUNIT or p.powers[pw_super]
					// Lach: moved this to the MT_JANA_CHARGEFULL MobjThinker
					/*if not S_SoundPlaying(p.mo, sfx_rchrg)
						S_StartSound(p.mo, sfx_rchrg)
					end*/
					// Lach: moved this to JanaEnergySaber.SpawnChargeEffect so I can use it in my script
					/*if not p.janahasdiveobj --or p.jansterdiveobject != nil and not p.jansterdiveobject.valid
						local joemama = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_JANA_CHARGEFULL)
						p.janahasdiveobj = true
						joemama.target = p.mo
					end*/
					JanaEnergySaber.SpawnChargeEffect(p)
				end
			else
				p.jana.divemomz  = $ - FRACUNIT/2 - FRACUNIT/4
				if p.mo.state != S_PLAY_ROLL
					p.mo.state = S_PLAY_ROLL
				end
			end
			if P_IsObjectOnGround(p.mo)
				P_StartQuake(FRACUNIT*2, 15)
				S_StartSound(p.mo, sfx_mspogo)
				p.jana.controllock = clockval
			end
			if P_IsObjectOnGround(p.mo) or p.powers[pw_carry] or p.mo.eflags & MFE_JUSTHITFLOOR or p.jana.walltouch > 0
				p.jana.diving = false
				p.panim = PA_DASH
			end
		end
		if p.jana.controllock > 0
			if not P_IsObjectOnGround(p.mo)
				p.jana.controllock = 0
			end
			p.powers[pw_noautobrake] = 2
			if p.jana.controllock == clockval
				p.mo.momx = $/4
				p.mo.momy = $/4
			end
			--p.powers[pw_nocontrol] = 2
			p.normalspeed = 0
			--p.pflags = $ | PF_JUMPSTASIS
			--both of the vanilla landing states are fuckin stupid so heres a new one
			if p.mo.state != S_PLAY_JANA_LAND and P_IsObjectOnGround(p.mo)
				p.mo.state = S_PLAY_JANA_LAND
			end
			if p.jana.controllock == clockval 
				if p.jana.divemomz <= -39*FRACUNIT or p.powers[pw_super]
					local anchor = P_SpawnMobjFromMobj(p.mo, 0,0,0, MT_JANA_DESPACITOSPIDER)
					anchor.fuse = 36
					--anchor.spawner = p.mo
					local i = 0 while i < 4
						local laser = P_SpawnMobjFromMobj(p.mo, 0,0,0, MT_JANA_LASER)
						if laser and laser.valid
							laser.angle = p.drawangle+(i*ANGLE_90)
							laser.target = anchor
							laser.spawner = p.mo
							laser.rotobject = anchor
							--laser.flags = $|MF_MISSILE
							--if gametyperules & GTR_TEAMS and p.mo.color == SKINCOLOR_RED
								--laser.colorized = true
								--laser.color = SKINCOLOR_RED
							--end
							laser.fuse = 35
							laser.lasernum = 1
						end
						i = $+1
					end
					S_StartSound(p.mo, sfx_rekoha)
				end
				P_RadiusAttack(p.mo, p.mo, 150*FRACUNIT)
			end
			p.panim = PA_DASH
			p.jana.controllock = $ - 1
		elseif p.mo.state == S_PLAY_JANA_LAND
			p.mo.state = S_PLAY_STND
		end
		if p.normalspeed == 0 and p.mo.state != S_PLAY_JANA_LAND
			p.normalspeed = skins[p.mo.skin].normalspeed
		end
		--gamer time
		if P_IsObjectOnGround(p.mo) and p.cmd.buttons & BT_CUSTOM2 and p.cmd.buttons & BT_TOSSFLAG
		and (p.cmd.sidemove == 0) and (p.cmd.forwardmove == 0)
		and not p.jana.drippin and not p.jana.rockin
			p.jana.drippin = true
			p.mo.state = S_PLAY_DRIP
			P_PlayJingleMusic(p, "DRIP", nil, true, JT_OTHER)
			S_StartSound(p.mo, sfx_jadrip)
			if p == displayplayer
				P_StartQuake(FRACUNIT*2, 10)
			end
		elseif P_IsObjectOnGround(p.mo) and p.cmd.buttons & BT_TOSSFLAG
		and (p.cmd.sidemove == 0) and (p.cmd.forwardmove == 0)
		and not p.jana.drippin and not p.jana.rockin
			p.jana.rockin = true
			p.mo.state = S_PLAY_JANA_ROCK
			if p.mo.rockmusicfan == 0
				P_PlayJingleMusic(p, "ROCKON", nil, true, JT_OTHER)
			end
		end
		if p.jana.drippin
			if P_IsObjectOnGround(p.mo)
				if (p.cmd.sidemove != 0) or (p.cmd.forwardmove != 0)
					if p.mo.state == S_PLAY_DRIP
						p.mo.state = S_PLAY_WALK
					end
					p.jana.drippin = false
					P_RestoreMusic(p)
				elseif p.mo.state != S_PLAY_DRIP
					p.mo.state = S_PLAY_DRIP
				end
			else
				if p.mo.state == S_PLAY_DRIP
					p.mo.state = S_PLAY_FALL
				end
				p.jana.drippin = false
				P_RestoreMusic(p)
			end
			
		elseif p.jana.rockin
			if P_IsObjectOnGround(p.mo)
				if (p.cmd.sidemove != 0) or (p.cmd.forwardmove != 0)
					if p.mo.state == S_PLAY_JANA_ROCK
						p.mo.state = S_PLAY_WALK
					end
					p.jana.rockin = false
					if p.mo.rockmusicfan == 0
						P_RestoreMusic(p)
					end
				elseif p.mo.state != S_PLAY_JANA_ROCK
					p.mo.state = S_PLAY_JANA_ROCK
				end
				if p.mo.frame & FF_FRAMEMASK == B and p == displayplayer
					P_StartQuake(FRACUNIT/3, 5)
				end
				if not (p.powers[pw_super]) and p.mo.frame & FF_FRAMEMASK == B
					local circ = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_JANACIRCLE)
					circ.fuse = 10
					if p.mo.color == SKINCOLOR_BROWN
						circ.color = SKINCOLOR_SALMON
					else
						circ.color = ColorOpposite(p.skincolor)
					end
					--circ.blendmode = AST_ADD
					circ.scale = p.mo.scale
					circ.renderflags = $ | RF_FLOORSPRITE
				end
				if p.powers[pw_super] and p.mo.frame & FF_FRAMEMASK == B 
					if	p.jana.lastframe != p.mo.frame
						for i = 0,8 do
							local supercoolsparkle = P_SpawnMobjFromMobj(p.mo, P_RandomRange(-10, 10) * p.mo.scale, P_RandomRange(-10, 10) * p.mo.scale, 20*p.mo.scale, MT_BOXSPARKLE) 
							supercoolsparkle.momx = P_RandomRange(-9, 9) * p.mo.scale
							supercoolsparkle.momy = P_RandomRange(-9, 9) * p.mo.scale
							supercoolsparkle.momz = P_RandomRange(-9, 9) * p.mo.scale
							supercoolsparkle.colorized = true
							supercoolsparkle.color = SKINCOLOR_GOLD
							supercoolsparkle.scale = p.mo.scale + p.mo.scale/5
							--supercoolsparkle.fuse = 13
						end
					end
					local circ = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_JANACIRCLE)
					circ.fuse = 10
					circ.color = SKINCOLOR_GOLD
					circ.blendmode = AST_ADD
					circ.scale = p.mo.scale+p.mo.scale/2
					circ.renderflags = $ | RF_FLOORSPRITE
				end
				local flip = P_MobjFlip(p.mo)
				local dist = 270
				if p.powers[pw_super]
					dist = 580
				end
				local mo = p.mo
				searchBlockmap("objects", function(_, found)
					if not (found.player) return end
					if found == p.mo return end
					if found.skin == "jana" and found.jana and found.jana.rockin return end
					if found.rockmusicfan == 0
						P_PlayJingleMusic(found.player, "ROCKON", nil, true, JT_OTHER)
						--P_SetObjectMomZ(found, 50*FRACUNIT, false)
					end
					found.rockmusicfan = 2
					if p.mo.frame & FF_FRAMEMASK == B and found.player == displayplayer
						P_StartQuake(FRACUNIT/3, 5)
					end
				end, mo, mo.x - dist*mo.scale, mo.x + dist*mo.scale, mo.y - dist*mo.scale, mo.y + dist*mo.scale)
			else
				if p.mo.state == S_PLAY_JANA_ROCK
					p.mo.state = S_PLAY_FALL
				end
				p.jana.rockin = false
				if p.mo.rockmusicfan == 0
					P_RestoreMusic(p)
				end
			end
		end
		p.jana.lastframe = p.mo.frame
		--Super floating.
		if (p.mo.state == S_PLAY_WAIT or p.mo.state == S_PLAY_RUN) and p.powers[pw_super]
			if p.mo.anim_duration > 5
				p.mo.anim_duration = 5
			end
			p.mo.spriteyoffset = 3*cos(ANG10*leveltime)
			p.jana.dankmemes = true
		end
		if p.mo.spriteyoffset != 0 and p.jana.dankmemes and not ((p.mo.state == S_PLAY_WAIT or p.mo.state == S_PLAY_RUN) and p.powers[pw_super])
			p.mo.spriteyoffset = 0
			p.jana.dankmemes = false
		end
		--Now for actual moveset stuff. This here be the dash. basically just mmx but in srb2 lol.
		if p.jana.dtapcooldown < 4 and p.jana.dtapcooldown > 0 and (p.cmd.sidemove != 0 or p.cmd.forwardmove != 0) and not (p.janatapdash and p.janatapdash == 2)
			p.jana.dtapdash = true
		end
		if p.cmd.forwardmove == 0 and p.cmd.sidemove == 0
			if p.jana.dtapcooldown > 0
				p.jana.dtapcooldown = $ - 1
			end
			p.jana.dtapped = 0
		else
			if p.jana.dtapped <= 4
				p.jana.dtapcooldown = 4
			else
				p.jana.dtapcooldown = 0
			end
			p.jana.dtapped = $ + 1
		end
		--print(p.jana.dtapcooldown)
		--print((p.cmd.sidemove != 0 or p.cmd.forwardmove != 0))
		--p.jana.dtaphelper = (p.cmd.forwardmove != 0 and p.cmd.sidemove != 0)
		local dashval = 14
		if p.jana.killspin
			p.jana.killspin = false
			p.pflags = $ & ~ PF_SPINNING
		end
		if (p.cmd.buttons & BT_CUSTOM1 and not p.jana.c1down or p.jana.dtapdash) and not p.jana.drippin and not p.jana.rockin and not (p.gotflag > 0) and not p.powers[pw_nocontrol] and not p.exiting
		and not JanaEnergySaber.InAttackState(p) // Lach: don't allow dash to cancel an attack
		and not (p.mo.state >= S_PLAY_SUPER_TRANS1 and p.mo.state <= S_PLAY_SUPER_TRANS6) //Spork saves the day #8
			--janaghost(p.mo)
			if p.jana.dashing == 0 and (P_IsObjectOnGround(p.mo) or p.powers[pw_super]) and not (p.mo.eflags & MFE_JUSTHITFLOOR)
				p.jana.dashing = dashval
				p.jana.killspin = true
				if not P_IsObjectOnGround(p.mo)
					if p.mo.momz*P_MobjFlip(p.mo) < 0 
						p.mo.momz = 0
					end
					p.mo.state = S_PLAY_DASH
				end
				if p.normalspeed > skins[p.mo.skin].normalspeed+skins[p.mo.skin].normalspeed/2
					P_InstaThrust(p.mo, inputangle(p), FixedMul(p.normalspeed, p.mo.scale)) //Spork saves the day #4
				else
					P_InstaThrust(p.mo, inputangle(p), FixedMul(skins[p.mo.skin].normalspeed + skins[p.mo.skin].normalspeed/2, p.mo.scale))
				end
				S_StartSound(p.mo, sfx_jadash)
				p.pflags = $ | PF_SPINNING --hacky solution to dumb friction bs
				p.drawangle = inputangle(p)
				p.jana.controllock = 0
				--p.pflags = $ & ~ PF_JUMPSTASIS
			end
		end
		p.jana.dtapdash = false
		if p.jana.dashing > 0
			if P_IsObjectOnGround(p.mo)
				p.jana.dashing = $ - 1
				if p.mo.state ~= S_PLAY_DASH
				and not JanaEnergySaber.InAttackState(p) // Lach: prevent overwriting dash attack states
					p.mo.state = S_PLAY_DASH
				end
				if p.jana.dashing > dashval-6
					local dashdust = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_SPINDUST)
					dashdust.scale = p.mo.scale
					dashdust.momx = P_RandomRange(-5, 5)*p.mo.scale
					dashdust.momy = P_RandomRange(-5, 5)*p.mo.scale
				end
			end
			if p.mo.eflags & MFE_JUSTHITFLOOR or (p.powers[pw_carry] == CR_ROLLOUT)
				p.jana.dashing = 1
			end
			if p.jana.walltouch == 0
			and not (p.mo.state >= S_PLAY_SUPER_TRANS1 and p.mo.state <= S_PLAY_SUPER_TRANS6) //Spork saves the day #1
				janaghost(p.mo)
			end
			p.normalspeed = skins[p.mo.skin].normalspeed + skins[p.mo.skin].normalspeed/2
			if P_IsObjectOnGround(p.mo)
				p.thrustfactor = 3
			else
				p.thrustfactor = 8
			end
			if p.speed < 30*p.mo.scale and (p.jana.dashing < dashval-2 and P_IsObjectOnGround(p.mo))
				p.jana.dashing = 1
			end
			p.hasnomomentum = true
			if p.jana.dashing == 1
				p.normalspeed = skins[p.mo.skin].normalspeed
				p.thrustfactor = skins[p.mo.skin].thrustfactor
				p.hasnomomentum = false
				p.jana.dashing = 0
				if p.mo.state == S_PLAY_DASH
					p.mo.state = S_PLAY_RUN
				end
			end
		end
		p.jana.c1down = (p.cmd.buttons & BT_CUSTOM1)
	end
end)
addHook("PlayerThink", function(p)
	if p.mo and p.mo.valid and p.mo.health
		if p.mo.skin == "jana" and p.jana and p.jana.rockin return end
		if p.mo.rockmusicfan > 0
			if p.mo.rockmusicfan == 1
				P_RestoreMusic(p)
			end
			p.mo.rockmusicfan = $ - 1
		end
		--if p.mo.skin != "jana"
			--print(p.mo.rockmusicfan)
		--end
	end
end)
addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health 
		if mo.target and mo.target.valid and mo.target.health
			A_CapeChase(mo, 0, 0)
			mo.scale = mo.target.scale+mo.target.scale/2
			mo.blendmode = AST_ADD
			mo.spriteyoffset = mo.target.spriteyoffset-mo.target.spriteyoffset/2
			if not (mo.target.player.powers[pw_super])
				P_RemoveMobj(mo)
			end
		else
			P_RemoveMobj(mo)
		end
	end
end, MT_JANA_BADASSAURA)
addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health and mo.lasernum
		if mo.target and mo.target.valid --and mo.target.health
		--and mo.target.spawner and mo.target.spawner.valid and mo.target.spawner.health and mo.target.spawner.player and mo.target.skin == "jana"
		--and not P_PlayerInPain(mo.target.spawner.player)
			mo.flags = $|MF_NOCLIP
			
			mo.height = $ + FRACUNIT/3
			mo.spriteyscale = $ + FRACUNIT/3
			mo.spriteyoffset = $ - FRACUNIT/18
			mo.target = mo.rotobject
			if mo.lastx == nil
				mo.lastx = mo.x
				mo.lasty = mo.y
			end
			if mo.speenextend == nil
				mo.speenextend = 0
			else
				mo.speenextend = $ + 4
			end
			A_Custom3DRotate(mo, 90+mo.speenextend, (64+mo.speenextend/2*FRACUNIT/mo.scale)*FRACUNIT)
			if mo.eflags&MFE_VERTICALFLIP
				mo.z = mo.target.z+mo.target.height-mo.spriteyscale-16*mo.scale
			else
				mo.z = mo.target.z-16*mo.scale
			end
			mo.target = mo.spawner
			local fire = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_JANA_LASER_FIRE)
				fire.target = mo.target
				--fire.flags = $&~MF_PAIN&~MF_FIRE|MF_MISSILE
				fire.color = SKINCOLOR_SUPERSKY2
				fire.colorized = true
				fire.mass = DMG_FIRE
				fire.angle = R_PointToAngle2(mo.x, mo.y, mo.lastx, mo.lasty)
				fire.scale = mo.target.scale/2
				if mo.colorized
					fire.color = mo.color
				end
			mo.momx = 0
			mo.momy = 0
			mo.momz = 0
			mo.lastx = mo.x
			mo.lasty = mo.y
			mo.flags = $&~MF_NOCLIP
			if mo.fuse == 1
				local spoopy = P_SpawnGhostMobj(mo)
				spoopy.spriteyscale = mo.spriteyscale
				spoopy.spriteyoffset = mo.spriteyoffset
			end
		else
			P_RemoveMobj(mo)
		end
	end
end, MT_JANA_LASER)
local function collZCheck(m,n) return m.z*m.scale < n.z+n.height and m.z+m.height+m.spriteyscale*m.scale > n.z end
addHook("MobjMoveCollide", function(thing, tmthing)
	if thing and thing.valid and tmthing and tmthing.valid and tmthing.health and tmthing != thing.target
		if collZCheck(thing, tmthing)
			P_DamageMobj(tmthing, thing, thing.target, DMG_FIRE)
		end
	end
end, MT_JANA_LASER)
addHook("MobjMoveCollide", function(thing, tmthing)
	if thing and thing.valid and tmthing and tmthing.valid and tmthing.health and tmthing != thing.target
		if collZCheck(thing, tmthing)
			P_DamageMobj(tmthing, thing, thing.target, DMG_FIRE)
		end
	end
end, MT_JANA_LASER_FIRE)
addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health and mo.target and mo.target.valid and mo.target.health
		mo.momx = mo.target.momx
		mo.momy = mo.target.momy
	end
end, MT_JANA_ENERGYBALL)
addHook("MobjThinker", function(mo)
	// Lach: rearranged this thinker a bit
	if not mo.valid
		return
	end
	
	local target = mo.target
	local player = target and target.player
	
	if player
		if JanaEnergySaber.CheckStatus(player)
		and (player.jana.diving or player.janaEnergySaber.chargeTime >= JanaEnergySaber.FULLCHARGETIME) // Lach: charge effect is active while charging an attack
			P_MoveOrigin(mo, target.x, target.y, target.z)
			if not S_SoundPlaying(target, sfx_rchrg)
				S_StartSound(target, sfx_rchrg)
			end
			return
		end
	end
	P_RemoveMobj(mo)
end, MT_JANA_CHARGEFULL)
/*addHook("PlayerThink", function(p)
		if p.cmd.buttons & BT_CUSTOM1
			local colorghost = P_SpawnMobjFromMobj(p.mo, 0, 0, 0, MT_STUPIDFUCKIGNJANNEROBJEKT)
				colorghost.skin = p.mo.skin
				colorghost.state = p.mo.state
				colorghost.angle = p.drawangle
				colorghost.fuse = 4
				colorghost.colorized = true
				colorghost.color = SKINCOLOR_BLUEAFTERIMG
				colorghost.frame = p.mo.frame | TR_TRANS90
				colorghost.tics = -1
		end
	end)
addHook("MobjThinker", function(mo)
	if mo and mo.valid and mo.health
		mo.frame = $ | 
		mo.tics = -1
	end
end, MT_STUPIDFUCKIGNJANNEROBJEKT)*/
addHook("ShouldJingleContinue", function(player, musname)
    if musname != "ROCKON" return end
    if player.mo.skin == "jana" and player.jana.rockin or player.mo.rockmusicfan != nil and player.mo.rockmusicfan > 0
		if p.mo.skin != "jana"
			print("e")
		end
		return true
    else
        return false
    end
end)

addHook("ShouldJingleContinue", function(player, musname)
    if musname != "DRIP" return end
    if player.mo.skin == "jana" and player.jana.drippin
        return true
    else
        return false
    end
end)

function A_WallSlide(actor)
	if not actor.player
	or actor.skin ~= "jana"
		return
	end
	actor.tics = 10
end

states[i].action = A_WallSlide

--jana's walljump
addHook("MobjMoveBlocked", function(mobj)
    if not (mobj.player and mobj.skin == "jana"
    /*and mobj.player.wallability*/ and not P_IsObjectOnGround(mobj)) return end
	if mobj.player.jana.diving return end
	if mobj.player.powers[pw_carry] == CR_NIGHTSMODE return end
	local oldline = mobj.player.lastlinehit
	local oldside = mobj.player.lastsidehit
	mobj.player.lastlinehit = -1
	mobj.player.lastsidehit = -1
    P_SlideMove(mobj)
    mobj.player.powers[pw_pushing] = 3
    local line = lines[mobj.player.lastlinehit]
	if line and line.valid
		if (line.frontsector)
			if (line.frontsector.ceilingheight == line.frontsector.floorheight) and (mobj.z > line.frontsector.ceilingheight)
				return
			end
		end
		if (line.backsector)
			if (line.backsector.ceilingheight == line.backsector.floorheight) and (mobj.z > line.backsector.ceilingheight)
				return
			end
		end
		mobj.player.jana.throwangle = R_PointToAngle2(mobj.x,mobj.y,P_ClosestPointOnLine(mobj.x,mobj.y,line))+FixedAngle(180*FRACUNIT)
		if mobj.state != S_PLAY_CLING
			mobj.state = S_PLAY_CLING
			mobj.player.jana.diving = false
			if mobj.player.jana.walltouch < 3
				S_StartSound(mobj, sfx_s3k4c) 
			end
		end
		mobj.player.pflags = $ & ~ PF_THOKKED
		mobj.player.jana.walltouch = 5
		mobj.player.drawangle = mobj.player.jana.throwangle-FixedAngle(180*FRACUNIT)
		if mobj.momz*P_MobjFlip(mobj) < -2*mobj.scale
			P_SetObjectMomZ(mobj, -2*FRACUNIT, false)
		end
    else
		mobj.player.lastlinehit = oldline
		mobj.player.lastsidehit = oldside
	end
    return true
end, MT_PLAYER)
addHook("PlayerThink", function(p)
	if p.mo and p.mo.valid and p.mo.health and p.mo.skin == "jana"
	--print(p.jana.walltouch,"","","")
		if p.jana.walltouch > 0
			if not P_IsObjectOnGround(p.mo)
				--p.mo.state = S_PLAY_CLING // Spork saves the day #2. Also who tf did this???
			end
			if --p.mo.momz*P_MobjFlip(p.mo) < -2*p.mo.scale and 
			leveltime % 5 == 0
				local dust = P_SpawnMobjFromMobj(p.mo, P_RandomRange(-5, 5)*p.mo.scale+P_ReturnThrustX(p.mo, p.jana.throwangle+FixedAngle(180*FRACUNIT), 10*FRACUNIT), P_RandomRange(-5, 5)*p.mo.scale+P_ReturnThrustY(p.mo, p.jana.throwangle+FixedAngle(180*FRACUNIT), 10*FRACUNIT), 35*p.mo.scale, MT_SPINDUST)
				dust.momx = P_RandomRange(0,4)*p.mo.scale
				dust.momy = P_RandomRange(0,4)*p.mo.scale
				dust.momz = p.mo.momz/2
				dust.flags = $ | MF_NOCLIPHEIGHT
				S_StartSound(p.mo, sfx_s3k7e)
			end
			if (p.cmd.buttons & BT_JUMP) and not p.jana.jumpdown and not P_IsObjectOnGround(p.mo) --and not (p.pflags & PF_JUMPDOWN)
				P_Thrust(p.mo, p.jana.throwangle, 20*p.mo.scale)
				P_SetObjectMomZ(p.mo, 15*FRACUNIT, false)
				S_StartSound(p.mo, sfx_jwljmp)
				p.jana.walltouch = 0
				p.mo.state = S_PLAY_JUMP
				p.drawangle = p.jana.throwangle
				p.jana.forcedang = 20
				p.jana.diving = false
				p.pflags = $|PF_JUMPED|PF_STARTJUMP&~PF_THOKKED
			end
		elseif p.mo.state == S_PLAY_CLING
			p.mo.state = S_PLAY_JUMP
		end
		if p.jana.forcedang > 0
			p.jana.forcedang = $ - 1
			p.drawangle = p.jana.throwangle
		end
	end
end)
--prolly dont need to use a postthink for this, just doing this this way to make it easier for me lmao
addHook("PostThinkFrame", function(p)
	for p in players.iterate
		if p.mo and p.mo.valid and p.mo.health and p.mo.skin == "jana"
			if p.jana.walltouch > 0
				p.jana.walltouch = $ - 1
			end
			p.jana.jumpdown = (p.cmd.buttons & BT_JUMP)
		end
	end
end)

local function CheckAndCrumble2(mo, sec)
  for fof in sec.ffloors()
    if not (fof.flags & FF_EXISTS) continue end -- Does it exist?
    if not (fof.flags & FF_BUSTUP) continue end -- Is it bustable?
    
    if mo.z + mo.momz + mo.height < fof.bottomheight continue end -- Are we too low?
    if mo.z + mo.momz > fof.topheight continue end -- Are we too high?

    -- Check for whatever else you may want to    

    //EV_CrumbleChain(fof) -- Crumble
    JanaEnergySaber.MobjBustFOF(mo, fof) // Lach: account for linedef executors
  end
end

addHook("PlayerThink", function(p)
  if not p.mo return end
  if p.mo.skin != "jana" return end
  if not p.jana.diving return end
	CheckAndCrumble2(p.mo, p.mo.subsector.sector)
end)

addHook("MobjLineCollide", function(mo, line)
  if not mo.player return end
  if mo.skin != "jana" return end
  if not (mo.player.jana and mo.player.jana.diving) return end
  for _, sec in ipairs({line.frontsector, line.backsector})
    CheckAndCrumble2(mo, sec)
  end
end, MT_PLAYER)
local spikekiller = function(thing, tmthing)
	if not (thing and thing.valid and tmthing and tmthing.valid) return end
	if tmthing.player and tmthing.skin == "jana" and ((tmthing.player.jana and tmthing.player.jana.diving))
	and (abs(thing.z - tmthing.z) <= 60*tmthing.scale)
		if tmthing.z >= thing.z-tmthing.height and tmthing.z <= thing.z+thing.height+tmthing.height
			P_KillMobj(thing, tmthing)
			return true
		end
	end
end
addHook("MobjCollide", function(thing, tmthing) spikekiller(thing, tmthing) end, MT_SPIKE)
addHook("MobjCollide", function(thing, tmthing) spikekiller(thing, tmthing) end, MT_WALLSPIKE)
local spikekillerbutforlasers = function(thing, tmthing)
	if not (thing and thing.valid and tmthing and tmthing.valid) return end
	if tmthing and tmthing.valid and tmthing.type == MT_JANA_LASER
	--and (abs(thing.z - tmthing.z) <= 60*tmthing.scale)
		if collZCheck(thing, tmthing)
			P_KillMobj(thing, tmthing)
			return true
		end
	end
end
addHook("MobjCollide", function(thing, tmthing) spikekillerbutforlasers(thing, tmthing) end, MT_SPIKE)
addHook("MobjCollide", function(thing, tmthing) spikekillerbutforlasers(thing, tmthing) end, MT_WALLSPIKE)
// I/O example by Cyron. Slightly edited by frostiikin, but the vast majority of this is all cyron's doing.
// I/O Support, I don't know how to put them in one file so I make multiple vars
local configplayer--I'm actually not sure if configplayer ever needs to be used tbh, I'm mostly winging it off what I saw in derp code

local function valid(mo)
	return mo and mo.valid
end

local JANADASH = "client/jana/thefunny.dat"--you need a place to save that shit
//

//
addHook("ThinkFrame", do--Cyron can't fucking code but this is IO stuff
	if valid(consoleplayer)
		and not valid(configplayer)--i really dont know if this is needed..
		and consoleplayer.janatapdash == nil	--my codes ass backwards so this will always read nil at launch, that won't work for all types of codes probably
			configplayer = consoleplayer --i really dont know if this is needed..
			local file = io.openlocal(JANADASH)--check for the file
            if file--do you actually have a file to read
                local num = file:read("*n")--tells the fucker to OPEN UP, use *a for strings, *n for numbers
					if num == 1
						COM_BufInsertText(consoleplayer, "janatapdash ".."on")--tells that fucker to put the value here
					else
						COM_BufInsertText(consoleplayer, "janatapdash ".."off")
					end
				file:close()--perish
            else--bitch where the file
                COM_BufInsertText(consoleplayer, "janatapdash on")--this makes a default if theres no file to read
        end
	end
end)


//The Command Shit
local function JanaDash(player, arg)--Conjunction junction, what's your function?
	if player.mo and player.mo.valid
		if arg
			if arg == "on" or arg == "1" or arg == "true" or arg == "yes"--for the dummy these are numbers, but they can be strings, but you'll have to call the read differently
				player.janatapdash =  1
				CONS_Printf(player, "Jana can now dash by double-tapping movement keys.")
				if io and player == consoleplayer--this section calls to save the data
					local file = io.openlocal(JANADASH, "w+")--w+ neans to write and overwrite all data in the file.
					file:write(player.janatapdash)--put that value in the file, idfk how to make boolean functions save so i force put "true" or "false" here cuz im shit
					file:close()--perish
				end
			elseif arg == "off" or arg == "false" or arg == "0" or arg == "no"--same thing but different answer
				player.janatapdash =  2
				CONS_Printf(player, "Jana can no longer dash by double-tapping movement keys.")
				if io and player == consoleplayer
					local file = io.openlocal(JANADASH, "w+")
					file:write(player.janatapdash)
					file:close()
				end
			end
		else
			if player.janatapdash == 1
				CONS_Printf(player, "Decides wether or not jana can dash by double tapping movement keys. Currently on.")
			else
				CONS_Printf(player, "Decides wether or not jana can dash by double tapping movement keys. Currently off.")
			end
		end
	elseif player.spectator //Spork saves the day #7
		CONS_Printf(player, "You are a spectator.")
	else
		CONS_Printf(player, "You aren't in a stage.")
	end
end

COM_AddCommand("janatapdash", function(player, arg)--This adds the command
	JanaDash(player, arg)--Tells command what function to do
end)

