//Original code made by Jana Sol
//Rewrited by DarknessStylus

local ChangeStage = function(p)
	if not p.mo and p.mo.valid then return end
	if p.selectedstageleft
		if not p.stagegatehudcontrolt.arrows.changing.reset
			p.stagegatehudcontrolt.arrows.changing.right = false
			p.stagegatehudcontrolt.arrows.changing.left = true
			p.stagegatehudcontrolt.arrows.changing.active = true
			p.stagegatehudcontrolt.arrows.changing.reset = true
		end
		for i = 1, 16 do
			local tactnum = mapheaderinfo[p.mapselected].actnum
			if mapheaderinfo[p.mapselected-i] ~= nil
				if mapheaderinfo[p.mapselected-i].lvlttl ~= nil
					if mapheaderinfo[p.mapselected-i].actnum == tactnum
					--or not (mapheaderinfo[p.mapselected-i].actnum)
						p.mapselected = $-i
						p.maptoteleport = p.mapselected
						if not p.teleportto
							p.teleportto = true
						end
						p.selectedstageleft = nil
						break
					end
				else
					p.selectedstageleft = nil
					continue
				end
			else
				p.selectedstageleft = nil
				continue
			end
		end
	end
	if p.selectedstageright
		if not p.stagegatehudcontrolt.arrows.changing.reset
			p.stagegatehudcontrolt.arrows.changing.left = false
			p.stagegatehudcontrolt.arrows.changing.right = true
			p.stagegatehudcontrolt.arrows.changing.active = true
			p.stagegatehudcontrolt.arrows.changing.reset = true
		end
		for i = 1, 16 do
			local tactnum = mapheaderinfo[p.mapselected].actnum
			local tlvlttl = mapheaderinfo[p.mapselected].lvlttl
			if mapheaderinfo[p.mapselected+i] ~= nil
				if mapheaderinfo[p.mapselected+i].lvlttl ~= nil
					if p.mapselected+i > 23 --Can't go beyond this one for now...
						p.selectedstageright = nil
						break
					end
					if mapheaderinfo[p.mapselected+i].actnum == tactnum
					--or not (mapheaderinfo[p.mapselected+i].actnum)
						p.mapselected = $+i
						if not p.teleportto
							p.teleportto = true
						end
						p.selectedstageright = nil
						break
					end
				else
					p.selectedstageright = nil
					continue
				end
			else
				p.selectedstageright = nil
				continue
			end
		end
	end
	if p.teleportto
		for i_mo in mobjs.iterate() do
			if i_mo and i_mo.valid 
			and i_mo.type == MT_STAGEGATE
				if i_mo.warp ~= nil
					if mapheaderinfo[p.mapselected].lvlttl == mapheaderinfo[i_mo.warp].lvlttl
						p.maptoteleport = i_mo.warp
						if not p.teleportplayerto
							p.teleportplayerto = true
						end
						p.teleportto = nil
					end
					if mapheaderinfo[p.mapselected].lvlttl == "Red Volcano"
						p.maptoteleport = 17
						if not p.teleportplayerto
							p.teleportplayerto = true
						end
						p.teleportto = nil
					end
				end
			end
		end
	end
	if p.selectedstageact
		for i = 1, 8 do
			local tactnum = mapheaderinfo[p.mapselected].actnum
			if tactnum == 1
				if mapheaderinfo[p.mapselected+i] ~= nil
					if mapheaderinfo[p.mapselected+i].lvlttl ~= nil
						if mapheaderinfo[p.mapselected+i].actnum == 2
							p.mapselected = $+i
							p.selectedstageact = nil
							break
						end
					else
						p.selectedstageact = nil
						continue
					end
				else
					p.selectedstageact = nil
					continue
				end
			elseif tactnum == 2
				if mapheaderinfo[p.mapselected-i] ~= nil
					if mapheaderinfo[p.mapselected-i].lvlttl ~= nil
						if mapheaderinfo[p.mapselected-i].actnum == 1
							p.mapselected = $-i
							p.selectedstageact = nil
							break
						end
					else
						p.selectedstageact = nil
						continue
					end
				else
					p.selectedstageact = nil
					continue
				end
			end
		end
	end
end

addHook("MobjSpawn", function(mo) -- Stage Gate Spawn
	mo.waittimer = 0
	if mo.state == S_STAGEGATE_ACTIVE
	and mo.tanation == nil
		local light = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_STAGEGATELIGHT)
		light.state = S_STAGEGATELIGHT
		light.tanation = mo
		light.blendmode = AST_ADD
		mo.tanation = light
	end
