freeslot("S_PLAY_HUG", "S_COLORHEART", "SPR_HUG_", "SPR_RHRT")

states[S_PLAY_HUG] = {
	sprite = SPR_HUG_,
	frame = A,
	tics = -1
}

states[S_COLORHEART] = {
	sprite = SPR_RHRT,
	tics = -1
}

local function SpawnHearts(player)
	local heart = P_SpawnMobjFromMobj(player.mo, 0, 0, player.mo.height, MT_CDLHRT)
	heart.destscale = (5*player.mo.scale)>>4
	heart.fuse = (5*TICRATE)>>1
	heart.momz = player.mo.scale
	heart.target = player.mo
	heart.extravalue1 = player.mo.x
	heart.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
	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
	end
	
	return false
end

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

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

addHook("ThinkFrame", function()
	for player in players.iterate
		if player.mo.skin != "alm" continue end
		
		if amyhugs.value == 0 continue end
		
		local huggable
		local rosy = player
		
		-- Hug delay ticker
		if rosy.hugdelay
			rosy.hugdelay = $ - 1
		end
		
		if rosy.thrown and rosy.mo.momz < 0
			rosy.mo.sprite2 = SPR2_ROLL
			rosy.mo.frame = D
			rosy.thrown = false
		end
		
		if rosy.hug
			rosy.drawangle = rosy.hugangle
			rosy.pflags = $ | PF_STASIS
			rosy.hug.pflags = $ | PF_STASIS
			rosy.mo.state = S_PLAY_HUG
			rosy.hugtime = $ + 1
		end
		
		-- Let's find the closest person to hug!
		for p in players.iterate
			-- Already hugging
			if rosy.hug continue end
			
			-- It's another Rosy and she's not hugging you
			if p.hug and rosy.hugged != p continue end
			
			-- Don't hug yourself
			if p == rosy 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 != rosy.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(rosy.mo.z - p.mo.z) > 4*FRACUNIT continue end
			
			-- Too far away
			local dist = R_PointToDist2(rosy.mo.x, rosy.mo.y, p.mo.x, p.mo.y)
			if dist > rosy.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 heart
		if not huggable and not rosy.hug and not rosy.thrown
			if rosy.heart and rosy.heart.valid
				P_RemoveMobj(rosy.heart)
			end
			
			rosy.heart = nil
			continue
		end
		
		-- Found someone? Place the heart indicator
		if not rosy.heart
			rosy.heart = P_SpawnMobj(huggable.mo.x, huggable.mo.y, huggable.mo.z + huggable.mo.height + 24*huggable.mo.scale, MT_LOCKON)
			rosy.heart.state = S_COLORHEART
			rosy.heart.color = rosy.mo.color
			rosy.heart.scale = 2*huggable.mo.scale/3
			rosy.heart.fuse = -1
			rosy.heart.tracer = rosy.mo
			rosy.heart.target = huggable.mo
		end
		
		-- Hug/release
		if rosy.cmd.buttons & BT_CUSTOM1 and not rosy.hugdelay
			if rosy.hug
				ReleaseHug(rosy)
			else
				huggable.hugged = rosy
				rosy.hug = huggable
				rosy.hugtime = 0
				rosy.hugangle = R_PointToAngle2(rosy.mo.x, rosy.mo.y, huggable.mo.x, huggable.mo.y)
				local radius = huggable.mo.radius
				--P_TeleportMove(rosy.mo, huggable.mo.x + FixedMul(radius, cos(rosy.hugangle)), huggable.mo.y + FixedMul(radius, sin(rosy.hugangle)), rosy.mo.z)
				S_StartSound(rosy.mo, sfx_cdpcm6)
				rosy.hugdelay = TICRATE
			end
		elseif rosy.hug and rosy.cmd.buttons & BT_CUSTOM2
			if (leveltime & 7) == 0
				SpawnHearts(rosy)
			end
		end
	end
end)

addHook("MobjThinker", function(mo)
	if mo.tracer
		if mo.tracer.skin != "alm" or mo.tracer.player.hug or amyhugs.value == 0
			mo.tracer.heart = 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_COLORHEART
		P_RemoveMobj(mo)
	end
end, MT_LOCKON)

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

addHook("JumpSpecial", ReleaseHug)