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
 | 