end, MT_STAGEGATE)

addHook("PlayerSpawn", function(p) -- Player Spawn Values
	if p and p.mo and p.mo.valid
		p.stageexittimer = 0
		p.stagetimer = 0
		p.jumpholdtimer = 0
		p.spinholdtimer = 0
		p.fadetimer = 0
		p.hubtimer = 0
		p.teleportto = nil
	end
end)

addHook("MobjThinker", function(mo)
	if mo and mo.valid //The original check was... weird UnU
		if mo.spawnpoint.args[0]
			mo.warp = mo.spawnpoint.args[0]
		end
		if mo.spawnpoint.args[1] == 0 -- Stage Gate Types
			mo.state = S_STAGEGATE_ACTIVE
			mo.spawntype = 0
			mo.tanation.frame = A
		end
		if mo.spawnpoint.args[1] == 1
			mo.state = S_STAGEGATENIGHT_ACTIVE
			mo.spawntype = 1
			mo.tanation.frame = B
		end
		if mo.spawnpoint.args[1] == 2
			mo.state = S_STAGEGATECUSTOM_ACTIVE
			mo.spawntype = 2
			mo.tanation.frame = C
			if mo.spawnpoint.args[2]
				mo.color = mo.spawnpoint.args[2]
				mo.tanation.color = mo.spawnpoint.args[2]
			end
		end
		if mo.waittimer > 0
			mo.waittimer = $-1
		end
	end
end, MT_STAGEGATE)

//PreThinkFrame
addHook("PreThinkFrame", do
	for p in players.iterate do
		if p.mo and p.mo.valid
			local mo = p.mo
			//For some reason cmd.sidemove and cmd.forwardmove doesn't work when PF_FULLSTASIS is active, so this is a weird way to make it work
			if not p.sidemovei2 then p.sidemovei2 = 0 end
			if not p.uselessfthing then p.uselessfthing = 0 end
			if not p.maptoteleport then p.maptoteleport = 0 end
			if p.stagegatepos == nil or (type(p.stagegatepos) ~= "table")
				p.stagegatepos = {
					x = 0,
					y = 0,
					z = 0,
					angle = 0,
					modangle = 0,
					camdist = 0,
					movex = 0,
					movey = 0,
					movez = 0,
					timetomove = 0,
					timetomove2 = 0,
					changeacttime = 0
				}
			end
			p.sidemovei2 = p.cmd.sidemove
		end
	end
end)

addHook("PlayerCmd", function(p, cmd)
	if p.mo and p.mo.valid
		if p.selectingstage == true
			//cmd.sidemove = 0
			//cmd.forwardmove = 0
		end
	end
end)

addHook("JumpSpecial", function(p)
	if p.mo and p.mo.valid
		if p.stagegatepos.changeact
		or p.selectingstage
			return true
		end
	end
end)

