204 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
	
		
			6.9 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 DrawSecRect(x, y, w, h, r, g, b, a)
 | 
						|
    DrawRect(x + w * 0.5, y + h * 0.5, w, h, r, g, b, math.floor(a))
 | 
						|
end
 | 
						|
 | 
						|
local function DrawSeqText(x, y, text, scale, r, g, b, a, outline)
 | 
						|
    SetTextFont(0)
 | 
						|
    SetTextScale(scale, scale)
 | 
						|
    SetTextColour(r, g, b, math.floor(a))
 | 
						|
    SetTextCentre(true)
 | 
						|
    if outline then
 | 
						|
        SetTextDropshadow(1, 0, 0, 0, 50)
 | 
						|
        SetTextOutline()
 | 
						|
    end
 | 
						|
    SetTextEntry("STRING")
 | 
						|
    AddTextComponentSubstringPlayerName(text)
 | 
						|
    DrawText(x, y)
 | 
						|
end
 | 
						|
 | 
						|
local function DisablePlayerInput()
 | 
						|
    for group = 0, 2 do
 | 
						|
        DisableAllControlActions(group)
 | 
						|
    end
 | 
						|
    EnableControlAction(0, 1, true)
 | 
						|
    EnableControlAction(0, 2, true)
 | 
						|
    EnableControlAction(0, 241, true)
 | 
						|
    EnableControlAction(0, 242, true)
 | 
						|
end
 | 
						|
 | 
						|
