-- LUA Script - precede every function and global member with lowercase name of script + '_main'
-- smallg's portal gun script
-- DESCRIPTION: [GUNNAME$=""] (the gun's name to use as the portal gun) 
-- DESCRIPTION: [ISPROJECTILE!=0] (tick if gun is a projectile weapon (not instant bullet)
-- DESCRIPTION: [PORTAL1=0] (the entity number of the first portal particle)
-- DESCRIPTION: [PORTAL2=0] (the entity number of the second portal particle)
-- DESCRIPTION: [PLAYERHEIGHT=30] (adjusts the starting point of the raycast)
-- DESCRIPTION: [SHOWHELDGUN!=0] (for easy set up tick this to show the currently held gun)
-- DESCRIPTION: [PORTALRANGE=200] (how close to portal you can get before it teleports you)
-- DESCRIPTION: [PORTALDELAY=1] (how long till the portal activates)
-- DESCRIPTION: [ANIMATONSPEED=1] (how quickly the teleportanimation plays)
-- DESCRIPTION: sound slot 1 on portals will play when porting
U = U or require "scriptbank\\utillib"
g_portalgun = {}
local pg
local rad = math.rad 
local currentportal = 1
local fired_recently = false 
local bothportalsactive = 0
local ported_recently = 2
local timer = {}
local teleportspr = nil 
local teleportimg = {}
local current_img = 1
local isporting = false 

function portalgun_properties(e, gunname, isprojectile, portal1, portal2, playerheight, showheldgun, portalrange, portaldelay, animationspeed)
	g_portalgun[e] = {}
	pg = g_portalgun[e]
	pg.gunname = gunname
	pg.isprojectile = isprojectile
	pg.portal1 = portal1
	pg.portal2 = portal2
	pg.playerheight = playerheight
	pg.showheldgun = showheldgun
	pg.portalrange = portalrange
	pg.portaldelay = portaldelay
	pg.animationspeed = animationspeed
	
end 

function portalgun_init(e)

	local function file_exists(name)
		 local f=io.open(name,"r")
		 if f~=nil then io.close(f) return true else return false end
	end
	
	g_portalgun[e] = {}
	pg = g_portalgun[e]
	pg.gunname = ""
	pg.isprojectile = 0
	pg.portal1 = 0
	pg.portal2 = 0
	pg.playerheight = 30
	pg.showheldgun = 0
	pg.portalrange = 200
	pg.portaldelay = 1
	pg.animationspeed = 1
	
	timer[e] = {}
	timer[e][1] = nil 
	local imagename = ""
	for a = 0, 99 do 
		imagename = "teleport_0"
		if a < 10 then 
			imagename = imagename.."0"
		elseif a > 99 then 
			imagename = "teleport_"
		end 
		imagename = imagename..a..".png"
		local file = "scriptbank\\smallg\\images\\teleport\\"..imagename
		if file_exists(file) == true then 
			teleportimg[a] = LoadImage(file)	
			if teleportspr == nil then 
				teleportspr = CreateSprite(LoadImage("scriptbank\\smallg\\images\\teleport\\teleport_099.png"))
				SetSpriteSize(teleportspr,100,100)
				SetSpritePosition(teleportspr,2000,2000)
			end			
		end 
	end 	

end 

function portalgun_main(e)	
	
	local function RaycastTerrain(x1,y1,z1,x2,y2,z2)
		local r = RayTerrain(x1,y1,z1,x2,y2,z2) -- returns 1 if the ray cast hits the terrain geometry
		local x3,y3,z3 = 0,0,0
		if r ~= 0 then 
			x3 = GetRayCollisionX() -- returns the X position of the terrain hit position
			y3 = GetRayCollisionY() -- returns the Y position of the terrain hit position
			z3 = GetRayCollisionZ() -- returns the Z position of the terrain hit position
		end 
		return x3,y3,z3 
	end 
	
	local function RaycastStatic(x1,y1,z1,x2,y2,z2,IgnoreObj)
		local x3,y3,z3 = 0,0,0
		local xn,yn,zn = 0,0,0
		local r = IntersectStatic(x1,y1,z1,x2,y2,z2,IgnoreObj) -- returns 1 if the ray cast hits ANY entity or lightmapped geometry
		if r ~= nil then 
			--x=IntersectStatic(x1,y1,z1,x2,y2,z2,IgnoreObj) -- returns 1 if the ray cast hits non-animating entity or lightmapped geometry
			x3 = GetIntersectCollisionX() -- returns the X position of the entity hit position
			y3 = GetIntersectCollisionY() -- returns the Y position of the entity hit position
			z3 = GetIntersectCollisionZ() -- returns the Z position of the entity hit position
			xn = GetIntersectCollisionNX() -- returns the X normal of the entity hit surface
			yn = GetIntersectCollisionNY() -- returns the Y normal of the entity hit surface
			zn = GetIntersectCollisionNZ() -- returns the Z normal of the entity hit surface
		else 
			r = 0
		end 
		return x3,y3,z3,xn,yn,zn,r
	end 
	
	local function RaycastALL(x1,y1,z1,x2,y2,z2,IgnoreObj)
		local x3,y3,z3 = 0,0,0
		local xn,yn,zn = 0,0,0
		local r = IntersectAll(x1,y1,z1,x2,y2,z2,IgnoreObj) -- returns 1 if the ray cast hits ANY entity or lightmapped geometry
		if r ~= nil then 
			--x=IntersectStatic(x1,y1,z1,x2,y2,z2,IgnoreObj) -- returns 1 if the ray cast hits non-animating entity or lightmapped geometry
			x3 = GetIntersectCollisionX() -- returns the X position of the entity hit position
			y3 = GetIntersectCollisionY() -- returns the Y position of the entity hit position
			z3 = GetIntersectCollisionZ() -- returns the Z position of the entity hit position
			xn = GetIntersectCollisionNX() -- returns the X normal of the entity hit surface
			yn = GetIntersectCollisionNY() -- returns the Y normal of the entity hit surface
			zn = GetIntersectCollisionNZ() -- returns the Z normal of the entity hit surface
		else 
			r = 0
		end 
		return x3,y3,z3,xn,yn,zn,r
	end 
	
	if g_PlayerGunName ~= "" then 	
		--if no gun set then we will just get the current gun when one is held 
		if pg.gunname == "" then 			
			pg.gunname = g_PlayerGunName
		end 
		--check if the player fired a gun 
		if g_PlayerGunFired == 1 then 
			if fired_recently == false then 
				fired_recently = true 
			end 
		else 
			if fired_recently == true then 
				--check if it was the portal gun 
				if pg.gunname == g_PlayerGunName then 
					--if it's an instant bullet gun we need to ray cast for position
					if pg.isprojectile == 0 then 	
						local x1,y1,z1 = g_PlayerPosX, g_PlayerPosY+pg.playerheight, g_PlayerPosZ
						local xa1,ya1,za1 = g_PlayerAngX, g_PlayerAngY, g_PlayerAngZ					
						xa1 = rad(xa1)
						ya1 = rad(ya1)
						za1 = rad(za1)
						local ox,oy,oz = U.Rotate3D( 0, 0, 3000, xa1, ya1, za1 ) 
						x2,y2,z3 = x1+ox,y1+oy,z1+oz 							
						local rx,ry,rz = RaycastTerrain(x1,y1,z1,x2,y2,z2)
						--check if we hit the terrain (doesn't appear to be working in Max beta 3)
						if rx ~= 0 and ry ~= 0 and rz ~= 0 then 
							--PromptDuration(rx.."  "..ry.."  "..rz, 5000)
							local p1 = pg.portal1
							local p2 = pg.portal2
							if currentportal == 1 or p2 == 0 then 
								if p1 > 0 then 
									CollisionOff(p1)
									SetPosition(p1,rx,ry,rz)
									RotateToPlayer(p1)
									MoveForward(p1,5)
									CollisionOn(p1)
									currentportal = 2
								end 
							elseif p2 > 0 then 
								CollisionOff(p2)
								SetPosition(p2,rx,ry,rz)
								RotateToPlayer(p2)
								MoveForward(p2,5)
								CollisionOn(p2)
								currentportal = 1
							end 					
						else 
							local rxn,ryn,rzn,r = 0,0,0,0
							rx,ry,rz,rxn,ryn,rzn,r = RaycastALL(x1,y1,z1,x2,y2,z2,0)
							if r ~= 0 then --hit a dynamic object (should be if ~= 0)							
								local p1 = pg.portal1
								local p2 = pg.portal2
								if currentportal == 1 or p2 == 0 then 
									if p1 > 0 then 
										CollisionOff(p1)
										SetPosition(p1,rx,ry,rz)
										RotateToPlayer(p1)
										MoveForward(p1,5)
										--CollisionOn(p1)
										currentportal = 2
									end 
								elseif p2 > 0 then 
									CollisionOff(p2)
									SetPosition(p2,rx,ry,rz)
									RotateToPlayer(p2)
									MoveForward(p2,5)
									--CollisionOn(p2)
									currentportal = 1
								end 					
								--PromptDuration(r,1000)
							else --should check static objects but not working yet
								rxn,ryn,rzn,r = 0,0,0,0
								rx,ry,rz,rxn,ryn,rzn,r = RaycastStatic(x1,y1,z1,x2,y2,z2,0)
								if r == 0 then --hit a static object
									local p1 = pg.portal1
									local p2 = pg.portal2
									if currentportal == 1 or p2 == 0 then 
										if p1 > 0 then 
											CollisionOff(p1)
											SetPosition(p1,rx,ry,rz)
											RotateToPlayer(p1)
											MoveForward(p1,5)
											--CollisionOn(p1)
											currentportal = 2
										end 
									elseif p2 > 0 then 
										CollisionOff(p2)
										SetPosition(p2,rx,ry,rz)
										RotateToPlayer(p2)
										MoveForward(p2,5)
										--CollisionOn(p2)
										currentportal = 1
									end 					
								end 
							end 
						end 
					--is a projectile so we need to check the collision info later
					else 
					
					end 
				end 
				if currentportal == 2 and bothportalsactive == 0 then 
					bothportalsactive = 1
				elseif currentportal == 1 and bothportalsactive == 1 then 
					bothportalsactive = 2 
				end 				
			end 
			fired_recently = false			
		end 
		if bothportalsactive == 2 then 
			local p1 = pg.portal1
			local p2 = pg.portal2
			local distp1 = GetPlayerDistance(p1)
			local distp2 = GetPlayerDistance(p2)
			--PromptLocal(p1,distp1)
			--PromptLocal(p2,distp2)
			--Text(50,90,3,ported_recently)
			if ported_recently ~= 1 then 						
				if distp1 < pg.portalrange then 
					if timer[e][1] == nil then 
						timer[e][1] = g_Time + (pg.portaldelay*1000)
					end 
					if g_Time > timer[e][1] then 
						SetFreezePosition(g_Entity[p2]['x'],g_Entity[p2]['y'],g_Entity[p2]['z'])
						SetFreezeAngle(g_Entity[p2]['anglex'],g_Entity[p2]['angley'],g_Entity[p2]['anglez'])
						TransportToFreezePosition()
						UnFreezePlayer()
						PlaySound(p2,1)
						ported_recently = 2 
						timer[e][1] = nil 
						isporting = false
					else 						
						if isporting == false then 
							current_img = 1 
							isporting = true 
							SetFreezeAngle(g_PlayerAngX,g_PlayerAngY,g_PlayerAngZ)
							SetFreezePosition(g_PlayerPosX,g_PlayerPosY,g_PlayerPosZ)
							TransportToFreezePosition()
							PlaySound(p1,0)
							FreezePlayer()
						else 
							if teleportimg[current_img] ~= nil then 
								SetSpriteImage(teleportspr,teleportimg[current_img])
							end 
							PasteSpritePosition(teleportspr,0,0)
							current_img = current_img + pg.animationspeed
							if current_img > 100 then 
								current_img = current_img - 100 
							end 
						end 
					end 
				elseif distp2 > pg.portalrange and ported_recently == 2 then 
					ported_recently = 0
				end 
			end 
			if ported_recently ~= 2 then 
				if distp2 < pg.portalrange then 
					if timer[e][1] == nil then 
						timer[e][1] = g_Time + (pg.portaldelay*1000)
					end 
					if g_Time > timer[e][1] then 
						SetFreezePosition(g_Entity[p1]['x'],g_Entity[p1]['y'],g_Entity[p1]['z'])
						SetFreezeAngle(g_Entity[p1]['anglex'],g_Entity[p1]['angley'],g_Entity[p1]['anglez'])
						TransportToFreezePosition()						
						UnFreezePlayer()
						PlaySound(p1,1)
						ported_recently = 1 
						timer[e][1] = nil 
						isporting = false 
					else 
						if isporting == false then 
							SetFreezeAngle(g_PlayerAngX,g_PlayerAngY,g_PlayerAngZ)
							SetFreezePosition(g_PlayerPosX,g_PlayerPosY,g_PlayerPosZ)
							TransportToFreezePosition()
							FreezePlayer()
							current_img = 1 
							PlaySound(p2,0)
							isporting = true 
						else 
							if teleportimg[current_img] ~= nil then 
								SetSpriteImage(teleportspr,teleportimg[current_img])
							end 
							PasteSpritePosition(teleportspr,0,0)
							current_img = current_img + pg.animationspeed
							if current_img > 100 then 
								current_img = current_img - 100 
							end 
						end 
					end 					
				elseif distp1 > pg.portalrange and ported_recently == 1 then 
					ported_recently = 0
				end 
			end 
		end 					
		--show the currently held gun if option is ticked
		if pg.showheldgun == 1 then 
			Prompt(g_PlayerGunName)
		end 
	end 

end 



