255 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
	
		
			8.5 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
local QBCore = exports['qb-core']:GetCoreObject()
 | 
						|
 | 
						|
function StartMinigame(combo)
 | 
						|
	local Coords = GetEntityCoords(PlayerPedId(), false)
 | 
						|
	local Object = GetClosestObjectOfType(Coords.x, Coords.y, Coords.z, 5.0, `v_ilev_gangsafedoor`, false, false, false)
 | 
						|
	local ObjectHeading = GetEntityHeading(Object)
 | 
						|
	local txd = CreateRuntimeTxd(SafeCracker.Config.TextureDict)
 | 
						|
	for i = 1, 2 do CreateRuntimeTextureFromImage(txd, tostring(i), "LockPart" .. i .. ".PNG") end
 | 
						|
	loadAnimDict("mini@safe_cracking")
 | 
						|
	TaskPlayAnim(PlayerPedId(), "mini@safe_cracking", "dial_turn_anti_fast_1", 3.0, 3.0, -1, 49, 0, 0, 0, 0)
 | 
						|
	FreezeEntityPosition(PlayerPedId(), true)
 | 
						|
	SetEntityHeading(PlayerPedId(), ObjectHeading)
 | 
						|
	SafeCracker.MinigameOpen = true
 | 
						|
	SafeCracker.SoundID 	  = GetSoundId() 
 | 
						|
	SafeCracker.Timer 		  = GetGameTimer()
 | 
						|
  	SafeCracker.StayClosed = false
 | 
						|
 | 
						|
	if not RequestAmbientAudioBank(SafeCracker.Config.AudioBank, false) then RequestAmbientAudioBank(SafeCracker.Config.AudioBankName, false); end
 | 
						|
	if not HasStreamedTextureDictLoaded(SafeCracker.Config.TextureDict, false) then RequestStreamedTextureDict(SafeCracker.Config.TextureDict, false); end
 | 
						|
	CreateThread(function() 
 | 
						|
		Update(combo)
 | 
						|
	end)
 | 
						|
end
 | 
						|
 | 
						|
RegisterNetEvent('SafeCracker:StartMinigame', function(combo)
 | 
						|
	StartMinigame(combo); 
 | 
						|
end)
 | 
						|
 | 
						|
function Update(combo)
 | 
						|
	CreateThread(function() HandleMinigame(combo); end)
 | 
						|
	while SafeCracker.MinigameOpen do
 | 
						|
		InputCheck()  
 | 
						|
		if IsEntityDead(PlayerPedId()) then EndMinigame(false, false); end
 | 
						|
		Wait(0)
 | 
						|
	end
 | 
						|
end
 | 
						|
 | 
						|
