require(GlobalDependencys:GetDependency("StandardBase"):GetPackageName())

--GAME VARS
fAdditionalFOV = 0
FOVScale = 0
fDefaultAspectRatio = 1.777778
fFOVMax = 110
HUD_Left = 0
HUD_Width = 0

--ControlVars
bFOVFix = true
bFixEnabled = true
bAspectRatio = true
bResLimit = true
bHUDFix = false
bLODFix = true

--PROCESS VARS
Process_FriendlyName = Module:GetFriendlyName()
Process_WindowName = "*"
Process_ClassName = "UnrealWindow"
Process_EXEName = "LOP-Win64-Shipping.exe"

--INJECTION BEHAVIOUR
InjectDelay = 1000
WriteInterval = 500
SearchInterval = 1000
SuspendThread = true

--Name                         Manual/Auto/Hybrid  		Steam/Origin/Any                IncludeFile:Configure;Enable;Periodic;Disable;
SupportedVersions = { 		
{"Automatically Detect",       "Hybrid",  		  	"Any",	                         "Configure_SignatureScan;Enable_Inject;Periodic;Disable_Inject;"},
}

function Init_Controls()
	DefaultControls.AddHeader("Header_FOV","FOV Fine adjustment",15,70,210,17)
	DefaultControls.AddFixedFOVSlider("FOVSliderF","FOVSliderF_Changed",55,100,125,35,0,30,0,1)
	DefaultControls.AddHeader("Header_FixesEnableDisable","Individual Fixes",245,70,210,17)
	DefaultControls.AddFixToggle("CKFOVFix_Enable","FOV Fix","CKFOVFix_Changed",255,101,180,14)	
	DefaultControls.AddFixToggle("CKAspect_Enable","Aspect Ratio","CKAspect_Changed",255,120,180,14)
	DefaultControls.AddFixToggle("CKHUDFix_Enable","HUD Fix","CKHUDFix_Changed",255,139,180,14,false)		
	DefaultControls.AddFixToggle("CKResLimit_Enable","Remove Resolution Limit","CKResLimit_Changed",255,139+19,180,14)

	HUDScalingOptions = {"Use DisplayDetection","Constrain HUD to 16:9","Constrain HUD to 16:10","Constrain HUD to 21:9"}
	DefaultControls.AddHeader("Header_HUDScalingOptions","HUD Scaling Options",245,210-19,210,17)
	DefaultControls.AddComboBox("HUDScalingCombo","HUDScalingCombo_Changed",HUDScalingOptions,255,235-19,190,300)	
	
	FOVSliderF:SetLabel1Text("0%")
	FOVSliderF:SetLabel2Text("30%")
	FOVSliderF:SetTickFrequency(5)

end

function Configure_SignatureScan() 



	local tAddress = HackTool:AddAddress("AspectRatioFix")
	if HackTool:SignatureScan("F3 0F 10 ?? ?? ?? ?? ?? F3 0F 58 ?? ?? ?? ?? ?? EB ?? F3 0F 10 ?? ?? ?? ?? ?? F3 0F 11 ?? ?? 8B",tAddress,PAGE_EXECUTE_READ,0x1F,Process_EXEName) == 0 then	
		return ErrorOccurred(string.format(SigScanError,tAddress:GetName()))			
	else
		print( tAddress:GetInfo(TYPE_ADDRESS) )		
	end		

	
		local tAddress = HackTool:AddAddress("FOVFix")
		if HackTool:SignatureScan("F3 0F 10 ?? ?? ?? ?? ?? F3 0F 58 ?? ?? ?? ?? ?? EB ?? F3 0F 10 ?? ?? ?? ?? ?? F3 0F 11 ?? ?? 8B",tAddress,PAGE_EXECUTE_READ,0x1A,Process_EXEName) == 0 then	
			return ErrorOccurred(string.format(SigScanError,tAddress:GetName()))
		else
			print( tAddress:GetInfo(TYPE_ADDRESS) )		
		end

		local tAddress = HackTool:AddAddress("FrameLimiter")
		if HackTool:SignatureScan("0F ?? ?? EB ?? 48 8B ?? 44 0F ?? ?? ?? 48 8B ?? ?? ?? 73 ?? 80",tAddress,PAGE_EXECUTE_READ,0x8,Process_EXEName) == 0 then	
			return ErrorOccurred(string.format(SigScanError,tAddress:GetName()))
		else
			print( tAddress:GetInfo(TYPE_ADDRESS) )		
		end	

		--remove lower limit
		local tAddress = HackTool:AddAddress("ResLimit2")
		if HackTool:SignatureScan("4C 89 ?? ?? ?? 77 ?? F3 0F 10 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? CD CC CC 3F 48 ?? ?? ?? ?? ?? ?? 33 ?? F3",tAddress,PAGE_EXECUTE_READ,0x22,Process_EXEName) == 0 then	
			return ErrorOccurred(string.format(SigScanError,tAddress:GetName()))
		else
			print( tAddress:GetInfo(TYPE_ADDRESS) )		
		end	

		--remove upper limit
		local tAddress = HackTool:AddAddress("ResLimit1")
		if HackTool:SignatureScan("7F ?? 42 8B ?? ?? ?? 3B ?? 7F ?? 41 ?? ?? 02 75 ?? 3B ?? 7D 04 3B ?? 7C ??",tAddress,PAGE_EXECUTE_READ,0x0,Process_EXEName) == 0 then	
			return ErrorOccurred(string.format(SigScanError,tAddress:GetName()))
		else
			print( tAddress:GetInfo(TYPE_ADDRESS) )		
		end	

		local tAddress = HackTool:AddAddress("HUDFix")
		if HackTool:SignatureScan("F3 44 0F 59 ?? ?? ?? ?? ?? 44 0F ?? ?? F3 ?? 0F 59 ?? F3 ?? 0F 59 ?? ?? F3 44 0F 59 ?? ?? ?? ?? ?? 75",tAddress,PAGE_EXECUTE_READ,0xD,Process_EXEName) == 0 then	
			return ErrorOccurred(string.format(SigScanError,tAddress:GetName()))
		else
			print( tAddress:GetInfo(TYPE_ADDRESS) )		
		end	



	return true

