-- by space jockey
-- most of this stuff has been done by Royal, as noted

-- helicopter ascent/descent logic
function helicopterAscend(units, _, caller)
	local iterated = 0

	for i = 0, units, units / 20 do
		timer.Simple(
			0.02 * iterated,
			function()
				caller:FireUser6(i)
			end
		)

		iterated = iterated + 1
	end
end


-- red sniper laser logic
local function removeCallbacks(player, callbacks) -- removeCallbacks refers to the local variable
	if not IsValid(player) then -- check if the 
		return
	end

	for _, callbackId in pairs(callbacks) do
		player:RemoveCallback(callbackId)
	end
end

local function getEyeAngles(player)
	local pitch = player["m_angEyeAngles[0]"]
	local yaw = player["m_angEyeAngles[1]"]

	return Vector(pitch, yaw, 0)
end

function LaserOnAim(_, activator)
	local laser = ents.CreateWithKeys("info_particle_system", {
		effect_name = "laser_sight_beam",
		start_active = 0,
		flag_as_weather = 0,
	}, false)

	laser:SetName("le_laser")

	local pointer = Entity("info_particle_system", true)
	local color = Entity("info_particle_system", true)

	pointer:SetName("le_laserpointer")
	color:SetName("le_lasercolor")

	color:SetAbsOrigin(Vector(255, 0, 0))

	laser.m_hControlPointEnts[1] = pointer
	laser.m_hControlPointEnts[2] = color

	local callbacks = {}

	local started = false

	local check
	-- might cause a client side memory leak because the laser isn't cleared when the laser entity itself is
	-- who knows!
	-- this is a bandaid to forcefully hide the lasers out of sight (and out of mind. don't think about it)
	local function hideLaser()
		if not IsValid(laser) then
			-- print("nah")
			return
		end

		laser:Stop()

		laser:SetAbsOrigin(pointer:GetAbsOrigin())
	end

	local terminated = false

	local function terminate()
		if terminated then
			return
		end

		terminated = true

		timer.Stop(check)
		removeCallbacks(activator, callbacks)

		hideLaser()

		timer.Simple(0.1, function()
			for _, e in pairs({ laser, pointer, color }) do
				if IsValid(e) then
					e:Remove()
				end
			end
		end)
	end

	check = timer.Create(0.015, function()
		if activator.m_iTeamNum == 0 or activator.m_iTeamNum == 1 then
			terminate()
			return
		end

		if not IsValid(activator) or not activator:IsAlive() then
			terminate()
			return
		end

		if activator:InCond(0) ~= 1 then
			if started then
				hideLaser()

				started = false
			end

			return
		end

		local eyeAngles = getEyeAngles(activator)

		local DefaultTraceInfo = {
			start = activator,
			distance = 10000,
			angles = eyeAngles,
			mask = MASK_SOLID,
			collisiongroup = COLLISION_GROUP_DEBRIS,
		}
		local trace = util.Trace(DefaultTraceInfo)

		laser:SetAbsOrigin(trace.StartPos)
		pointer:SetAbsOrigin(trace.HitPos)

		laser:Start()

		started = true
	end, 0)

	callbacks.died = activator:AddCallback(ON_DEATH, function()
		terminate()
	end)
	callbacks.removed = activator:AddCallback(ON_REMOVE, function()
		terminate()
	end)
	callbacks.spawned = activator:AddCallback(ON_SPAWN, function()
		terminate()
	end)
end

local inWave = false

local HudTextParams = {

	channel = 3, --Channel number 0 - 5, -- Channel 0 is used to display wave explanation, -- Channel 1 is used to display cash in reverse mvm,
    x = -1, -- X coordinate from 0 to 1, -- -1 for center positon, -- Text is wrapped so it does not overflow the screen
    y = 0.3, -- Y coordinate from 0 to 1, -- -1 for center positon Text is wrapped so it does not overflow the screen
    effect = 2, -- 0,1 - fade in/fade out text, -- 2 - typeout text
    r1 = 100, -- 0 - 255 range, -- The text is rendered additively, black text will not display
    r2 = 255, -- 0 - 255 range, -- The text is rendered additively, black text will not display
    g1 = 100, -- 0 - 255 range, -- The text is rendered additively, black text will not display
    g2 = 255, -- 0 - 255 range, -- The text is rendered additively, black text will not display
    b1 = 100, -- 0 - 255 range, -- The text is rendered additively, black text will not display
    b2 = 255, -- 0 - 255 range, -- The text is rendered additively, black text will not display
    a1 = 100, -- 0 - 255 range, -- 0 - fully visible, 255 - invisible
    a2 = 0, -- 0 - 255 range, -- 0 - fully visible, 255 - invisible
    fadeinTime = 0.01, -- Time to fade in text
    fadeoutTime = 0, -- Time to fade out text
    holdTime = 0.5, -- Time the text is fully displayed
    fxTime = 0.01, -- Time to type a single letter with typeout effect
}

-- func_button - Braindawg
function OnPlayerConnected(player)
--	player.HoldTime = 0
	player.InteractWith = "nothing"
	player.InteractCooldown = false
end


function OnWaveStart(wave)
	inWave = TickCount()
end

function OnWaveInit(wave)
	if wave > 1 then
		inWave = true
	end
end

function OnGameTick()

	if inWave then
		ButtonHintThink()
	end
	
	for _, player in pairs(ents.GetAllPlayers()) do

		if player:IsRealPlayer() then

			if player.m_bUsingActionSlot == 1 and player.InteractCooldown ~= true then
                
--				player.HoldTime = player.HoldTime + 1 --holdtime stuff removed

				FindButtons()
				if player.InteractWith ~= "nothing" then
					
					nearbutton = ents.FindByName(player.InteractWith)
					nearbutton:AcceptInput("Press",_,player)
					player.InteractCooldown = true
					player.InteractWith = "nothing" 
--					player.HoldTime = 0 
					timer.Simple(3, function() player.InteractCooldown = false end)	
				end
--			else
--			 	player.HoldTime = 0
			end
		end
	end
end

function FindButtons()
	
    for _, e in pairs(ents.FindAllByClass("func_button")) do 

		local button = e:GetAbsOrigin()

		for _, player in pairs(ents.FindInSphere(button,50)) do
			PrintTable(HudTextParams)

			if player:IsRealPlayer() then
				
				player.InteractWith = e:GetName()

			end
		end      
    end             
end

function ButtonHintThink()
	
    for _, g in pairs(ents.FindAllByClass("func_button")) do 

		local b = g:GetAbsOrigin()

		for _, player in pairs(ents.FindInSphere(b,50)) do

			if player:IsRealPlayer() and player.InteractCooldown == false then
				player:ShowHudText(HudTextParams,"Press your canteen button to use")
			end
		end      
    end             
end