Bar Activities
Bar Activities
Overview
The Bar Activities script offers a multiplayer darts experience for FiveM, allowing players to engage in various game modes such as 301, 501, and Around the Clock. It features placeable dart boards, server-side scoring, and a persistent leaderboard that tracks player performance. Additionally, the script includes admin tools for managing dart boards and customizable interaction options for players.
Compatibility
Framework: ESX, QBCore, QBox, Standalone
Target: ox_target, qb-target, or qtarget (optional) — falls back to 3D text / TextUI if none are installed
Dependencies
Required Dependencies
- ox_lib
Optional Dependencies
- oxmysql
- mysql-async
- ox_inventory
- qb-inventory
- qs-inventory
- ox_target or qb-target or qtarget
- es_extended or qb-core
Installation
1. Upload the resource
Place the resource folder inside your server's resources directory (rename it to drc_baractivities if needed).
2. Install dependencies
Make sure all of the following are installed and started before this script:
ox_lib
3. Import database
This script uses a database. Import the included drc_baractivities/install/drc_darts.sql — or run the following SQL directly:
CREATE TABLE IF NOT EXISTS `drc_darts_boards` (
`id` varchar(64) NOT NULL,
`data` longtext NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `drc_darts_leaderboard` (
`identifier` varchar(80) NOT NULL,
`name` varchar(80) NOT NULL,
`wins` int NOT NULL DEFAULT 0,
`losses` int NOT NULL DEFAULT 0,
`matches` int NOT NULL DEFAULT 0,
`throws` int NOT NULL DEFAULT 0,
`total_score` int NOT NULL DEFAULT 0,
`highest_throw` int NOT NULL DEFAULT 0,
`highest_match_score` int NOT NULL DEFAULT 0,
`bullseyes` int NOT NULL DEFAULT 0,
`player_hits` int NOT NULL DEFAULT 0,
`last_played` int NOT NULL DEFAULT 0,
PRIMARY KEY (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `drc_darts_armwrestling` (
`id` varchar(64) NOT NULL,
`data` longtext NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4. Add to server.cfg
ensure ox_lib
ensure drc_baractivities
5. Configure the script
Open the config file and adjust the settings for your server. See the Config section below.
6. Restart and test
Restart your server (or start the resource) and test it in-game to confirm it loads without errors.
Config
drc_baractivities/shared/config.lua
Config = {}
Config.Debug = false
Config.Locale = 'en'
Config.Framework = 'auto-detect' -- Framework: 'auto-detect', 'standalone', 'ESX', 'qbcore'
Config.InteractionType = 'auto-detect' -- InteractionType: 'auto-detect', 'ox_target', 'qb-target', 'qtarget', 'textui', '3dtext'
-- Target settings used when InteractionType resolves to a target resource.
Config.FrameworkTarget = 'auto-detect'
Config.Target = {
Enabled = true,
Icon = 'fa-solid fa-bullseye',
Label = 'Play Darts',
AdminIcon = 'fa-solid fa-pen-to-square',
AdminLabel = 'Manage Darts',
Distance = 2.0
}
Config.Menu = {
Type = 'nui', -- nui | ox_lib | qbcore | custom
Align = 'right'
}
-- Text UI provider: 'ox_lib', 'qbcore', 'custom', 'none'
Config.TextUI = {
Type = 'ox_lib',
Position = 'left-center',
Icon = 'bullseye'
}
Config.Text3D = {
Scale = 0.36,
Background = true,
BackgroundColour = { r = 0, g = 0, b = 0, a = 115 },
TextColour = { r = 255, g = 255, b = 255, a = 235 },
DartsOffsetZ = 0.65,
BilliardsOffsetZ = 1.05,
BilliardsRackOffsetZ = 0.85,
ArmWrestlingOffsetZ = 0.9
}
Config.NotificationType = 'ox_lib' -- Notifications: 'ox_lib', 'ESX', 'qbcore', 'custom'
-- Inventory used for dartboard items: 'auto-detect', 'ox_inventory', 'qb-inventory', 'qs-inventory', 'core_inventory', 'custom', 'none'
Config.Inventory = {
Type = 'auto-detect',
CheckItems = true
}
-- Storage: 'json', 'oxmysql', 'mysql-async'
Config.Storage = {
Type = 'json',
JsonFile = 'data/boards.json',
Table = 'drc_darts_boards',
Autosave = true
}
-- Creator and admin permissions.
Config.Permissions = {
CreatorAce = 'drc_darts.creator',
AdminAce = 'drc_darts.admin',
Groups = { 'admin', 'superadmin' },
Jobs = {
-- ['police'] = 3
}
}
-- Commands available to admins/creators.
Config.Commands = {
Create = 'createdarts',
Edit = 'editdarts',
Delete = 'deletedarts',
Leave = 'leavedarts'
}
-- Optional map blips for saved boards.
Config.Blips = {
Enabled = false,
ShowCreatorBoards = true,
ShowItemBoards = false,
Text = 'Darts',
Sprite = 103,
Colour = 3,
Scale = 0.7
}
-- Marker shown at the throwing position during a turn.
Config.Markers = {
Throw = {
Enabled = true,
Type = 1,
Distance = 0.85,
Scale = 0.55,
ZOffset = 1.0,
Colour = { r = 0, g = 212, b = 255, a = 155 }
}
}
-- Input controls. Control IDs are FiveM/GTA control indexes.
Config.Controls = {
Throw = 24,
Cancel = 177,
Help = 74,
ConfirmPlacement = 191,
CancelPlacement = 177,
Keyboard = {
Up = 172,
Down = 173,
Left = 174,
Right = 175
},
DisableDuringThrow = { 1, 2, 21, 22, 24, 25, 30, 31, 32, 33, 34, 35, 44, 45, 68, 69, 70, 71, 72, 75, 140, 141, 142, 143, 172, 173, 174, 175, 257, 263, 264 }
}
-- Animation dictionaries and clip names used by the protected gameplay code.
Config.Animations = {
Prep = { Dict = 'mini@darts', Name = 'enter_throw_c', Flag = 50, Duration = 1450 },
Idle = { Dict = 'anim@amb@clubhouse@mini@darts@', Name = 'throw_idle_a_up', Flag = 49 },
Throw = { Dict = 'anim@amb@clubhouse@mini@darts@', Name = 'throw_overlay', Flag = 48, Duration = 900 },
RetrieveNeutral = { Dict = 'anim@amb@clubhouse@mini@darts@', Name = 'retrieve_neutral', Flag = 48, Duration = 2200 },
RetrieveWin = { Dict = 'anim@amb@clubhouse@mini@darts@', Name = 'retrieve_win_a', Flag = 48, Duration = 2500 },
Bad = { Dict = 'mini@dartsoutro', Name = 'darts_outro_01_guy2', Flag = 48, Duration = 2500 },
Win = { Dict = 'mini@dartsoutro', Name = 'darts_outro_03_guy2', Flag = 48, Duration = 3000 }
}
-- Prop models and usable items.
Config.Props = {
Boards = {
{ Label = 'Classic Board', Model = 'prop_dart_bd_01', Item = 'dartboard_1' },
{ Label = 'Cabinet Board', Model = 'prop_dart_bd_cab_01', Item = 'dartboard_2' }
},
ArmWrestling = {
{ Label = 'Arm Wrestling Table', Model = 'prop_arm_wrestle_01' },
{ Label = 'Clubhouse Arm Wrestling Table 01', Model = 'bkr_prop_clubhouse_arm_wrestle_01a' },
{ Label = 'Clubhouse Arm Wrestling Table 02', Model = 'bkr_prop_clubhouse_arm_wrestle_02a' }
},
Billiards = {
Tables = {
{ Label = 'Pool Table', Model = 'prop_pooltable_02' },
{ Label = 'Pool Table 3B', Model = 'prop_pooltable_3b' }
},
AtenaTables = {
{ Label = 'Atena Pool Table 1', Model = 'ate_pooltable_1' },
{ Label = 'Atena Pool Table 2', Model = 'ate_pooltable_2' },
{ Label = 'Atena Pool Table 3', Model = 'ate_pooltable_3' },
{ Label = 'Atena Pool Table 4', Model = 'ate_pooltable_4' }
},
Cue = 'prop_pool_cue',
Racks = {
'prop_pool_rack_01',
'prop_pool_rack_02'
},
CueBall = 'prop_poolball_cue',
Balls = {
'prop_poolball_1',
'prop_poolball_2',
'prop_poolball_3',
'prop_poolball_4',
'prop_poolball_5',
'prop_poolball_6',
'prop_poolball_7',
'prop_poolball_8',
'prop_poolball_9',
'prop_poolball_10',
'prop_poolball_11',
'prop_poolball_12',
'prop_poolball_13',
'prop_poolball_14',
'prop_poolball_15'
}
},
Darts = {
Hand = 'prop_dart_1',
Flying = 'prop_dart_1',
Stuck = 'prop_dart_2',
FlightPitch = 88.0,
StartFromHand = true,
StartBackOffset = 0.75,
StartUpOffset = 0.05,
RotationOffset = vector3(0.0, 0.0, 0.0)
}
}
Config.Items = {
Enabled = true,
RemoveOnPlace = true,
List = {
dartboard_1 = { Label = 'Classic Dart Board', Model = 'prop_dart_bd_01' },
dartboard_2 = { Label = 'Cabinet Dart Board', Model = 'prop_dart_bd_cab_01' }
}
}
-- Board creator settings.
Config.Creator = {
DefaultDistance = 2.0,
DefaultThrowDistance = 2.65,
WallRayDistance = 7.0,
WallSurfaceOffset = 0.035,
WallHeadingOffset = 180.0,
ExistingPropSearchRadius = 1.0,
ThrowZOffset = 0.05,
PlacementStep = 0.035,
RotationStep = 2.0,
HeightStep = 0.025,
TestPed = true,
MaxBoards = 200,
OffsetTuning = {
Enabled = true,
WallMin = -0.10,
WallMax = 0.25,
CenterMin = -0.20,
CenterMax = 0.20,
RadiusMin = 0.18,
RadiusMax = 0.40,
Step = 0.005
}
}
-- Arm wrestling tables created through the same creator UI.
Config.ArmWrestling = {
Enabled = true,
JsonFile = 'data/armwrestling.json',
Table = 'drc_darts_armwrestling',
DefaultDistance = 2.0,
AnimDictTimeoutMs = 10000,
MaxTables = 200,
Blips = {
Enabled = true,
Text = 'Arm Wrestling',
Sprite = 311,
Colour = 5,
Scale = 0.7
}
}
Config.DartsDui = {
Enabled = true,
Model = 'prop_dart_bd_cab_01',
Width = 0.3920,
Height = 0.7360,
DuiWidth = 1400,
DuiHeight = 1100,
UpdateMs = 180,
DebugFrame = false,
AutoUseModel = true,
SpectatorDistance = 25.0,
SpectatorBroadcastMs = 2500,
Blank = {
Model = 'drc_baractivities_board_01',
Models = {
{ Label = 'Bar Scoreboard Small', Model = 'drc_baractivities_board_01' },
{ Label = 'Bar Scoreboard Large', Model = 'drc_baractivities_board_02' }
},
Width = 1.05,
Height = 0.72,
RightOffset = 0.0,
NormalOffset = -0.025,
UpOffset = 0.0,
Yaw = 0.0,
Roll = 0.0,
ModelSettings = {
drc_baractivities_board_01 = {
Width = 1.3080,
Height = 0.7740,
RightOffset = -0.0120,
NormalOffset = -0.0040,
UpOffset = -0.0030,
Yaw = 90.00,
Roll = 0.0
},
drc_baractivities_board_02 = {
Width = 1.7100,
Height = 1.1340,
RightOffset = -0.0060,
NormalOffset = 0.0140,
UpOffset = 0.0030,
Yaw = 90.00,
Roll = 0.0
}
}
},
Panels = {
Left = {
RightOffset = -0.5320,
NormalOffset = -0.2620,
UpOffset = 0.0050,
Yaw = 29.75,
Roll = 0.0
},
Right = {
RightOffset = 0.5230,
NormalOffset = -0.2590,
UpOffset = 0.0020,
Yaw = 330.00,
Roll = 359.50
}
}
}
-- Billiards tables created through the creator UI.
Config.Billiards = {
Enabled = true,
UsingAtenaPool = true,
JsonFile = 'data/billiards.json',
Table = 'drc_darts_billiards',
DefaultDistance = 2.0,
MaxPlayerDistance = 10.0,
MaxTables = 200,
MaxPlayers = 2,
PowerMin = 0.15,
PowerMax = 1.0,
BallZOffset = 0.933,
BallRadius = 0.065,
CollisionRadius = 0.047,
TableLength = 2.706,
TableWidth = 1.526,
TableOffset = { x = 0.130, y = 0.078, z = 0.0 },
TableRotation = 89.85,
PocketRadius = 0.105,
RailBounds = { MinX = -1.3505, MaxX = 1.3545, MinY = -0.7725, MaxY = 0.7655 },
Pockets = {
{ name = 'bottom_left', x = -1.3595, y = -0.7735, r = 0.1030 },
{ name = 'bottom_middle', x = 0.0000, y = -0.8025, r = 0.1050 },
{ name = 'bottom_right', x = 1.3555, y = -0.7695, r = 0.1050 },
{ name = 'top_left', x = -1.3645, y = 0.7835, r = 0.1050 },
{ name = 'top_middle', x = 0.0000, y = 0.8025, r = 0.1050 },
{ name = 'top_right', x = 1.3475, y = 0.7925, r = 0.1050 }
},
RuntimeProps = {
Enabled = true,
RackLinkDistance = 5.0
},
BallLayout = {
Rotation = 357.42,
Cue = { x = -0.679, y = -0.016 },
Balls = {
{ id = 1, x = 0.4, y = 0.002 },
{ id = 2, x = 0.475, y = -0.036 },
{ id = 3, x = 0.541, y = 0.087 },
{ id = 4, x = 0.674, y = 0.093 },
{ id = 5, x = 0.608, y = 0.052 },
{ id = 6, x = 0.60, y = 0.14 },
{ id = 7, x = 0.690, y = -0.145 },
{ id = 8, x = 0.543, y = 0.007 },
{ id = 9, x = 0.613, y = -0.029 },
{ id = 10, x = 0.471, y = 0.044 },
{ id = 11, x = 0.545, y = -0.074 },
{ id = 12, x = 0.620, y = -0.107 },
{ id = 13, x = 0.687, y = -0.067 },
{ id = 14, x = 0.676, y = 0.014 },
{ id = 15, x = 0.666, y = 0.169 }
}
},
ModelSettings = {
prop_pooltable_3b = {
BallZOffset = 0.925,
BallRadius = 0.065,
CollisionRadius = 0.047,
TableLength = 2.635,
TableWidth = 1.498,
TableOffset = { x = 0.004, y = 0.001, z = 0.0 },
TableRotation = 90.27,
PocketRadius = 0.105
},
ate_pooltable_1 = {
BallZOffset = 0.2800,
BallRadius = 0.065,
CollisionRadius = 0.047,
TableLength = 1.904,
TableWidth = 1.047,
TableOffset = { x = 0.004, y = 0.017, z = 0.0 },
TableRotation = 0.45,
PocketRadius = 0.105
},
ate_pooltable_2 = {
BallZOffset = 0.2800,
BallRadius = 0.065,
CollisionRadius = 0.047,
TableLength = 2.855,
TableWidth = 1.452,
TableOffset = { x = -0.002, y = -0.015, z = 0.0 },
TableRotation = 359.55,
PocketRadius = 0.105
},
ate_pooltable_3 = {
BallZOffset = 0.2270,
BallRadius = 0.065,
CollisionRadius = 0.047,
TableLength = 2.661,
TableWidth = 1.365,
TableOffset = { x = -0.013, y = -0.006, z = 0.0 },
TableRotation = 0.03,
PocketRadius = 0.105
},
ate_pooltable_4 = {
BallZOffset = 0.1860,
BallRadius = 0.065,
CollisionRadius = 0.047,
TableLength = 2.811,
TableWidth = 1.431,
TableOffset = { x = 0.006, y = 0.001, z = 0.0 },
TableRotation = 0.15,
PocketRadius = 0.105
}
},
SpectatorDui = {
Enabled = true,
DrawDistance = 7.0
},
Sounds = {
Enabled = true
},
Modes = {
casual = {
Label = 'Casual Pool',
Description = 'Simple alternating turns. No official 8-ball rules.',
Enabled = true
},
practice = {
Label = 'Practice',
Description = 'Solo practice on the selected table.',
Enabled = true
}
},
Blips = {
Enabled = true,
Text = 'Billiards',
Sprite = 614,
Colour = 25,
Scale = 0.7
}
}
-- Darts activities/modes.
Config.Activities = {
['301'] = {
Label = '301',
Description = 'Reach exactly zero before everyone else.',
StartScore = 301,
DoubleOut = false,
Enabled = true
},
['501'] = {
Label = '501',
Description = 'Long format, exact zero finish.',
StartScore = 501,
DoubleOut = false,
Enabled = true
},
around = {
Label = 'Around the Clock',
Description = 'Hit 1 through 20 in order.',
TargetMax = 20,
Enabled = true
},
highscore = {
Label = 'High Score',
Description = 'Highest score after fixed rounds wins.',
Rounds = 5,
Enabled = true
}
}
-- Core gameplay timing and safety distances.
Config.Gameplay = {
MaxPlayers = 4,
InviteDistance = 8.0,
InviteTimeout = 20000,
LobbyTimeout = 120000,
TurnTimeout = 45000,
ThrowsPerTurn = 3,
GoodTurnScore = 60,
ThrowReleaseDelay = 280,
AfterThrowCameraHold = 900,
RetrieveDartCleanupDelay = 900,
RetrieveAckTimeout = 9000,
RetrieveWalkToBoardDistance = 1.05,
MaxBoardDistance = 18.0,
ClearDartsAfterMatch = 120000,
TurnTransitionDelay = 1250,
EndIfHostLeaves = true,
TransferHostOnLeave = false
}
-- Money and item rewards are validated server-side only.
Config.Rewards = {
Enabled = false,
Account = 'money',
Winner = { Min = 0, Max = 0 },
Participation = { Min = 0, Max = 0 },
Items = {
-- { Name = 'trophy', Amount = 1, WinnerOnly = true }
}
}
Config.Betting = {
Enabled = true,
Account = 'money',
Min = 0,
Max = 10000,
Step = 100,
Default = 0,
RefundOnNoWinner = true
}
-- Server anti-spam and cooldowns.
Config.Cooldowns = {
ServerEventMs = 450,
ThrowMs = 650,
SaveBoardMs = 2000,
InviteMs = 1500,
SuspiciousLogMs = 5000
}
-- Funny player-hit mechanic. Damage is disabled by default.
Config.PlayerHit = {
Enabled = true,
RagdollDuration = 3000,
AttachDartToPlayer = true,
DartRemoveTime = 10000,
HitDetectionRadius = 0.65,
AllowHitMatchPlayers = true,
AllowHitSpectators = true,
CountAsThrow = true,
ScoreOnPlayerHit = 0,
DamageEnabled = false,
DamageAmount = 0
}
-- Persistent leaderboard.
Config.Leaderboard = {
Enabled = true,
Command = 'dartsleaderboard',
MaxEntries = 50,
MinimumMatchesForWinRate = 5,
UseCharacterName = true,
ResetCommand = 'resetdartsleaderboard',
ResetPermission = 'admin',
JsonFile = 'data/leaderboard.json',
Table = 'drc_darts_leaderboard'
}
-- Webhook logging. Leave URL empty to disable.
Config.Webhooks = {
Enabled = false,
Url = '',
Name = 'DRC Darts',
Color = 3447003,
SuspiciousColor = 15158332
}
-- Board scoring geometry.
Config.Board = {
VisualRadius = 0.225,
SurfaceOffset = 0.04,
SurfaceDepth = 0.12,
BullseyeRadius = 0.075,
BullRadius = 0.155,
TripleInner = 0.515,
TripleOuter = 0.595,
DoubleInner = 0.900,
DoubleOuter = 1.000,
SegmentOrder = { 20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5 },
ModelProfiles = {
prop_dart_bd_01 = {
Radius = 0.225,
CenterOffset = vector3(0.0, 0.0, 0.0),
SurfaceOffset = 0.04
},
prop_dart_bd_cab_01 = {
Radius = 0.225,
CenterOffset = vector3(0.0, 0.0, 0.0),
SurfaceOffset = 0.04
}
}
}
-- Throw aiming difficulty.
Config.Aiming = {
Sensitivity = 0.006,
KeyboardStep = 0.008,
Sway = 0.095,
SwaySpeed = 6.0,
HoldToStabilize = true,
StabilizeSeconds = 1.2,
MaxStabilize = 0.30,
ReleaseRequired = true,
RandomInaccuracy = 0.0,
DefaultDifficulty = 'normal',
MaxAimRadius = 1.25,
Difficulty = {
easy = { Sway = 0.050, Random = 0.0 },
normal = { Sway = 0.095, Random = 0.0 },
hard = { Sway = 0.140, Random = 0.0 }
}
}
-- Camera used while throwing.
Config.Camera = {
TransitionMs = 550,
Offset = vector3(0.72, -1.05, 0.32),
PlayerHeight = 1.45,
BaseBone = 24818,
BoneZOffset = 0.32,
Fov = 42.0,
TargetOffset = vector3(0.0, 0.0, 0.02)
}
-- NUI colors and sounds.
Config.UI = {
Primary = '#00d4ff',
Accent = '#f2c94c',
Sound = true
}