//Tails Doll Boss
freeslot("MT_TAILSDOLL_BOSS", "MT_TAILSDOLL_CLONE", "MT_DOLLTELEPORT", "sfx_tdshld", "sfx_hello", "MT_CRYSTALSPIKES", "MT_INSTACRYSTALSPIKES")

for i = 1, 4
	freeslot("S_TAILSDOLL_HYPNOS"..i)
end

for i = 1, 5
	freeslot("S_TDCLONE"..i)
end

local function CreateClones(mo)
	mo.state = S_TAILSDOLL_ROLL
	for i = 1, 6
		local clone = P_SpawnMobj(mo.x, mo.y, mo.z+4*FRACUNIT, MT_TAILSDOLL_CLONE)
		if (clone and clone.valid)
			clone.angle = FixedAngle(60*FRACUNIT)*i
			P_InstaThrust(clone, clone.angle, 8*FRACUNIT)
			P_SetObjectMomZ(clone, 8*FRACUNIT)
			clone.target = mo.target
			clone.fuse = 10*TICRATE
		end
	end
	mo.momx = 0
	mo.momy = 0
	mo.momz = 0
end

local function AllPlayerHypno(mo)
	for player in players.iterate
		if (player.mo and player.mo.valid and player.playerstate == PST_LIVE)
			player.mo.hypnosis = 3*TICRATE
		end
	end
	S_StartSound(nil, sfx_s3k9c)
	mo.momx = 0
	mo.momy = 0
	mo.momz = 0
end

local function InvTD(mo, arg)
	if arg == 1
		mo.flags = $1 & ~(MF_NOCLIPTHING)
	elseif arg == 2
		mo.flags = $1|MF_NOCLIPTHING
	end
end

local function FlySimulation(exe)
	local angle = R_PointToAngle2(0, 0, exe.momx, exe.momy)
	if exe.speed == nil
		exe.speed = 0
	end
	exe.speed = FixedHypot(exe.momx, exe.momy)
	if exe.float_sim == nil
		exe.float_sim = 0
	end
	if (leveltime % 16) < 8
		if exe.float_sim < 16*FRACUNIT
			exe.float_sim = $1 + 2*FRACUNIT
		end
	else
		if exe.float_sim > -16*FRACUNIT
			exe.float_sim = $1 - 2*FRACUNIT
		end
	end
	if (exe.target and exe.target.health)
		local dist = R_PointToDist2(exe.x, exe.y, exe.target.x, exe.target.y)
		local target_angle = R_PointToAngle2(exe.x, exe.y, exe.target.x, exe.target.y)
		local speedmul = FixedMul(exe.speed+8*FRACUNIT, exe.scale)
		local dist2 = P_AproxDistance(P_AproxDistance(exe.target.x - exe.x, exe.target.y - exe.y), exe.target.z+exe.target.height/2+exe.float_sim - exe.z)
		if dist2 < 1
			dist2 = 1
		end
		A_FaceTarget(exe)
		exe.momz = FixedMul(FixedDiv(exe.target.z+exe.target.height/2+exe.float_sim - exe.z, dist), speedmul)
		if dist > 128*FRACUNIT
			if exe.speed < 16*FRACUNIT
				P_Thrust(exe, exe.angle, FRACUNIT)
			else
				P_InstaThrust(exe, angle, exe.speed-2*FRACUNIT)
			end
		elseif dist <= 128*FRACUNIT
			if dist <= 96*FRACUNIT
				P_Thrust(exe, target_angle, -FRACUNIT)
				if dist <= 64*FRACUNIT
					P_Thrust(exe, target_angle, -FRACUNIT)
				end
			else
				if exe.speed >= 0*FRACUNIT
					P_InstaThrust(exe, angle, exe.speed-FRACUNIT)
				end
			end
		end
	end
end

local function TDShockWave(mobj)
	local numtospawn = 24
	local ang = 0
	local interval = FixedAngle((360 << FRACBITS) / numtospawn)
	local shock = nil
	local sfirst = nil
	local sprev = nil
	for i = 0, numtospawn
		shock = P_SpawnMobj(mobj.x, mobj.y, mobj.floorz, MT_SHOCKWAVE)
		shock.target = mobj
		shock.fuse = shock.info.painchance
		if (i % 2 == 0)
			shock.state = states[shock.state].nextstate
		end
		if not (sprev)
			sfirst = shock
		else
			if (i == numtospawn - 1)
				shock.hnext = sfirst
			end
			sprev.hnext = shock
		end
		P_Thrust(shock, ang, shock.info.speed)
		ang = $1 + interval
		sprev = shock
	end
	S_StartSound(mobj, shock.info.seesound)
