196 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
-- https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
 | 
						|
local sequenceKeys = {
 | 
						|
    { code = 0x56, label = "V" },
 | 
						|
    { code = 0x43, label = "C" },
 | 
						|
    { code = 0x52, label = "R" },
 | 
						|
    { code = 0x51, label = "Q" },
 | 
						|
    { code = 0x47, label = "G" },
 | 
						|
    { code = 0x45, label = "E" },
 | 
						|
    { code = 0x58, label = "X" },
 | 
						|
    { code = 0x59, label = "Y" },
 | 
						|
    { code = 0x48, label = "H" },
 | 
						|
    { code = 0x5A, label = "Z" },
 | 
						|
}
 | 
						|
 | 
						|
local function GenerateSequence(len)
 | 
						|
    local seq = {}
 | 
						|
    for i = 1, len do
 | 
						|
        seq[i] = sequenceKeys[math.random(#sequenceKeys)]
 | 
						|
    end
 | 
						|
    return seq
 | 
						|
end
 | 
						|
 | 
						|
local function DrawSequenceRect(x, y, w, h, r, g, b, a)
 | 
						|
    DrawRect(x + w / 2, y + h / 2, w, h, r, g, b, math.floor(a))
 | 
						|
end
 | 
						|
 | 
						|
local function DrawSequenceText(x, y, text, scale, r, g, b, a, center, outline)
 | 
						|
    SetTextFont(0)
 | 
						|
    SetTextScale(scale, scale)
 | 
						|
    SetTextColour(r, g, b, math.floor(a))
 | 
						|
    SetTextCentre(center)
 | 
						|
    if outline then
 | 
						|
        SetTextDropshadow(1, 0, 0, 0, 50)
 | 
						|
        SetTextOutline()
 | 
						|
    end
 | 
						|
    SetTextEntry("STRING")
 | 
						|
    AddTextComponentSubstringPlayerName(text)
 | 
						|
    DrawText(x, y)
 | 
						|
end
 | 
						|
 | 
						|
local function DrawLabelAndInfo(sx, sy, totalHeight, label, infoText, alpha)
 | 
						|
    alpha = alpha or 1
 | 
						|
    local labelY = sy - (totalHeight * 0.5) - 0.02
 | 
						|
    local infoY  = sy + (totalHeight * 0.5) + 0.005
 | 
						|
    
 | 
						|
    if label and label ~= "" then
 | 
						|
        DrawSequenceText(sx, labelY, label, 0.18, 255, 255, 255, 255 * alpha, true, true)
 | 
						|
    end
 | 
						|
    if infoText and infoText ~= "" then
 | 
						|
        DrawSequenceText(sx, infoY, infoText, 0.15, 255, 255, 255, 255 * alpha, true, true)
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
local function DrawMinigameBoxes(sequence, pressedFlags, coords, currentIndex, hiddenMode, label, infoText)
 | 
						|
    local onScreen, sx, sy = GetScreenCoordFromWorldCoord(coords.x, coords.y, coords.z)
 | 
						|
    if not onScreen then return end
 | 
						|
 | 
						|
    local boxW, boxH = 0.02, 0.03
 | 
						|
    local spacing    = 0.002
 | 
						|
    local count      = #sequence
 | 
						|
    local totalW     = (count * boxW) + ((count - 1) * spacing)
 | 
						|
    local startX     = sx - (totalW * 0.5)
 | 
						|
    
 | 
						|
    for i, keyData in ipairs(sequence) do
 | 
						|
        local bx = startX + (i - 1) * (boxW + spacing)
 | 
						|
 | 
						|
        local r, g, b = 0, 0, 0
 | 
						|
        if pressedFlags[i] then
 | 
						|
            r, g, b = 108, 240, 156
 | 
						|
        end
 | 
						|
        DrawSequenceRect(bx, sy - boxH / 2, boxW, boxH, r, g, b, 180)
 | 
						|
 | 
						|
        local label = keyData.label
 | 
						|
        if hiddenMode and currentIndex > 1 and (not pressedFlags[i]) then
 | 
						|
            local scrambled = {'#', '?', '$', '%'}
 | 
						|
            label = scrambled[((math.floor(GetGameTimer() / 50) + i) % #scrambled) + 1]
 | 
						|
        end
 | 
						|
 | 
						|
        local textX = bx + (boxW / 2)
 | 
						|
        local textY = sy - (boxH / 2) + 0.004
 | 
						|
        local textScale = 0.3 - (0.022 * #label)
 | 
						|
        if textScale < 0.18 then textScale = 0.18 end
 | 
						|
        DrawSequenceText(textX, textY, label, textScale, 255, 255, 255, 255, true)
 | 
						|
    end
 | 
						|
    
 | 
						|
    DrawLabelAndInfo(sx, sy, boxH, label, infoText)
 | 
						|
end
 | 
						|
 | 
						|
local function DrawFinalSequence(sequence, coords, colorMode, label, infoText, alpha)
 | 
						|
    local onScreen, sx, sy = GetScreenCoordFromWorldCoord(coords.x, coords.y, coords.z)
 | 
						|
    if not onScreen then return end
 | 
						|
 | 
						|
    local boxW, boxH = 0.02, 0.03
 | 
						|
    local spacing    = 0.002
 | 
						|
    local count      = #sequence
 | 
						|
    local totalW     = (count * boxW) + ((count - 1) * spacing)
 | 
						|
    local startX     = sx - (totalW * 0.5)
 | 
						|
 | 
						|
    local r, g, b    = 108, 240, 156
 | 
						|
    if colorMode == 'red' then
 | 
						|
        r, g, b = 200, 50, 50
 | 
						|
    end
 | 
						|
    
 | 
						|
    for i, keyData in ipairs(sequence) do
 | 
						|
        local bx = startX + (i - 1) * (boxW + spacing)
 | 
						|
 | 
						|
        DrawSequenceRect(bx, sy - boxH / 2, boxW, boxH, r, g, b, 180 * alpha)
 | 
						|
 | 
						|
        local label = keyData.label
 | 
						|
        local textX = bx + (boxW / 2)
 | 
						|
        local textY = sy - (boxH / 2) + 0.004
 | 
						|
        local textScale = 0.3 - (0.022 * #label)
 | 
						|
        if textScale < 0.18 then textScale = 0.18 end
 | 
						|
 | 
						|
        DrawSequenceText(textX, textY, label, textScale, 255, 255, 255, 255 * alpha, true)
 | 
						|
    end
 | 
						|
    
 | 
						|
    DrawLabelAndInfo(sx, sy, boxH, label, infoText, alpha)
 | 
						|
end
 | 
						|
 | 
						|
local function DisablePlayerInput()
 | 
						|
    for group = 0, 2 do
 | 
						|
        DisableAllControlActions(group)
 | 
						|
    end
 | 
						|
    -- Re-enable camera look + zoom
 | 
						|
    EnableControlAction(0, 1, true)   -- LookLeftRight
 | 
						|
    EnableControlAction(0, 2, true)   -- LookUpDown
 | 
						|
    EnableControlAction(0, 241, true) -- MouseWheelUp  (zoom)
 | 
						|
    EnableControlAction(0, 242, true) -- MouseWheelDown (zoom)
 | 
						|
end
 | 
						|
 | 
						|
function SequenceMinigame(coords, length, hiddenMode, label, infoText)
 | 
						|
    local sequence = GenerateSequence(length)
 | 
						|
    local pressedFlags = {}
 | 
						|
    for i = 1, length do
 | 
						|
        pressedFlags[i] = false
 | 
						|
    end
 | 
						|
 | 
						|
    local currentIndex = 1
 | 
						|
    local gameActive   = true
 | 
						|
    local wasSuccess   = false
 | 
						|
 | 
						|
    while gameActive do
 | 
						|
        Citizen.Wait(0)
 | 
						|
        
 | 
						|
        if IsRawKeyDown(0x1B) or IsRawKeyDown(0x08) then
 | 
						|
            return false
 | 
						|
        end
 | 
						|
 | 
						|
        DisablePlayerInput()
 | 
						|
 | 
						|
        DrawMinigameBoxes(sequence, pressedFlags, coords, currentIndex, hiddenMode, label, infoText)
 | 
						|
 | 
						|
        local correctCode = sequence[currentIndex].code
 | 
						|
 | 
						|
        if IsRawKeyReleased(correctCode) then
 | 
						|
            pressedFlags[currentIndex] = true
 | 
						|
            currentIndex = currentIndex + 1
 | 
						|
            if currentIndex > #sequence then
 | 
						|
                wasSuccess = true
 | 
						|
                gameActive = false
 | 
						|
            end
 | 
						|
        else
 | 
						|
            for _, keyData in ipairs(sequenceKeys) do
 | 
						|
                if IsRawKeyReleased(keyData.code) then
 | 
						|
                    if keyData.code ~= correctCode then
 | 
						|
                        wasSuccess = false
 | 
						|
                        gameActive = false
 | 
						|
                    end
 | 
						|
                    break
 | 
						|
                end
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    local endDuration, colorMode
 | 
						|
    if wasSuccess then
 | 
						|
        colorMode = 'green'
 | 
						|
        endDuration = 500
 | 
						|
    else
 | 
						|
        colorMode = 'red'
 | 
						|
        endDuration = 1000
 | 
						|
    end
 | 
						|
    
 | 
						|
    local endTime = GetGameTimer() + endDuration
 | 
						|
    while GetGameTimer() < endTime do
 | 
						|
        Citizen.Wait(0)
 | 
						|
        DisablePlayerInput()
 | 
						|
 | 
						|
        local alpha = math.max(0, (endTime - GetGameTimer()) / endDuration)
 | 
						|
        
 | 
						|
        DrawFinalSequence(sequence, coords, colorMode, label, infoText, alpha)
 | 
						|
    end
 | 
						|
 | 
						|
    return wasSuccess
 | 
						|
end
 |