end


function Enable_Inject() 

	FOVCalculator = HackTool:InjectFOVCalculator("FOVCalculator")
	
	local Variables = HackTool:AllocateMemory("Variables",0)
	Variables:PushFloat("AR_Ingame_In")
	Variables:PushFloat("AR_Ingame_Out")
	Variables:PushFloat("FOV_In")
	Variables:PushFloat("FOV_Scale")
	Variables:PushFloat("FOV_Out")
	Variables:PushFloat("HUD_Left")
	Variables:PushFloat("HUD_Width")
	Variables:PushFloat("tmp")
	Variables:Allocate()
	
	local asm = [[	
			
			
		(codecave:jmp)AspectRatioFix,AspectRatioFix_cc:
			%originalcode%
			mov [(allocation)Variables->AR_Ingame_In], $$1			$ctx=1
			mov $$1, [(allocation)Variables->AR_Ingame_Out]			$ctx=1
			jmp %returnaddress%
			%end%

		(codecave:jmp)FOVFix,FOVFix_cc:
			movss [(allocation)Variables->FOV_In], $$2				$ctx=1
			fld dword [(allocation)Variables->FOV_In]
			fmul dword ptr [(allocation)Variables->FOV_Scale]
			call (allocation)FOVCalculator			
			fstp dword ptr [(allocation)Variables->FOV_Out]			
			movss $$2, [(allocation)Variables->FOV_Out]				$ctx=1
			%originalcode%
			jmp %returnaddress%		
			%end%

		(codecave:jmp)HUDFix,HUDFix_cc:
			movss [tmp], $$1										$ctx=1
			movss $$1, [(allocation)Variables->HUD_Width]			$ctx=1
			divss $$1, [$$2+0x8]									$ctx=1
			movss [$$2], $$1										$ctx=1
			movss $$1, [(allocation)Variables->HUD_Left]			$ctx=1
			movss [$$2+0x2C], $$1									$ctx=1			
			movss $$1, [tmp]										$ctx=1			
			%originalcode%
			jmp %returnaddress%		
			%end%
			
		tmp: (float)1.0
			
		(codecave)ResLimit1,ResLimit1_cc:
			jmp $$1+0xF												$ctx=6

		(codecave)ResLimit2,ResLimit2_cc:
			xorps $$1,$$1											$ctx=1
			nop [rax+rax+0x10]

	]]

	if HackTool:CompileAssembly(asm,"FOVFix") == nil then
		return ErrorOccurred("Assembly compilation failed...")
	else
		ResolutionChanged()
		Toggle_CodeCave("FOVFix_cc",bFOVFix)
		Toggle_CodeCave("HUDFix_cc",bHUDFix)
		Toggle_CodeCave("AspectRatioFix_cc",bAspectRatio)
		Toggle_CodeCave("ResLimit1_cc",bResLimit)
		Toggle_CodeCave("ResLimit2_cc",bResLimit)
	end	
		
end

function Periodic()
	
	PluginViewport:AppendStatusMessage(	string.format("\r\n%s",FOVCalculatorSummary("FOVCalculator","World",bFOVFix)) )	
	
	local Variables = HackTool:GetAllocation("Variables")
	if Variables then 	
		if bAspectRatio == true then			
			PluginViewport:AppendStatusMessage( string.format("     (Aspect Ratio) In=%.2f, Out=%.2f",	Variables["AR_Ingame_In"]:ReadFloat(),Variables["AR_Ingame_Out"]:ReadFloat()) )	
		end
		
		PluginViewport:AppendStatusMessage( "\r\n" )
		
		if bHUDFix == true then
			PluginViewport:AppendStatusMessage( string.format("     (HUDScaling) Left=%.0f, Width=%.0f   (%d:%s)", Variables["HUD_Left"]:ReadFloat(), Variables["HUD_Width"]:ReadFloat(), HUDScalingCombo:GetSelectedIndex(), HUDScalingCombo:GetSelectedString()) )
		end
	end		
	
