Mobius1 / rprogress

Customisable radial progress bars for FiveM
GNU General Public License v3.0
68 stars 40 forks source link
fivem fivem-roleplay fivem-script progressbar

rprogress

Customisable radial progress bars for FiveM.

Table of contents

Demo Videos

Requirements

Download & Installation

Configuration

Config.Async        = true  -- Whether to run the progress dial asyncronously

Config.From         = 0     -- Starting progress percentage
Config.To           = 100   -- Ending progress percentage

Config.Duration         = 5000          -- Duration of the progress
Config.Label            = "Loading..."  -- Text shown with the dial
Config.LabelPosition    = "bottom"

Config.Color        = "rgba(255, 255, 255, 1.0)"    -- Progress dial colour
Config.BGColor      = "rgba(0, 0, 0, 0.4)"          -- Progress background colour
Config.ZoneColor    = "rgba(51, 105, 30, 1)"        -- Minigame Zone colour

Config.x            = 0.5 -- Horizontal position
Config.y            = 0.5 -- Vertical position

Config.Rotation     = 0         -- Rotation angle of dial
Config.MaxAngle     = 360       -- Max arc in degrees - 360 will be a full circle, 90 will be a quarter of a circle, etc
Config.Radius       = 60        -- Radius of the radial dial
Config.Stroke       = 10        -- stroke width of the radial dial
Config.Width        = 300       -- Width of the linear bar
Config.Height       = 40        -- Height of the linear bar
Config.Cap          = 'butt'    -- or 'round'
Config.Padding      = 0         -- Background bar padding
Config.CancelKey    = 178       -- Key used for cancelling progress

Config.ShowTimer    = true  -- Shows the timer countdown within the radial dial
Config.ShowProgress = false -- Shows the progress within the radial dial

Config.Easing       = "easeLinear" -- The easing used for the dial animation - see "rprogress/ui/js/easings.js"

Config.DisableControls = {
    Mouse           = false,    -- Disable mouse controls until progress is complete
    Player          = false,    -- Disable player movement until progress is complete
    Vehicle         = false     -- Disable vehicle control until progress is complete    
}

NOTE: Config.Position is based on screen size so setting Config.Position.x = 0.5 will be the center of the screen, Config.Position.x = 1.0 with be right-side of the screen, Config.Position.x = 0.0 will be the left-side of the screen, etc.

Upgrading

Upgrading to v0.6.0

Replace all instances of exports.rprogress:NewStaticProgress with exports.rprogress:Static

Client Functions

NOTE: DO NOT run these in a loop

Available exports:

-- starts the progress dial for the defined duration
-- This runs in sync so any code after this call won't be run until the progress is complete
exports.rprogress:Start(text, duration)

-- stops the progress dial early
exports.rprogress:Stop()

-- Display a custom progress dial by overriding config.lua values
exports.rprogress:Custom(options)

-- Create a static progress dial
exports.rprogress:Static(options)

-- Create a linear progress bar
exports.rprogress:Linear(text, duration)

-- or

exports.rprogress:Custom({
    Type = 'linear'
    Duration = 3000,
    Width = 400,
    Height = 50,
    y = 0.75
})
Display a progress dial with text for set duration
exports.rprogress:Start(text, duration)
Stop the progress dial early
exports.rprogress:Stop()
Create a custom progress instance
exports.rprogress:Custom({
    Async = true,
    canCancel = true,       -- Allow cancelling
    cancelKey = 178,        -- Custom cancel key
    x = 0.5,                -- Position on x-axis
    y = 0.5,                -- Position on y-axis
    From = 0,               -- Percentage to start from
    To = 100,               -- Percentage to end
    Duration = 1000,        -- Duration of the progress
    Radius = 60,            -- Radius of the dial
    Stroke = 10,            -- Thickness of the progress dial
    Cap = 'butt',           -- or 'round'
    Padding = 0,            -- Padding between the progress dial and the background dial
    MaxAngle = 360,         -- Maximum sweep angle of the dial in degrees
    Rotation = 0,           -- 2D rotation of the dial in degrees
    Width = 300,            -- Width of bar in px if Type = 'linear'
    Height = 40,            -- Height of bar in px if Type = 'linear'
    ShowTimer = true,       -- Shows the timer countdown within the radial dial
    ShowProgress = false,   -- Shows the progress % within the radial dial    
    Easing = "easeLinear",
    Label = "My Custom Label",
    LabelPosition = "right",
    Color = "rgba(255, 255, 255, 1.0)",
    BGColor = "rgba(0, 0, 0, 0.4)",
    ZoneColor = "rgba(51, 105, 30, 1)",
    Animation = {
        scenario = "WORLD_HUMAN_AA_SMOKE", -- https://pastebin.com/6mrYTdQv
        animationDictionary = "missheistfbisetup1", -- https://alexguirre.github.io/animations-list/
        animationName = "unlock_loop_janitor",
    },
    DisableControls = {
        Mouse = true,
        Player = true,
        Vehicle = true
    },    
    onStart = function()
        -- do something when progress starts
    end,
    onComplete = function(cancelled)
        -- cancelled: boolean - whether player cancelled the progress

        -- do something when progress is complete
    end
})