//Player Think.... :/
addHook("PlayerThink", function(p) -- Player Stage Gate Control
	if not p.mo and p.mo.valid then return end
	local mo = p.mo
	if p.selectingstage == true
		p.pflags = $|PF_FULLSTASIS
		//Start sound
		if not p.dostageselsoundt
			S_StartSound(nil, sfx_geop, p)
			p.dostageselsoundt = true
		end
		//Select map thing
		if p.stagegatehudcontrolt.top_shapes.inter >= FU
			if ((p.sidemovei2 > 0) or (p.cmd.buttons & BT_CUSTOM3))
				if not p.alredyselectedstage
					if not p.selectedstageright
						p.selectedstageright = true
					end
					S_StartSoundAtVolume(nil, sfx_gsld, 90, p)
					p.alredyselectedstage = true
				end
			elseif ((p.sidemovei2 < 0) or (p.cmd.buttons & BT_TOSSFLAG))
				if not p.alredyselectedstage
					if not p.selectedstageleft
						p.selectedstageleft = true
					end
					S_StartSoundAtVolume(nil, sfx_gsld, 90, p)
					p.alredyselectedstage = true
				end
			elseif p.cmd.buttons & BT_CUSTOM2
				if not p.alredyselectedstage
					if not p.selectedstageact
						p.selectedstageact = true
					end
					S_StartSoundAtVolume(nil, sfx_gcur, 90, p)
					p.alredyselectedstage = true
				end
			else
				if p.alredyselectedstage
					p.alredyselectedstage = nil
				end
			end
		else
			if p.sidemovei2 ~= 0
			or p.cmd.buttons
				if not p.alredyselectedstage
					p.alredyselectedstage = true
				end
			else
				if p.alredyselectedstage
					p.alredyselectedstage = nil
				end
			end
			p.selectedstageright = nil
			p.selectedstageleft = nil
			p.selectedstageact = nil
		end
		ChangeStage(p)
		//Teleport player to the next stage gate
		if p.teleportplayerto
			if not p.uselesstimert then p.uselesstimert = 0 end
			p.uselesstimert = $+1
			p.uselessfthing = 0
			if p.uselesstimert < 2
				if p.localstagegate
					p.localstagegate = nil
				end
			else
				for i_mo in mobjs.iterate() do
					if i_mo and i_mo.valid 
					and i_mo.type == MT_STAGEGATE
						if i_mo.warp == nil
							if p.maptoteleport == (i_mo.angle/ANG1)
								p.stagegatepos.movex = R_PointToDist2(i_mo.x, i_mo.y, p.stagegatepos.x, p.stagegatepos.y)/4
								p.stagegatepos.movey = R_PointToDist2(i_mo.x, i_mo.y, p.stagegatepos.x, p.stagegatepos.y)/4
								p.stagegatepos.movez = mo.z - i_mo.z
								P_MoveOrigin(mo, i_mo.x, i_mo.y, i_mo.z)
								p.stagegatepos.x = i_mo.x
								p.stagegatepos.y = i_mo.y
								p.stagegatepos.z = i_mo.z
								p.stagegatepos.modangle = R_PointToDist2(0, i_mo.angle/ANG1, 0, (p.stagegatepos.angle)/ANG1)*ANG1
								p.stagegatepos.angle = i_mo.angle
								p.stagegatepos.timetomove = FRACUNIT
								p.stagegatepos.timetomove2 = TICRATE/2
							end
							p.localstagegate = i_mo
							p.teleportplayerto = nil
						else
							if i_mo.warp == p.maptoteleport
								p.stagegatepos.movex = R_PointToDist2(i_mo.x, i_mo.y, p.stagegatepos.x, p.stagegatepos.y)/4
								p.stagegatepos.movey = R_PointToDist2(i_mo.x, i_mo.y, p.stagegatepos.x, p.stagegatepos.y)/4
								p.stagegatepos.movez = mo.z - i_mo.z
								P_MoveOrigin(mo, i_mo.x, i_mo.y, i_mo.z)
								p.stagegatepos.x = i_mo.x
								p.stagegatepos.y = i_mo.y
								p.stagegatepos.z = i_mo.z
								p.stagegatepos.modangle = R_PointToDist2(0, i_mo.angle/ANG1, 0, (p.stagegatepos.angle)/ANG1)*ANG1
								p.stagegatepos.angle = i_mo.angle
								p.stagegatepos.timetomove = FRACUNIT
								p.stagegatepos.timetomove2 = TICRATE/2
							end
							p.localstagegate = i_mo
							p.teleportplayerto = nil
						end
					end
				end
			end
		else
			p.uselesstimert = nil
			p.uselessfthing = min($+1, 4)
		end
		//Other things
		if (p.cmd.buttons & BT_JUMP) and not p.jumpholdtimer -- Accept
			if not p.stagegatepos.changeact
				p.stagegatepos.changeact = true
			end
			p.selectingstage = false
		end
		if (p.cmd.buttons & BT_SPIN) and not p.spinholdtimer -- Cancel
			p.pflags = $ & ~ PF_FULLSTASIS
			if p.firstinteractionstgt
				p.firstinteractionstgt = nil
			end
			S_StartSound(nil, sfx_gcls, p)
			p.selectingstage = false
		end
	else
		if p.dostageselsoundt
			p.dostageselsoundt = nil
		end
	end
	if p.stagegatepos.changeact
		p.stagegatepos.changeacttime = $+1
		if p.stagegatepos.changeacttime == 2
			S_StartSound(nil, sfx_gsel, p)
		end
		if p.stagegatepos.changeacttime > 16
			p.pflags = $ & ~ PF_FULLSTASIS
			G_SetCustomExitVars(p.mapselected, 1)
			G_ExitLevel()
			if p.firstinteractionstgt
				p.firstinteractionstgt = nil
			end
			p.stagegatepos.changeacttime = 0
			p.stagegatepos.changeact = nil
		end
	end
	if (p.cmd.buttons & BT_JUMP)
		p.jumpholdtimer = $+1
	else
		p.jumpholdtimer = 0
	end
		
	if (p.cmd.buttons & BT_SPIN)
		p.spinholdtimer = $+1
	else
		p.spinholdtimer = 0
	end
end)