end

//Sound a Light Thunder
freeslot("sfx_wowf", "sfx_woww", "S_TDTHUNDER", "SPR_WOW_", "MT_TDTHUNDER")

mobjinfo[MT_TDTHUNDER] = {
	spawnstate = S_TDTHUNDER,
	spawnhealth = 1000,
	radius = 16*FRACUNIT,
	height = 32*FRACUNIT,
	speed = 1,
	flags = MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT,
	dispoffset = 6
}

states[S_TDTHUNDER] = {
	sprite = SPR_WOW_,
	frame = FF_ANIMATE|FF_FULLBRIGHT,
	tics = 7,
	var1 = 6,
	var2 = 1,
	nextstate = S_NULL
}

mobjinfo[MT_TDTHUNDER].name = "Light Thunder"

addHook("MobjThinker", function(tdlight)
	if tdlight and tdlight.valid
		tdlight.blendmode = AST_ADD
		tdlight.color = P_RandomRange(SKINCOLOR_RED, SKINCOLOR_SALMON)
		tdlight.colorized = true
		if P_RandomChance(FRACUNIT/4) then 
			S_StartSound(tdlight, sfx_s3k40)
		end
		for i = 1,3
			local part = P_SpawnMobj(tdlight.x + P_RandomRange(-48,48)*tdlight.scale, tdlight.y + P_RandomRange(-48,48)*tdlight.scale, tdlight.z + tdlight.height/2 + P_RandomRange(0,88)*tdlight.scale, MT_PARTICLE)
			part.eflags = $ | (tdlight.eflags & MFE_VERTICALFLIP)
			part.scale = tdlight.scale/3
			part.state = S_SSPK1
		end
	end
end, MT_TDTHUNDER)

addHook("MobjThinker", function(mo)
	if mo and mo.valid
		if mo.type == MT_CRYSTALSPIKES
			mo.blendmode = AST_ADD
			mo.color = P_RandomRange(SKINCOLOR_RED, SKINCOLOR_SALMON)
			mo.colorized = true
			local tdfiretrail = P_SpawnGhostMobj(mo)
			tdfiretrail.blendmode = AST_ADD
			for i = 0,9
				tdfiretrail.fuse = 6
				tdfiretrail.scale = (FRACUNIT * 8/10) - (i * FRACUNIT/320)
				tdfiretrail.destscale = 0
			end
		end
		if mo.type == MT_INSTACRYSTALSPIKES
			mo.blendmode = AST_ADD
			mo.color = P_RandomRange(SKINCOLOR_PURPLE, SKINCOLOR_PASTEL)
			mo.colorized = true
			local tdfiretrail2 = P_SpawnGhostMobj(mo)
			tdfiretrail2.color = P_RandomRange(SKINCOLOR_PURPLE, SKINCOLOR_PASTEL)
			tdfiretrail2.colorized = true
			tdfiretrail2.blendmode = AST_ADD
			for i = 0,9
				tdfiretrail2.fuse = 6
				tdfiretrail2.scale = (FRACUNIT * 8/10) - (i * FRACUNIT/320)
				tdfiretrail2.destscale = 0
			end
		end
	end
end)

addHook("MobjSpawn", function(mo)
	mo.scale = FRACUNIT-FRACUNIT/4
end, MT_TAILSDOLL_CLONE)

addHook("PostThinkFrame", function()
    for player in players.iterate
		if player.playerstate == PST_LIVE
		and player.mo.hypnosis
			local hypnosis2 = P_SpawnGhostMobj(player.mo)
			hypnosis2.colorized = true
			hypnosis2.fuse = 1
			hypnosis2.color = SKINCOLOR_RED
			P_TeleportMove(hypnosis2, player.mo.x, player.mo.y, player.mo.z - 4*FRACUNIT)
			hypnosis2.frame = $|FF_ADD
			hypnosis2.scale = 1*FRACUNIT + 1*FRACUNIT/6
			if hypnosis2.tracer
				hypnosis2.tracer.fuse = ghost.fuse
			end
		end
	end
end)