Scenarios and Animations

rprogress allows you to run a scenario or play an animation while the progress dial is running.

If you want to run a scenario, then provide the Animation table with the scenario key.

exports.rprogress:Custom({
    Animation = {
        scenario = "WORLD_HUMAN_AA_SMOKE"
    }
}) 

You can find a list of scenarios here

If you want to play an animation, then provide the Animation table with the required animationDictionary and animationName keys. You can also provide the optional flag key (see TaskPlayAnim).

exports.rprogress:Custom({
    Animation = {
        animationDictionary = "missheistfbisetup1",
        animationName = "unlock_loop_janitor",
        flag = 1, -- optional
    }
}) 

You can find a list of animation dictionaries / names here.

If scenario is set as well as animationDictionary and animationName, then the scenario will take priority.

MiniGame

rProgress can be set up to allow a minigame to test player reflexes by utilising the MiniGame() method.

The progress bar will flip back and forth and display a trigger zone for the player to hit the SpaceBar when the progress bar is within it.

As with the Custom() method, you can pass a variety of options. The onComplete callback will return the success parameter to indicate whether the player was successful or not.

exports.rprogress:MiniGame({
    Difficulty = "Easy",
    Timeout = 5000, -- Duration before minigame is cancelled
    onComplete = function(success)
            if success then
                -- Player was successful
            else
                -- Player was unsuccessful
            end    
    end,
    onTimeout = function()
        -- Player took too long to respond
    end
})

You can define the defficulties in the config.lua file:

Config.MiniGameOptions = {
    MaxAngle = 240,
    Rotation = -120,    
    Difficulty = {
        Easy = {
            Zone = 40,
            Duration = 500
        },
        Medium = {
            Zone = 25,
            Duration = 450
        },
        Hard = {
            Zone = 20,
            Duration = 400
        }      
    }      
}

To add you own difficulty you can define it in the Config.MiniGameOptions.Difficulty table and add the Zone and Duration values:

Config.MiniGameOptions = {
    MaxAngle = 240,
    Rotation = -120,    
    Difficulty = {
        Custom = {
            Zone = 40,         -- The percentage of the dial that is the trigger zone (lower = harder)
            Duration = 1000    -- Time in milliseconds for the dial to fill in one direction (lower = harder)
        }
    }
}

Then use it in the MiniGame() method:

exports.rprogress:MiniGame({
    Difficulty = "Custom",
    onComplete = function(success)

    end
})

You can also pass the Zone and Duration values instead of Difficulty for on-the-fly difficulty settings:

exports.rprogress:MiniGame({
    Zone = 40,
    Duration = 750,
    onComplete = function(success)

    end
})

Sync vs Async

The Start() method runs in sync so any code after the call to the method won't be run until the progress is complete. If you want a progress dial to run asyncronously, you can use the Custom() method with Async set to true and utilise the onStart and onComplete callbacks.

Async
print("before")

exports.rprogress:Custom({
    Async = true,
    Duration = 3000,
    onStart = function()
        print("start")
    end      
    onComplete = function()
        print("complete")
    end    
})

print("after")
Output
before
after
start
complete
Sync
print("before")

exports.rprogress:Custom({
    Async = false,
    Duration = 3000,
    onStart = function()
        print("start")
    end      
    onComplete = function()
        print("complete")
    end     
})

print("after")
Output
before
start
complete
after

Static Progress Dials

If you don't just want a progress dial that fills automatically, you can create a static one and update it as required.

Demo Video

-- Create new static progress dial
local staticDial = exports.rprogress:Static(options)

-- Show the progress dial
staticDial.Show()

-- Update the progress of the dial (0-100)
staticDial.SetProgress(progress)

-- Hide the progress dial
staticDial.Hide()

-- Destroy the dial (set as no longer needed)
staticDial.Destroy()

Partial Progress Dials

To create a partial progress dial set the maxAngle property to the desired value:

exports.rprogress:Custom({
    maxAngle: 240
})

Result

You can also set rotation property to the desired value:

exports.rprogress:Custom({
    maxAngle: 240,
    rotation: -120
})

Result

Pie Progress

Setting the radius and stroke properties to equal values will produce a pie chart type progress:

exports.rprogress:Custom({
    Radius: 60,
    Stroke: 60
})

Result

Demo Commands

/rprogressStart [text] [duration]
/rprogressCustom [from] [to] [duration] [radius] [stroke] [MaxAngle] [rotation] [padding] [cap]
/rprogressMiniGame [difficulty]
/rprogressSync [duration]
/rprogressAsync [duration]
/rprogressStatic
/rprogressEasing [functionName] [duration]
/rprogressAnimation [animDictionary] [animName] [duration]
/rprogressScenario [scenarioName] [duration]

You can delete the demo.lua file and remove it's entry from fxmanifest.lua if these are not required.

Contributing

Pull requests welcome.

Legal

License

rprogress - Customisable radial progress dials for FiveM.

Copyright (C) 2020 Karl Saunders

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>