-- Hugs --

-- ABOUT: Again, because why not? This is modified from "Amy Hugs" by Tatsuru.

local function SpawnNote(player)
	local note = P_SpawnMobjFromMobj(player.mo, 0, 0, player.mo.height, MT_FLNOTE)
	note.destscale = (5*player.mo.scale)>>4
	note.fuse = (2*TICRATE)>>2
	note.momz = player.mo.scale+5*FRACUNIT
	note.target = player.mo
	note.extravalue1 = player.mo.x
	note.extravalue2 = player.mo.y
end

local function ReleaseHug(player)
	if player.hug
		player.pflags = $ & ~PF_STASIS
		player.hug.pflags = $ & ~PF_STASIS
		player.hug.hugged = nil
		player.hug = nil
		player.mo.state = S_PLAY_STND
		player.hugdelay = TICRATE
		player.mo.flchanhugging = 0
	elseif player.hugged
		player.pflags = $ & ~PF_STASIS
		player.hugged.pflags = $ & ~PF_STASIS
		player.hugged.mo.angle = R_PointToDist2(player.mo.x, player.mo.y, player.hugged.mo.x, player.hugged.mo.y)
		player.hugged.drawangle = player.hugged.mo.angle
		player.hugged.mo.state = S_PLAY_PAIN
		if player.hugged.hugtime > 1*TICRATE
			player.hugged.mo.sprite2 = SPR2_TRNS
			player.hugged.mo.frame = G
			player.hugged.thrown = true
		else
			player.hugged.mo.sprite2 = SPR2_PAIN
			S_StartSound(player.hugged.mo, sfx_cdpcm7)
		end
		A_DoNPCPain(player.hugged.mo)
		player.hugged.hug = nil
		player.hugged = nil
		player.hugdelay = TICRATE
		player.mo.flchanhugging = 0
	end
	return false
end

local function UnhugEveryone()
	for player in players.iterate
		if player.hug
			ReleaseHug(player)
		end
	end
end

local flhugs = CV_RegisterVar({"flhugs", "On", CV_NETVAR|CV_CALL, CV_OnOff, UnhugEveryone})

addHook("ThinkFrame", function()
	for player in players.iterate
		if player.mo.skin != "flchan" continue end
		if flhugs.value == 0 continue end
		local huggable
		local fl = player
		-- Hug delay ticker
		if fl.hugdelay
			fl.hugdelay = $ - 1
		end
		if fl.thrown and fl.mo.momz < 0
			fl.mo.sprite2 = SPR2_ROLL
			fl.mo.frame = D
			fl.thrown = false
		end
		if fl.hug
			fl.drawangle = fl.hugangle
			fl.pflags = $ | PF_STASIS
			fl.hug.pflags = $ | PF_STASIS
			fl.mo.state = S_PLAY_FLHG
			fl.hugtime = $ + 1
		end
		-- Let's find the closest person to hug!
		for p in players.iterate
			-- Already hugging
			if fl.hug continue end
			-- It's another FL Chan and she's not hugging you
			if p.hug and fl.hugged != p continue end
			-- Don't hug yourself
			if p == fl continue end
			-- Hug only living players
			if not p.mo continue end
			if p.playerstate != PST_LIVE continue end
			-- No hugging the enemy
			if p.ctfteam != fl.ctfteam continue end
			-- Can't hug if not on the floor or doing anything
			if not(P_IsObjectOnGround(p.mo) and (p.panim == PA_IDLE or p.panim == PA_WALK or p.panim == PA_RUN))
				continue
			end
			-- No hugging in NiGHTS
			if p.powers[pw_carry] & CR_NIGHTSMODE continue end
			-- Too high or too low to hug
			if abs(fl.mo.z - p.mo.z) > 4*FRACUNIT continue end
			-- Too far away
			local dist = R_PointToDist2(fl.mo.x, fl.mo.y, p.mo.x, p.mo.y)
			if dist > fl.mo.radius + p.mo.radius continue end
			-- Update the candidates
			if huggable and dist < huggable.dist
				huggable = p
				huggable.dist = dist
			else
				huggable = p
				huggable.dist = dist
			end
		end
		-- Did our closest player disappear? Get rid of the note
		if not huggable and not fl.hug and not fl.thrown
			if fl.note and fl.note.valid
				P_RemoveMobj(fl.note)
			end
			fl.note = nil
			continue
		end
		-- Found someone? Place the note indicator
		if not fl.note
			fl.note = P_SpawnMobj(huggable.mo.x, huggable.mo.y, huggable.mo.z + huggable.mo.height + 24*huggable.mo.scale, MT_LOCKON)
			fl.note.state = S_COLORNOTE
			fl.note.color = fl.mo.color
			fl.note.scale = 2*huggable.mo.scale/3
			fl.note.fuse = -1
			fl.note.tracer = fl.mo
			fl.note.target = huggable.mo
		end
		-- Hug/release
		if fl.cmd.buttons & BT_CUSTOM2 and not fl.hugdelay
			if fl.hug
				ReleaseHug(fl)
			else
				huggable.hugged = fl
				fl.hug = huggable
				fl.hugtime = 0
				fl.hugangle = R_PointToAngle2(fl.mo.x, fl.mo.y, huggable.mo.x, huggable.mo.y)
				local radius = huggable.mo.radius
				--P_TeleportMove(fl.mo, huggable.mo.x + FixedMul(radius, cos(fl.hugangle)), huggable.mo.y + FixedMul(radius, sin(fl.hugangle)), fl.mo.z)
				S_StartSound(fl.mo, sfx_3db06)
				fl.hugdelay = TICRATE
				SpawnNote(fl)
				fl.mo.flchanhugging = 1
			end
		end
	end
end)

addHook("MobjThinker", function(mo)
	if mo.tracer
		if mo.tracer.skin != "flchan" or mo.tracer.player.hug or flhugs.value == 0
			mo.tracer.note = nil
			P_RemoveMobj(mo)
		else
			mo.color = mo.tracer.color
			mo.scale = 2*mo.target.scale/3
			local z = mo.target.z + mo.target.height + FixedMul((16 + abs((leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mo.target.scale)
			P_TeleportMove(mo, mo.target.x, mo.target.y, z)
			return true
		end
	elseif not mo.tracer and mo.state == S_COLORNOTE
		P_RemoveMobj(mo)
	end
end, MT_LOCKON)

addHook("PlayerSpawn", function(p)
	p.hug = nil
	p.hugged = nil
end)

addHook("JumpSpecial", ReleaseHug)