local function hypnosis(mo, trailmo, freq)
    if not mo.prevz or not mo.prevleveltime or (mo.prevleveltime ~= leveltime - 1) then
       mo.prevz = mo.z
    end
    local rmomz = mo.z - mo.prevz
    mo.prevz = mo.z
    mo.prevleveltime = leveltime
    local mospeed = R_PointToDist2(0, 0, R_PointToDist2(0, 0, mo.momx, mo.momy), rmomz)
    local dist = (mospeed/freq)
    for i = dist, 1, -1 do
        local spawnedmo = P_SpawnMobjFromMobj(mo, (mo.momx/dist)*i, (mo.momy/dist)*i, (rmomz/dist)*i, trailmo)
        spawnedmo.color = SKINCOLOR_RED
        spawnedmo.blendmode = AST_ADD
		spawnedmo.frame = FF_TRANS50
		spawnedmo.fuse = 8
		spawnedmo.destscale = 0
    end
end

addHook("MobjThinker", function(mo)
	if (mo and mo.valid)
	and mo.type == MT_TAILSDOLL_BOSS
		if mo.health
			if mo.td_attack == nil
				mo.td_attack = 0
			elseif mo.td_attack == 1
				if (mo.td_state % 15) == 1
					P_SpawnMissile(mo, mo.target, MT_CRYSTALSPIKES)
					S_StartSound(mo,sfx_s3k4d)
				end
			elseif mo.td_attack == 2
				if (mo.td_state % 10) == 1
					local ring = P_SpawnMobj(mo.x, mo.y, mo.z, MT_THOK)
					if ring
					and ring.valid
						ring.color = SKINCOLOR_CRIMSON
						ring.colorized = true
						ring.blendmode = AST_ADD
						A_SetScale(ring, 4*FRACUNIT, 1)
					end
				end
				if mo.td_state <= 2
					mo.td_attack = 1
					mo.td_state = 45
				end
			end
			if mo.td_state == nil
				mo.td_state = 0
			elseif mo.td_state > 0
				mo.td_state = $1 - 1
			elseif mo.td_state <= 0
				mo.td_attack = 0
			end
			if mo.td_flash == nil
				mo.td_flash = 0
			end
			if mo.td_flash > 0
				mo.td_flash = $1 - 1
				InvTD(mo, 2)
			elseif mo.td_flash <= 0
				InvTD(mo, 1)
				mo.flags2 = $1 & ~MF2_DONTDRAW
			end
			if (mo.td_flash % 2) == 1
				mo.flags2 = $1|MF2_DONTDRAW
			else
				mo.flags2 = $1 & ~MF2_DONTDRAW
			end
			if mo.state == S_TAILSDOLL_SPAWN
				InvTD(mo, 2)
				if mo.tics == 2
					for player in players.iterate
						if (player.mo and player.mo.valid)
							P_FlashPal(player, 1, 15)
							local light = P_SpawnMobj(mo.x, mo.y, mo.floorz, MT_TDTHUNDER)
							light.state = S_TDTHUNDER
							light.color = SKINCOLOR_RED
							light.colorized = true
							light.blendmode = AST_ADD
							light.scale = 6*FRACUNIT/2
							for i = 1, 60
								local particle = P_SpawnMobj(mo.x, mo.y, mo.z, MT_THOK)
								P_InstaThrust(particle, (6*i)*ANG1, 64*FRACUNIT)
								particle.state = S_SSPK1
								particle.flags = MF_NOGRAVITY
							end
						end
					end
					S_StartSound(nil, sfx_litng1)
					A_FindTarget(mo, MT_PLAYER, 0)
				end
			elseif mo.state == S_TAILSDOLL_STAND
				FlySimulation(mo)
				if mo.td_time == nil
					mo.td_time = 5*TICRATE
				elseif mo.td_time > 0
					mo.td_time = $1 - 1
				else
					local prandom = P_RandomRange(1, 10)
					if prandom == 1 //laser Attack
						mo.td_attack = 1
						mo.td_state = 45
					elseif prandom == 2 //Hypnosis Clones
						AllPlayerHypno(mo)
						CreateClones(mo)
						S_StartSound(mo.target, sfx_cdfm33)
					elseif prandom == 3 //Clones + Laser Attack
						S_StartSound(nil, sfx_hello)
						mo.td_attack = 2
						mo.td_state = 30
						CreateClones(mo)
					elseif prandom == 4 //Ultra Laser Attack
						S_StartSound(nil, sfx_tdlaug)
						P_SpawnMissile(mo, mo.target, MT_INSTACRYSTALSPIKES)
					elseif prandom == 5 //Hypnosis
						mo.state = S_TAILSDOLL_ROLL
						mo.td_attack = 2
						mo.td_state = 30
						AllPlayerHypno(mo)
					elseif prandom == 6 //Creating Clones
						CreateClones(mo)
					elseif prandom == 7  //Ultimate Attack
						AllPlayerHypno(mo)
						CreateClones(mo)
						P_SpawnMissile(mo, mo.target, MT_INSTACRYSTALSPIKES)
						S_StartSound(nil, sfx_tdlaug)
						mo.td_attack = 1
						mo.td_state = 45
					elseif prandom == 8 //Smash Attack
						AllPlayerHypno(mo)
						CreateClones(mo)
						mo.td_attack = 1
						mo.td_state = 45
						S_StartSound(nil, sfx_hello)
					elseif prandom == 9 //Gem Blast Electric
						TDShockWave(mo)
						mo.state = S_TAILSDOLL_ROLL
						P_FlashPal(mo.target.player, PAL_NUKE, 10)
						S_StartSound(mo, sfx_s3k7c)
						A_Thrust(mo, 0, 1)
						P_SetObjectMomZ(mo, -1*FRACUNIT)
					elseif prandom == 10 //Crystal Spikes
						for i = 1, 30
							local crspikes = P_SPMAngle(mo, MT_CRYSTALSPIKES, (ANG2+ANG10)*i, 0, MF2_RAILRING)
						end
						mo.state = S_TD_BLAST1
						S_StartSound(mo, sfx_s1a6)
						A_Thrust(mo, 0, 1)
						P_SetObjectMomZ(mo, -1*FRACUNIT)
						S_StartSound(mo, sfx_tdshld)
					end
					mo.td_time = 5*TICRATE
				end
			elseif mo.state == S_TAILSDOLL_PAIN
				if P_IsObjectOnGround(mo)
					mo.state = S_TAILSDOLL_STAND
					mo.td_flash = 3*TICRATE
					mo.flags = mo.info.flags
				end
			end			
		else
			A_BossScream(mo)
		end
	end
end, MT_TAILSDOLL_BOSS)