local function DrawMultiMinigameBoxes(multiSequences, currentStep, progress, pressedFlags, coords, label, infoText, alpha, boostPos)
 | 
						|
    alpha = alpha or 1
 | 
						|
    local onScreen, sx, sy = GetScreenCoordFromWorldCoord(coords.x, coords.y, coords.z)
 | 
						|
    if not onScreen then return end
 | 
						|
 | 
						|
    local seqCount    = #multiSequences
 | 
						|
    local boxW, boxH  = 0.02, 0.03
 | 
						|
    local stepSpace   = 0.002
 | 
						|
    local rowSpace    = 0.003
 | 
						|
 | 
						|
    local totalHeight = seqCount * boxH + (seqCount - 1) * rowSpace
 | 
						|
    local startY      = sy - (totalHeight * 0.5)
 | 
						|
    
 | 
						|
    local labelY = startY - 0.04
 | 
						|
    if label and label ~= "" then
 | 
						|
        DrawSeqText(sx, labelY, label, 0.18, 255, 255, 255, 255 * alpha, true)
 | 
						|
    end
 | 
						|
    local infoY = startY + totalHeight
 | 
						|
    if infoText and infoText ~= "" then
 | 
						|
        DrawSeqText(sx, infoY, infoText, 0.15, 255, 255, 255, 255 * alpha, true)
 | 
						|
    end
 | 
						|
 | 
						|
    for s = 1, seqCount do
 | 
						|
        local sequence   = multiSequences[s]
 | 
						|
        local seqSteps   = #sequence
 | 
						|
        local rowY       = startY + (s - 1) * (boxH + rowSpace)
 | 
						|
        local totalW     = seqSteps * boxW + (seqSteps - 1) * stepSpace
 | 
						|
        local rowStartX  = sx - (totalW * 0.5)
 | 
						|
        local cStep      = currentStep[s]
 | 
						|
        local cProgress  = progress[s]
 | 
						|
        local rowPressed = pressedFlags[s]
 | 
						|
 | 
						|
        for i = 1, seqSteps do
 | 
						|
            local bx = rowStartX + (i - 1) * (boxW + stepSpace)
 | 
						|
            if rowPressed[i] then
 | 
						|
                DrawSecRect(bx, rowY - boxH * 0.5, boxW, boxH, 108, 240, 156, 180 * alpha)
 | 
						|
            elseif i == cStep then
 | 
						|
                DrawSecRect(bx, rowY - boxH * 0.5, boxW, boxH, 0, 0, 0, 180 * alpha)
 | 
						|
                
 | 
						|
                local fillW = boxW * cProgress
 | 
						|
                if boostPos and boostPos + 0.1 > cProgress then
 | 
						|
                    DrawSecRect(bx + boxW * boostPos, rowY - boxH * 0.5, boxW * 0.1, boxH, 108, 255, 156, 75 * alpha)
 | 
						|
                end
 | 
						|
                
 | 
						|
                DrawSecRect(bx, rowY - boxH * 0.5, fillW, boxH, 108, 240, 156, 180 * alpha)
 | 
						|
            else
 | 
						|
                DrawSecRect(bx, rowY - boxH * 0.5, boxW, boxH, 0, 0, 0, 180 * alpha)
 | 
						|
            end
 | 
						|
 | 
						|
            local stepData = sequence[i]
 | 
						|
            local textX = bx + boxW * 0.5
 | 
						|
            local textY = rowY - boxH * 0.5 + 0.005
 | 
						|
            local labelText = stepData.label or "??"
 | 
						|
            local tScale = 0.3 - (0.022 * #labelText)
 | 
						|
            if tScale < 0.18 then tScale = 0.18 end
 | 
						|
            DrawSeqText(textX, textY, labelText, tScale, 255, 255, 255, 255 * alpha, false)
 | 
						|
        end
 | 
						|
    end
 | 
						|
end
 | 
						|
 | 
						|
function HoldSequenceMinigame(coords, sequenceCount, length, timePerInput, allowSkips, label, infoText)
 | 
						|
    sequenceCount = math.max(1, sequenceCount)
 | 
						|
    
 | 
						|
    local seed = GetGameTimer()
 | 
						|
    local multiSequences = {}
 | 
						|
    for s = 1, sequenceCount do
 | 
						|
        local seq = {}
 | 
						|
        for i = 1, length do
 | 
						|
            seq[i] = sequenceKeys[math.random(#sequenceKeys)]
 | 
						|
        end
 | 
						|
        multiSequences[s] = seq
 | 
						|
    end
 | 
						|
 | 
						|
    local currentStep  = {}
 | 
						|
    local progress     = {}
 | 
						|
    local pressedFlags = {}
 | 
						|
    for s = 1, sequenceCount do
 | 
						|
        currentStep[s]  = 1
 | 
						|
        progress[s]     = 0.0
 | 
						|
        pressedFlags[s] = {}
 | 
						|
        for i = 1, length do
 | 
						|
            pressedFlags[s][i] = false
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    local finished = false
 | 
						|
    local prevTime = nil
 | 
						|
 | 
						|
    while not finished do
 | 
						|
        Citizen.Wait(0)
 | 
						|
        
 | 
						|
        if IsRawKeyDown(0x1B) or IsRawKeyDown(0x08) then
 | 
						|
            return false
 | 
						|
        end
 | 
						|
        
 | 
						|
        DisablePlayerInput()
 | 
						|
        
 | 
						|
        local boostPos
 | 
						|
        if sequenceCount == 1 and allowSkips then
 | 
						|
            math.randomseed(seed .. currentStep[1])
 | 
						|
            boostPos = math.random(5, 8) / 10
 | 
						|
        end
 | 
						|
 | 
						|
        DrawMultiMinigameBoxes(multiSequences, currentStep, progress, pressedFlags, coords, label, infoText, 1, boostPos)
 | 
						|
 | 
						|
        local allDone = true
 | 
						|
        for s = 1, sequenceCount do
 | 
						|
            if currentStep[s] <= length then
 | 
						|
                allDone = false
 | 
						|
                break
 | 
						|
            end
 | 
						|
        end
 | 
						|
        if allDone then
 | 
						|
            finished = true
 | 
						|
        else
 | 
						|
            local now = GetGameTimer()
 | 
						|
            if not prevTime then
 | 
						|
                prevTime = now
 | 
						|
            end
 | 
						|
            local deltaMS = now - prevTime
 | 
						|
            prevTime      = now
 | 
						|
 | 
						|
            for s = 1, sequenceCount do
 | 
						|
                if currentStep[s] <= length then
 | 
						|
                    local stepData   = multiSequences[s][currentStep[s]]
 | 
						|
                    local correctKey = stepData.code
 | 
						|
                    if IsRawKeyDown(correctKey) then
 | 
						|
                        local fillSpeed = deltaMS / timePerInput
 | 
						|
                        progress[s] = progress[s] + fillSpeed
 | 
						|
                        if progress[s] >= 1.0 then
 | 
						|
                            progress[s] = 1.0
 | 
						|
                            pressedFlags[s][currentStep[s]] = true
 | 
						|
                            currentStep[s] = currentStep[s] + 1
 | 
						|
                            progress[s] = 0.0
 | 
						|
                        end
 | 
						|
                    else
 | 
						|
                        if boostPos and progress[s] >= boostPos + 0.02 and progress[s] <= boostPos + 0.12 then
 | 
						|
                            progress[s] = 1.0
 | 
						|
                            pressedFlags[s][currentStep[s]] = true
 | 
						|
                            currentStep[s] = currentStep[s] + 1
 | 
						|
                            progress[s] = 0.0
 | 
						|
                        else
 | 
						|
                            progress[s] = 0
 | 
						|
                        end
 | 
						|
                    end
 | 
						|
                end
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end
 | 
						|
 | 
						|
    local endDuration = 300
 | 
						|
    local endTime     = GetGameTimer() + endDuration
 | 
						|
    while GetGameTimer() < endTime do
 | 
						|
        Citizen.Wait(0)
 | 
						|
        DisablePlayerInput()
 | 
						|
        local alpha = math.max(0, (endTime - GetGameTimer()) / endDuration)
 | 
						|
 | 
						|
        DrawMultiMinigameBoxes(multiSequences, currentStep, progress, pressedFlags, coords, label, infoText, alpha)
 | 
						|
    end
 | 
						|
 | 
						|
    return true
 | 
						|
end
 |