end

function Disable_Inject()
		
	CleanUp()
	
end

function ResolutionChanged() 

	SyncDisplayDetection()
	
	local CurrentAspectRatio = DisplayInfo:GetAspectRatio()
	
	if CurrentAspectRatio < 1.78 then
		CurrentAspectRatio = fDefaultAspectRatio
	end
	
	local AspectDevisional = CurrentAspectRatio/fDefaultAspectRatio
	
	
	UpdateFOVCalculator("FOVCalculator",AspectDevisional,0.0)		

	local Variables = HackTool:GetAllocation("Variables")
	if Variables then
		if Variables["AR_Ingame_Out"] then
			Variables["AR_Ingame_Out"]:WriteFloat(CurrentAspectRatio)
		end		
	end
	
	CalculateHUDScaling()
	WriteHUDScaling()
	WriteFOVScaling()

end

function CalculateHUDScaling() 	

	local Variables = HackTool:GetAllocation("Variables")
	if Variables then
	
		local cbIndex = HUDScalingCombo:GetSelectedIndex()
		
		local tHeight = DisplayInfo:GetHeight()
		local tWidth = DisplayInfo:GetWidth()
		
		if cbIndex == 0 then --Use DisplayDetection
			HUD_Width = DisplayInfo:GetfOffsetWidth(0,0)				
		elseif cbIndex == 1 then  -- Use 21:9	
			HUD_Width = math.floor(tHeight * 1.7777778) 	
		elseif cbIndex == 2 then --use 16:9	
			HUD_Width = math.floor(tHeight * 1.6000001)  		
		elseif cbIndex == 3 then  -- Use 21:9	
			HUD_Width = math.floor(tHeight * 2.3333334) 
		end
		
		if cbIndex ~= 0 then
			HUD_Left = (tWidth - HUD_Width) / 2
		else
			HUD_Left = DisplayInfo:GetiOffsetX(0)
		end

	end
	
end

function WriteHUDScaling()

	local Variables = HackTool:GetAllocation("Variables")
	if Variables and Variables["HUD_Left"] and Variables["HUD_Width"] then
		Variables["HUD_Left"]:WriteFloat(HUD_Left)
		Variables["HUD_Width"]:WriteFloat(HUD_Width)
	end

end

function HUDScalingCombo_Changed(Sender)

	CalculateHUDScaling()
	WriteHUDScaling()
	ForceUpdate()
	
end

function CKFOVFix_Changed(Sender)

	bFOVFix = Toggle_CheckFix(Sender)
	
	if bFOVFix then
		WriteFOVScaling()
	end
	
	Toggle_CodeCave("FOVFix_cc",bFOVFix)
	ForceUpdate()
	
end

function CKAspect_Changed(Sender)

	bAspectRatio = Toggle_CheckFix(Sender)
	Toggle_CodeCave("AspectRatioFix_cc",bAspectRatio)	
	ForceUpdate()
	
end

function CKHUDFix_Changed(Sender)

	bHUDFix = Toggle_CheckFix(Sender)
	Toggle_CodeCave("HUDFix_cc",bHUDFix)	
	WriteHUDScaling()	
	ForceUpdate()
	
end

function CKResLimit_Changed(Sender)

	bResLimit = Toggle_CheckFix(Sender)
	Toggle_CodeCave("ResLimit1_cc",bResLimit)	
	Toggle_CodeCave("ResLimit2_cc",bResLimit)
	ForceUpdate()
	
end

function HK_IncreaseFOV()	
	FOVSliderF:OffsetPosition(1)
end

function HK_DecreaseFOV()	
	FOVSliderF:OffsetPosition(-1)
end

function FOVSliderF_Changed(Sender)

	local tfAdditionalFOV = Sender:GetPosition()
	lblFOVSliderF.Caption:SetCaption( string.format("Value: +%.0f%%",tfAdditionalFOV) )
	
	FOVScale = 1.0 + (tfAdditionalFOV/100)
	
	WriteFOVScaling()
	
	ForceUpdate()
		
end

function WriteFOVScaling() 

	local Variables = HackTool:GetAllocation("Variables")
	if Variables and Variables["FOV_Scale"] then
		Variables["FOV_Scale"]:WriteFloat(FOVScale)
	end

end

function Init()	
	Init_BaseControls()
	Init_Controls()
end

function DeInit()
	DisableFix()
end