addHook("ThinkFrame", do
	for p in players.iterate do
		if p.mo and p.mo.valid
			local mo = p.mo
			local stgt = p.stagegatepos
			//Move the camera here
			if p.selectingstage == true
				//Do some vars things here
				/*stgt.timetomove2 = max($-1, 0)
				if stgt.timetomove2 <= 0
					stgt.timetomove = max($-256, 0)
				end
				stgt.modangle = ease.outsine(stgt.timetomove, 0, $)
				stgt.movex = ease.linear(stgt.timetomove, 0, $)
				stgt.movey = ease.linear(stgt.timetomove, 0, $)
				stgt.movez = ease.insine(stgt.timetomove, 0, $)
				//The camera itself
				if not (p.awayviewmobj and p.awayviewmobj.valid)
					p.awayviewmobj = P_SpawnMobj((mo.x) - 200*cos(stgt.angle), (mo.y) - 200*sin(stgt.angle), mo.z + mo.height, MT_ALTVIEWMAN)
					p.awayviewmobj.angle = stgt.angle
				else
					if P_CheckPosition(p.awayviewmobj, (stgt.x) - stgt.camdist*cos(stgt.angle + stgt.modangle) - stgt.movex, (stgt.y) - stgt.camdist*sin(stgt.angle + stgt.modangle) - stgt.movey) == true
						P_MoveOrigin(p.awayviewmobj, (stgt.x) - stgt.camdist*cos(stgt.angle + stgt.modangle) - stgt.movex, (stgt.y) - stgt.camdist*sin(stgt.angle + stgt.modangle) - stgt.movey, (stgt.z + 2*mo.scale)+stgt.movez)
					end
					p.awayviewmobj.angle = stgt.angle + stgt.modangle
				end
				p.awayviewtics = 2*/
				//Teleport the player to the stage gate
				if p.uselessfthing <= 0
					P_MoveOrigin(mo, stgt.x, stgt.y, stgt.z)
					p.drawangle = stgt.angle - ANGLE_180
					mo.momx = 0
					mo.momy = 0
					mo.state = S_PLAY_STND
				end
			else
				if p.localstagegate
					p.localstagegate = nil
				end
			end
		end
	end
end)

addHook("TouchSpecial",function(stgt, mo)
	--Use a Stage Gate if...
	if stgt and stgt.valid
		if stgt.state == S_STAGEGATE_ACTIVE or stgt.state == S_STAGEGATENIGHT_ACTIVE or stgt.state == S_STAGEGATECUSTOM_ACTIVE
			if mo.player and mo.player.valid
				local p = mo.player
				if not p.selectingstage and not stgt.waittimer
					if stgt.warp == nil
						p.mapselected = stgt.angle/ANG1
						p.maptoteleport = stgt.angle/ANG1
					else
						p.mapselected = stgt.warp
						p.maptoteleport = stgt.warp
					end
					if not p.firstinteractionstgt
						//Normal stats
						p.stagegatepos.x = stgt.x
						p.stagegatepos.y = stgt.y
						p.stagegatepos.z = stgt.z
						p.stagegatepos.angle = stgt.angle
						p.uselessfthing = 0
						//Camera stats and pos
						p.stagegatepos.modangle = R_PointToDist2(0, stgt.angle/ANG1, 0, (p.cmd.angleturn<<16)/ANG1)*ANG1
						if p.pflags & PF_ANALOGMODE
							p.stagegatepos.camdist = (CV_FindVar("cam_simpledist").value/FRACUNIT)+15 --200
						else
							p.stagegatepos.camdist = (CV_FindVar("cam_dist").value/FRACUNIT)
						end
						p.stagegatepos.timetomove = FRACUNIT
						p.stagegatepos.timetomove2 = TICRATE/2
						p.firstinteractionstgt = true
					end
					p.selectingstage = true
				end
				stgt.waittimer = TICRATE/2
			end
		end
		return true
	end
end, MT_STAGEGATE)