//instashield v6
//product of katsy

local function SafeFreeslot(...)
	for _, item in ipairs({...})
		if rawget(_G, item) == nil
			freeslot(item)
		end
	end
end

SafeFreeslot(
	"MT_INSTASHIELD",
	"S_INSTASHIELD",
	"S_INSTASHIELD1A",
	"S_INSTASHIELD1B",
	"S_INSTASHIELD2A",
	"S_INSTASHIELD2B",
	"S_INSTASHIELD3A",
	"S_INSTASHIELD3B",
	"S_INSTASHIELD4A",
	"S_INSTASHIELD4B",
	"S_INSTASHIELD5A",
	"S_INSTASHIELD5B",
	"S_INSTASHIELD6A",
	"S_INSTASHIELD6B",
	"SPR_TWSP"
)

mobjinfo[MT_INSTASHIELD] = {
	doomednum = -1,
	spawnhealth = 1,
	spawnstate = S_INSTASHIELD,
	radius = 48*FRACUNIT,
	height = 48*FRACUNIT,
	flags = MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT
}

states[S_INSTASHIELD] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_INSTASHIELD1A}
states[S_INSTASHIELD1A] = {SPR_TWSP, 0|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD1B}
states[S_INSTASHIELD1B] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_INSTASHIELD2A}
states[S_INSTASHIELD2A] = {SPR_TWSP, 1|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD2B}
states[S_INSTASHIELD2B] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_INSTASHIELD3A}
states[S_INSTASHIELD3A] = {SPR_TWSP, 2|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD3B}
states[S_INSTASHIELD3B] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_INSTASHIELD4A}
states[S_INSTASHIELD4A] = {SPR_TWSP, 3|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD4B}
states[S_INSTASHIELD4B] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_INSTASHIELD5A}
states[S_INSTASHIELD5A] = {SPR_TWSP, 4|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD5B}
states[S_INSTASHIELD5B] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_INSTASHIELD6A}
states[S_INSTASHIELD6A] = {SPR_TWSP, 5|FF_FULLBRIGHT, 1, A_CapeChase, 0, 0, S_INSTASHIELD6B}
states[S_INSTASHIELD6B] = {SPR_NULL, 0, 1, A_CapeChase, 0, 0, S_NULL}

addHook("JumpSpinSpecial", function(player)
	if (player.mo.skin == "ultsonic") and not (player.pflags & PF_THOKKED) and not (player.pflags & PF_SPINDOWN) and not player.powers[pw_super]
		S_StartSound(player.mo, sfx_s3k42)
		local instashield = P_SpawnMobjFromMobj(player.mo, 0, 0, 0, MT_INSTASHIELD)
		instashield.target = player.mo
		instashield.spritexscale = $*3/2
		instashield.spriteyscale = $*3/2
		if not (player.mo.colorized)
			instashield.flash = true
		end
		player.mo.tracer = instashield
		player.pflags = $|PF_SHIELDABILITY & ~PF_SPINNING
		return true
	end
end)

addHook("MobjThinker", function(insta)
	if (insta.target)
		if (insta.target.state != S_PLAY_JUMP)
			if insta.flash
				insta.target.colorized = false
			end
			pcall(P_RemoveMobj, insta)
			return
		end
		if insta.flash
			if (insta.sprite == SPR_NULL)
				insta.target.colorized = false
			else
				insta.target.colorized = true
				insta.target.frame = ($ & FF_FRAMEMASK)|FF_FULLBRIGHT
			end
		end
	end
end, MT_INSTASHIELD)

addHook("ShouldDamage", function(sonic, inflictor, source, damage, element)
	if (sonic.tracer) and sonic.tracer.type == MT_INSTASHIELD
		if not (element & DMG_DEATHMASK)
			return false
		end
	end
end, MT_PLAYER)

addHook("MobjMoveCollide", function(insta, mobj)
	if not (insta.z-FixedMul(24*FRACUNIT, insta.scale) > mobj.z+mobj.height) and not(mobj.z-FixedMul(24*FRACUNIT, insta.scale) > insta.z+insta.height)
		if (mobj.valid and (mobj.flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) or (mobj.flags & MF_PUSHABLE and mobj.flags & MF_SHOOTABLE))) and not (mobj.flags2 & MF2_FRET)
			P_DamageMobj(mobj, insta, insta.target)
			if P_MobjFlip(insta.target)*insta.target.momz < 0
				insta.target.momz = -$
			end
			if (mobj.info.spawnhealth > 1)
				insta.target.momy = -$
				insta.target.momx = -$
			end
		end
	end
end, MT_INSTASHIELD)