addHook("MobjDamage", function(mo, inf, source)
	if (mo and mo.valid)
	and mo.type == MT_TAILSDOLL_BOSS
		if mo.health > 1
			if (inf and inf.valid)
				A_DoNPCPain(mo, FRACUNIT, 0)
				if (source and source.valid and source.player)
					mo.target = source
				end
				mo.health = $1 - 1
				mo.state = mo.info.painstate
				mo.flags = MF_SCENERY
			end
			mo.td_attack = 0
			mo.td_state = 0
		elseif mo.health <= 1
			P_KillMobj(mo)
		end
	end
return true
end, MT_TAILSDOLL_BOSS)

addHook("MobjThinker", function(mo)
	if (mo and mo.valid)
	and mo.type == MT_TAILSDOLL_CLONE
		if (mo.flags & MF_NOCLIPTHING)
		and P_IsObjectOnGround(mo)
			mo.flags = $1 & ~MF_NOCLIPTHING
		end
	end
end, MT_TAILSDOLL_CLONE)

addHook("PlayerThink", function(player)
	if (player.mo and player.mo.valid and player.playerstate == PST_LIVE)
		if player.mo.hypnosis == nil
			player.mo.hypnosis = 0
		elseif player.mo.hypnosis > 0
			player.mo.hypnosis = $1 - 1
		end
		if player.mo.hypnosis
			hypnosis(player.mo, MT_GHOST, 4*FRACUNIT)
		end
	end
end)

addHook("PreThinkFrame", function()
	for player in players.iterate
		if (player.mo and player.mo.valid and player.playerstate == PST_LIVE)
			if player.mo.hypnosis != nil
			and player.mo.hypnosis > 0
				P_StartQuake(18*FRACUNIT, 35, {0, 0, 0}, player.mo.radius)
				player.cmd.forwardmove = $1 * -1
				player.cmd.sidemove = $1 * -1
			end
		end
	end
end)

hud.add(function(v, player)
	if not (player.mo.hypnosis) return end
	if (player.mo and player.mo.valid)
		v.drawStretched(0,0,2*FRACUNIT,2*FRACUNIT,v.cachePatch("STATIC"+tostring((leveltime%8)/2)),V_SNAPTOTOP|V_SNAPTOLEFT|V_PERPLAYER|V_SCALEPATCHMASK|V_80TRANS)
	end
end, "game")