function InputCheck()
 | 
						|
    local leftKeyPressed = IsControlPressed( 0, 174) or 0 -- Left
 | 
						|
    local rightKeyPressed = IsControlPressed( 0, 175) or 0 -- Right
 | 
						|
    if IsControlPressed( 0, 322) then -- Esc
 | 
						|
        EndMinigame(false)
 | 
						|
    end
 | 
						|
    if IsControlPressed( 0, 20) then -- Z
 | 
						|
        rotSpeed = 0.1
 | 
						|
        modifier = 33
 | 
						|
    elseif IsControlPressed( 0, 21) then -- Left Shift
 | 
						|
        rotSpeed = 1.0
 | 
						|
        modifier = 50
 | 
						|
    else
 | 
						|
        rotSpeed = 0.4
 | 
						|
        modifier = 90
 | 
						|
    end
 | 
						|
	
 | 
						|
    local lockRotation = math.max(modifier / rotSpeed, 0.1)
 | 
						|
 | 
						|
	if leftKeyPressed ~= 0 or rightKeyPressed ~= 0 then
 | 
						|
		
 | 
						|
    	SafeCracker.LockRotation = SafeCracker.LockRotation - ( rotSpeed * tonumber( leftKeyPressed ) )
 | 
						|
    	SafeCracker.LockRotation = SafeCracker.LockRotation + ( rotSpeed * tonumber( rightKeyPressed ) )
 | 
						|
    	if (GetGameTimer() - SafeCracker.Timer) > lockRotation then 
 | 
						|
    		PlaySoundFrontend(0, SafeCracker.Config.SafeTurnSound, SafeCracker.Config.SafeSoundset, false)
 | 
						|
    		SafeCracker.Timer = GetGameTimer() 
 | 
						|
    	end
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
function HandleMinigame(combo) 
 | 
						|
	local lockNumbers 	 = {}
 | 
						|
	local correctGuesses = {}
 | 
						|
	lockNumbers = combo
 | 
						|
	if lockNumbers[1] <= 149 then
 | 
						|
		lockRot = math.random(150, 359)
 | 
						|
	else
 | 
						|
		lockRot = math.random(1, 149)
 | 
						|
	end
 | 
						|
 | 
						|
	-----------------------
 | 
						|
	-- REDO LOCK NUMBERS --
 | 
						|
	-----------------------
 | 
						|
	-- Make numbers persist if chosen.
 | 
						|
	-- Add number count for difficulty.
 | 
						|
	-- Multiples of 2 are positive, 45 - 359;
 | 
						|
	-- Multiples of 3 are negative, 719 - 405;
 | 
						|
	-- Everything else is negative, 45 - 359;
 | 
						|
 | 
						|
	---------------------------------------------
 | 
						|
	-- Still havn't done, you're welcome to ^^ --
 | 
						|
	---------------------------------------------
 | 
						|
	--[[for i = 1,5 do
 | 
						|
		print(math.floor((lockNumbers[i] % 360) / 3.60))
 | 
						|
	end]]--
 | 
						|
	--------------------------------------
 | 
						|
	-- Comment this out for a challenge --
 | 
						|
	--------------------------------------
 | 
						|
 | 
						|
    local correctCount	= 1
 | 
						|
    local hasRandomized	= false
 | 
						|
 | 
						|
    SafeCracker.LockRotation = 0.0 + lockRot
 | 
						|
	while SafeCracker.MinigameOpen do	
 | 
						|
		--Texture Dictionary, Texture Name, xPos, yPos, xSize, ySize, 		   Heading,   R,   G,   B,   A,
 | 
						|
		DrawSprite(SafeCracker.Config.TextureDict, 		 "1",  0.8,  0.5,  0.15,  0.26, -SafeCracker.LockRotation, 255, 255, 255, 255)
 | 
						|
		DrawSprite(SafeCracker.Config.TextureDict, 		 "2",  0.8,  0.5, 0.176, 0.306, 		      -0.0, 255, 255, 255, 255)	
 | 
						|
 | 
						|
		hasRandomized = true
 | 
						|
 | 
						|
		local lockVal = math.floor(SafeCracker.LockRotation)
 | 
						|
 | 
						|
		if correctCount > 1 and correctCount < (#lockNumbers + 1) and lockVal + (SafeCracker.Config.LockTolerance * 3.60) < lockNumbers[correctCount - 1] and lockNumbers[correctCount - 1] < lockNumbers[correctCount] then EndMinigame(false); SafeCracker.MinigameOpen = false; 
 | 
						|
		elseif correctCount > 1 and correctCount < (#lockNumbers + 1) and lockVal - (SafeCracker.Config.LockTolerance * 3.60) > lockNumbers[correctCount - 1] and lockNumbers[correctCount - 1] > lockNumbers[correctCount] then EndMinigame(false); SafeCracker.MinigameOpen = false; 
 | 
						|
		elseif correctCount > #lockNumbers then EndMinigame(true)
 | 
						|
		end
 | 
						|
 | 
						|
		for k,v in pairs(lockNumbers) do
 | 
						|
			if not hasRandomized then SafeCracker.LockRotation = lockRot; end
 | 
						|
			if lockVal == v and correctCount == k then
 | 
						|
				local canAdd = true
 | 
						|
				for key,val in pairs(correctGuesses) do
 | 
						|
					if val == lockVal and key == correctCount then
 | 
						|
						canAdd = false
 | 
						|
					end
 | 
						|
				end
 | 
						|
 | 
						|
				if canAdd then 				
 | 
						|
					PlaySoundFrontend(-1, SafeCracker.Config.SafePinSound, SafeCracker.Config.SafeSoundset, true)
 | 
						|
					correctGuesses[correctCount] = lockVal
 | 
						|
					correctCount = correctCount + 1; 
 | 
						|
				end   				  			
 | 
						|
			end
 | 
						|
		end
 | 
						|
		Wait(0)
 | 
						|
	end
 | 
						|
end
 | 
						|
 | 
						|
 | 
						|
function EndMinigame(won)
 | 
						|
	SafeCracker.MinigameOpen = false
 | 
						|
	if won then 
 | 
						|
		PlaySoundFrontend(SafeCracker.SoundID, SafeCracker.Config.SafeFinalSound, SafeCracker.Config.SafeSoundset, true)
 | 
						|
		QBCore.Functions.Notify("Safe opened..", "success")
 | 
						|
	else
 | 
						|
		QBCore.Functions.Notify("Safe opening failed..", "error")
 | 
						|
	end
 | 
						|
  	TriggerEvent('SafeCracker:EndMinigame', won)
 | 
						|
	FreezeEntityPosition(PlayerPedId(), false)
 | 
						|
	ClearPedTasksImmediately(PlayerPedId())
 | 
						|
end
 | 
						|
 | 
						|
RegisterNetEvent('SafeCracker:EndGame', function()
 | 
						|
	EndMinigame();
 | 
						|
end)
 | 
						|
 | 
						|
function OpenSafeDoor()
 | 
						|
  CreateThread(function(...)
 | 
						|
    local objs = {}
 | 
						|
    local doorHash = (GetHashKey(SafeCracker.SafeModels.Door) % 0x100000000)
 | 
						|
    for k,v in pairs(objs) do
 | 
						|
      if (GetEntityModel(v)% 0x100000000) == doorHash then 
 | 
						|
 | 
						|
        local doorHeading = GetEntityPhysicsHeading(v)
 | 
						|
        local doorPosition = GetEntityCoords(v)
 | 
						|
 | 
						|
        SetEntityCollision(v, false, false)
 | 
						|
        FreezeEntityPosition(v, false)
 | 
						|
 | 
						|
        local targetHeading = doorHeading + 150
 | 
						|
        local tick = 0
 | 
						|
        while targetHeading > GetEntityHeading(v) and tick < 500 do    
 | 
						|
          tick = tick + 1
 | 
						|
          SetEntityHeading(v, GetEntityHeading(v) + 0.3)
 | 
						|
          SetEntityCoords(v, doorPosition, false, false, false, false)
 | 
						|
          Wait(0)
 | 
						|
        end
 | 
						|
 | 
						|
        if not (GetEntityHeading(v) >= targetHeading) then SetEntityHeading(v, targetHeading); end
 | 
						|
      end
 | 
						|
    end  
 | 
						|
  end)
 | 
						|
end
 | 
						|
 | 
						|
function loadAnimDict( dict )
 | 
						|
    while ( not HasAnimDictLoaded( dict ) ) do
 | 
						|
        RequestAnimDict( dict )
 | 
						|
        Wait( 5 )
 | 
						|
    end
 | 
						|
end 
 | 
						|
 | 
						|
function SpawnSafeObject(table, position, heading)
 | 
						|
	if not table then table = SafeCracker.SafeObjects; end
 | 
						|
	if not table or not position or not heading then return; end
 | 
						|
	if type(table) ~= 'table' or type(position) ~= 'vector3' or type(heading) ~= 'number' then return; end
 | 
						|
 | 
						|
	LoadModelTable(SafeCracker.SafeModels)
 | 
						|
 | 
						|
	local retTable = {}
 | 
						|
	local i = 0
 | 
						|
	for k,v in pairs(table) do
 | 
						|
		i = i + 1
 | 
						|
		local hash = GetHashKey(v.ModelName) % 0x100000000
 | 
						|
		local newHeading = heading + v.Heading
 | 
						|
 | 
						|
		local newObj = CreateObject(hash, v.Pos.x + position.x, v.Pos.y + position.y, v.Pos.z + position.z, false, false, false)
 | 
						|
 | 
						|
		if v.ModelName == SafeCracker.SafeModels.Door then 
 | 
						|
			SafeCracker.DoorObj = newObj
 | 
						|
			SafeCracker.DoorHeading = GetEntityHeading(SafeCracker.DoorObj)
 | 
						|
		end
 | 
						|
 | 
						|
		SetEntityAsMissionEntity(newObj, true)
 | 
						|
		FreezeEntityPosition(newObj, true)
 | 
						|
		SetEntityHeading(newObj, newHeading)
 | 
						|
 | 
						|
		if v.Rot.x ~= 0.0 or v.Rot.y ~= 0.0 or v.Rot.z ~= 0.0 then SetEntityRotation(newObj, v.Rot.x, v.Rot.y, v.Rot.z, 1, true); end
 | 
						|
		retTable[v.ModelName] = newObj		
 | 
						|
	end
 | 
						|
 | 
						|
	ReleaseModelTable(SafeCracker.SafeModels)
 | 
						|
	SafeCracker.Objects = retTable
 | 
						|
	return retTable
 | 
						|
end
 | 
						|
 | 
						|
function DelSafe()
 | 
						|
	for k,v in pairs(SafeCracker.Objects) do DeleteObject(v); end
 | 
						|
end
 | 
						|
 | 
						|
RegisterNetEvent('SafeCracker:SpawnSafe', function(tab, pos, heading, cb)
 | 
						|
if cb then cb(SpawnSafeObject(tab,pos,heading)) else SpawnSafeObject(tab,pos,heading); end; end)
 | 
						|
 | 
						|
function LoadModelTable(table)
 | 
						|
  if type(table) ~= 'table' then return false; end
 | 
						|
  for k,v in pairs(table) do
 | 
						|
    if type(v) == 'string' then
 | 
						|
      local hk = GetHashKey(v) % 0x100000000
 | 
						|
      while not HasModelLoaded(hk) do
 | 
						|
        RequestModel(hk)
 | 
						|
        Wait(0)
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
  return true
 | 
						|
end
 | 
						|
 | 
						|
function ReleaseModelTable(table)
 | 
						|
  if type(table) ~= 'table' then return false; end
 | 
						|
  for k,v in pairs(table) do
 | 
						|
    if type(v) == 'string' then
 | 
						|
      local hk = GetHashKey(v) % 0x100000000
 | 
						|
      if HasModelLoaded(hk) then
 | 
						|
        SetModelAsNoLongerNeeded(hk)
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
  return true
 | 
						|
end
 |