20 Commits

Author SHA1 Message Date
Jim Shield
762240b500 Version Bump
`2.0.07` - `2.0.08`
2025-10-06 02:29:07 +01:00
Jim Shield
0a0f60468a Rework calculations and fix alcohol/drug effects
This fixes calculation errors and implements support for jim_bridge built in synchronized alcohol/drug effects

Separates "drug control" `canOD` variable too
2025-10-06 02:28:03 +01:00
Jim Shield
9b189d89f5 fix needStats calculcation
My mad on this one, got `needTypes` and `needStats` confused, so made it just one table and included stress in it
2025-10-04 01:12:19 +01:00
Jim Shield
62db9f6900 Version Bump
`2.0.06` - `2.0.07`
2025-10-01 21:44:20 +01:00
Jim Shield
6317dee667 Stop double calculation of hunger and thirst
Missed this, it's doing the player stats + new stats and then in jim_bridge doing this again and doubling it all up
2025-10-01 21:43:14 +01:00
Jim Shield
15bb54c206 Add support for jim_bridge setStress function
Allows multiframework stress events
2025-10-01 01:20:33 +01:00
Jim Shield
94023857ff Release Notifier Push 2025-09-24 18:18:14 +01:00
Jim Shield
daa70a8844 Version Bump
`2.0.05` - `2.0.06`
2025-09-15 16:31:34 +01:00
Jim Shield
25e8d99839 Rework code to server side
In an attempt to tackle exploiters, I reworked a lot of the code to server side

This will be tied to the new `jim_bridge` release but should function as normal now
2025-09-13 02:54:36 +01:00
Jim Shield
2c2a486a41 Update notify-discord.yml 2025-09-04 16:59:41 +01:00
Jim Shield
16e957116e Create release.yml
Automate release zips and make them generate the folder name correctly

This helps users download a correctly named script so they dont end up with a script with a version number in the title
2025-09-01 10:22:10 +01:00
Jim Shield
b4d65ff043 Update notify-discord.yml 2025-07-27 18:48:05 +01:00
Jim Shield
9d866c88ee Update README.md 2025-07-25 00:41:11 +01:00
Jim Shield
018dcca6cc Update README.md 2025-07-24 22:51:21 +01:00
Jim Shield
e27b840a5e Try to fix props now spawning correctly
Not sure what is going on, they are server synced
but Its possible its not loading the correctly because of the spawn location

I've changed it to make the props at the players location in hopes this fixes the issue
2025-07-08 15:02:28 +01:00
Jim Shield
e794d9a446 Version Bump
`2.0.04` - `2.0.05`
2025-06-22 16:37:46 +01:00
Jim Shield
541263b156 Fixes related to progressbars 2025-06-22 16:13:18 +01:00
Jim Shield
60c42b2506 Fix hunger being wrong on esx when consuming 2025-06-20 21:54:14 +01:00
Jim Shield
2a4de6fdc1 Version Bump
`2.0.03` - `2.0.04`
2025-06-16 11:19:07 +01:00
Jim Shield
4b015e5efa Revamp hunger and thirst events
Realised I made a mistake, and the server function wasn't working fully on ESX

moved it to use the jim_bridge `setNeed` trigger and made the function smarter
2025-06-14 22:29:40 +01:00
12 changed files with 428 additions and 279 deletions

12
.gitattributes vendored Normal file
View File

@@ -0,0 +1,12 @@
# VCS / CI noise
.gitattributes export-ignore
.gitignore export-ignore
.github/** export-ignore
.gitmodules export-ignore
# Dev tooling/config
.vscode/** export-ignore
*.code-workspace export-ignore
.editorconfig export-ignore
.eslintrc* export-ignore
.prettier* export-ignore

View File

@@ -3,15 +3,16 @@ name: Discord Commit Notifier
on:
push:
branches:
- '*' # triggers on all branches
- '*'
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Discord Commits
uses: Sniddl/discord-commits@v1.6
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
template: "avatar-with-link"
include-extras: true
- name: Send commit payload to Discord Bot
env:
URL: http://${{ secrets.DISCORDBOT }}:3000/github-commits
run: |
curl -sS -X POST "$URL" \
-H 'Content-Type: application/json' \
--data-binary "@$GITHUB_EVENT_PATH"

71
.github/workflows/notify-release.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: Discord Release Notifier
on:
# Manual or UI-published releases
release:
types: [published]
# Releases created by your tag-driven workflow
workflow_run:
workflows: ["Package & Release"] # must match the 'name:' in release.yml
types: [completed]
permissions:
contents: read
jobs:
# 1) Handle manual / UI / non-workflow-created releases
notify-from-release:
if: github.event_name == 'release' && github.event.action == 'published'
runs-on: ubuntu-latest
steps:
- name: Send release payload to Discord Bot
env:
URL: http://${{ secrets.DISCORDBOT }}:3000/github-releases
run: |
curl -sS -X POST "$URL" \
-H 'Content-Type: application/json' \
--data-binary "@$GITHUB_EVENT_PATH"
# 2) Handle releases created by your 'Package & Release' workflow
# (which wont trigger `on: release` when using GITHUB_TOKEN)
notify-from-workflow-run:
if: >
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- name: Fetch release JSON by tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
OWNER="${GITHUB_REPOSITORY%/*}"
REPO="${GITHUB_REPOSITORY#*/}"
TAG="${{ github.event.workflow_run.head_branch }}"
# head_branch is the tag name for a tag push workflow_run
curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$OWNER/$REPO/releases/tags/$TAG" \
> release.json
- name: Wrap as 'release' event payload & notify bot
env:
URL: http://${{ secrets.DISCORDBOT }}:3000/github-releases
run: |
set -euo pipefail
jq -n --slurpfile rel release.json \
--arg repo "$GITHUB_REPOSITORY" \
--arg repo_url "https://github.com/$GITHUB_REPOSITORY" \
--arg action "published" '
{ action: $action,
repository: { full_name: $repo, html_url: $repo_url },
release: $rel[0],
sender: { login: "github-actions[bot]" } }' > payload.json
curl -sS -X POST "$URL" \
-H 'Content-Type: application/json' \
--data-binary "@payload.json"

88
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,88 @@
name: Package & Release
on:
push:
tags:
- "v*"
- "*.*.*"
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout (full history)
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Derive vars
id: vars
shell: bash
run: |
echo "name=${GITHUB_REPOSITORY##*/}" >> $GITHUB_OUTPUT # e.g. jim_bridge
echo "version=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT # strip leading v
- name: Build zip with folder prefix
shell: bash
run: |
NAME='${{ steps.vars.outputs.name }}'
VER='${{ steps.vars.outputs.version }}'
git archive --format=zip --prefix="${NAME}/" -o "${NAME}-${VER}.zip" "$GITHUB_REF_NAME"
ls -lh "${NAME}-${VER}.zip"
# --- Patch notes generation (commit titles + links) -------------------
- name: Find previous tag (SemVer aware)
id: prev
shell: bash
run: |
CUR="${GITHUB_REF_NAME}"
# Sort tags by version desc, drop the current, take the next newest
PREV=$(git tag --sort=-v:refname | grep -v -x "$CUR" | head -n 1 || true)
echo "prev=$PREV" >> $GITHUB_OUTPUT
echo "Previous tag: ${PREV:-<none>}"
- name: Generate RELEASE_NOTES.md from commits
shell: bash
run: |
REPO="${{ github.repository }}"
CUR="${GITHUB_REF_NAME}"
PREV='${{ steps.prev.outputs.prev }}'
if [ -n "$PREV" ]; then
RANGE="$PREV..$CUR"
HEADER="## Changes in $CUR"
else
# First release: include all commits
ROOT=$(git rev-list --max-parents=0 HEAD | tail -n 1)
RANGE="$ROOT..$CUR"
HEADER="## Changes"
fi
{
echo "$HEADER"
echo
# Oldest → newest, subject only, skip merge commits
# Escape '[' and ']' so markdown doesn't break on rare titles
git log --reverse --no-merges --pretty=format:'- ['%h'] - %s' "$RANGE" \
| perl -pe 's/([\[\]])/\\$1/g'
} > RELEASE_NOTES.md
echo "--- RELEASE_NOTES.md ---"
cat RELEASE_NOTES.md
echo "------------------------"
- name: Create / Update GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
files: |
*.zip
body_path: RELEASE_NOTES.md # attach our generated notes
# If you wanted GitHub's auto notes instead, set:
# generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

144
README.md
View File

@@ -1,5 +1,6 @@
# Jim-Consumables
Consumables script for QBCore
## FiveM MultiFrameork Consumables script
# What is this?
This script WAS designed as a replacement/override for food and drink consumables in `qb-smallresources`
@@ -12,140 +13,13 @@ Though if your players are cancelling all animations when consuming, it's recomm
# THIS DOESN'T USE DPEMOTES OR RPEMOTES OR SCULLYS EMOTEMENU
# Installation
---
- I always recommend starting my scripts **AFTER** `[qb]` not inside it as it can mess with any dependancies on server load
- I have a separate folder called `[jimextras]` (that is also in the resources folder) that starts before any scripts would use it.
- This ensure's it has everything it requires before trying to load
- Example of my load order:
```CSS
# QBCore & Extra stuff
ensure qb-core
ensure [qb]
ensure [standalone]
ensure [voice]
ensure [defaultmaps]
ensure [vehicles]
# Installation and Previews:
## [JixelPatterns GitBook Documentation](https://jixelpatterns.gitbook.io/docs)
# Extra Jim Stuff
ensure [jimextras]
ensure [jim]
```
### If you need support I have a discord server available, it helps me keep track of issues and give better support.
## [JixelPatterns Discord](https://discord.gg/9pCDHmjYwd)
## QB-SmallResources
- It should already take control of default qbcore food, drink and drugs.
- If it fails to do this and attempts to use qb-smallresources still you will need to:
- `[qb]` > `qb-smallresources` > `server` > `consumables.lua`
- Remove or comment out the `CreateUseableItem` events for *alcohol*, *eat*, *drink* and *drug* in this file
- Not all of them! (such as armour related items)
- This ***should*** stop `qb-smallresources` taking control and confusing `jim-consumables`
## New Items
To add an item, you only need to add a new item table in the Config.Consumables like this:
```lua
heartstopper = {
emote = "burger", -- Select an emote from below, it has to be in here
time = math.random(5000, 6000), -- Amount of time it takes to consume the item
stress = math.random(1,2), -- Amount of stress relief, can be 0
heal = 0, -- Set amount to heal by after consuming
armor = 5, -- Amount of armor to add
type = "food", -- Type: "alcohol" / "drink" / "food"
canRun = true, -- If true player can run while using the item, not to it will cancel the event
stats = {
screen = "thermal", -- The screen effect to be played when after consuming the item "rampage" "turbo" "focus" "weed" "trevor" "nightvision" "thermal"
effect = "heal", -- The status effect given by the item, "heal" / "stamina"
-- This supports ps-buffs effects "armor" "stress" "swimming" "hacking" "intelligence" "luck" "strength"
time = 10000, -- How long the effect should last (if not added it will default to 10000)
amount = 6, -- How much the value is changed by per second
hunger = math.random(10, 20), -- The hunger/thirst stats of the item, if not found in the items.lua
thirst = math.random(10, 20), -- The hunger/thirst stats of the item, if not found in the items.lua
canOD = true, -- This creates an OD Effect, killing the user if they have too much
},
--Reward Items Variables
-- These can be the only thing in a consumable table and the item will still work
amounttogive = 3, -- Used for "RewardItems", tells the script how many to give
rewards = {
[1] = {
item = "plastic", -- prize item name
max = 10, -- max amount to give (this is put into math.random(1, max) )
rarity = 1, -- the rarity system, 1 being rarest, 4 being most common
},
},
},
```
Consuming an item can also manually activate screen effects
The example above uses `rampage` as this is what the effect is named after, you can use it for any item you think best
```lua
--The current list of screen effects are:
"turbo"
"focus"
"rampage"
"weed"
"trevor"
"nightvision"
"thermal"
```
You can also now create "Box" items, when setting type to "pack", it will act as if you user is opening a box
Examples:
- Ammo boxes that give clips
- Packets of cigarretes
- Crates of beer
How to set up these:
```lua
-- Example Box Item
["9_box"] = { -- Name of the box item in the shared items
emote = "uncuff", -- The emote than should run when "unboxing"
canRun = true, -- If true player can run while using the item, not to it will cancel the event
time = 3500, -- How long it takes to use the item
type = "pack", -- Designate it as a "pack" to the script knows what to do
pack = {
item = "9_ammo", -- The item to give from the box when complete
amount = 20 -- How many of the item to give
},
},
```
## PS-Buffs Support
This scripts can be expanded with ps-buffs (https://github.com/Project-Sloth/ps-buffs)
If this script is enabled it will automatically try to use their system to apply buffs:
```lua
--The extra buffs that can be set include:
"heal" -- Health recovery buff
"stamina" -- Stamina recovery buff
"swimming" -- Swimming speed buff
"stress" -- Stress recovery buff
"armor" -- Armour recovery buff
"hacking" -- Hacking effect
"intelligence" -- Intelligence effect
"luck" -- Luck effect
"strength" -- Strength effect
```
This script supports dpemotes style emotes, so if you have some that you want to be triggered when eating or drinking drop it in the Config.Emotes section.
## Add consumables from external scripts
A small example of a server-sided snippet for this imports the item and the emote, then syncs it to players before and after they connect.
```lua
local foodTable = {
["shotfries"] = { emote = "bsfries", canRun = false, time = math.random(5000, 6000), stress = math.random(2, 4), heal = 0, armor = 0, type = "food", stats = { hunger = math.random(55,65), }},
}
local emoteTable = {
["bsfries"] = {"mp_player_inteat@burger", "mp_player_int_eat_burger_fp", "Fries", AnimationOptions = { Prop = "prop_food_bs_chips", PropBone = 18905, PropPlacement = {0.09, -0.06, 0.05, 300.0, 150.0}, EmoteMoving = true, EmoteLoop = true, }},
}
for k, v in pairs(foodTable) do TriggerEvent("jim-consumables:server:syncAddItem", k, v) end
for k, v in pairs(emoteTable) do TriggerEvent("jim-consumables:server:syncAddEmote", k, v) end
```
This will grab the `shotfries` item info and add it to the `Config.Consumables` while the servers running and the same with the built-in emote system
### If you think I did a good job here, consider donating as it keeps by lights on and my cat round:
## [JixelPatterns Kofi](https://ko-fi.com/jixelpatterns)

View File

@@ -38,6 +38,7 @@ AddStateBagChangeHandler("jimConsumableItems", nil, function(bagName, key, value
debugPrint("^5Statebag^7: ^2Synced ^6"..newItemCount.." ^2new Consumables^7")
end
end)
AddStateBagChangeHandler("jimConsumableEmotes", nil, function(bagName, key, value, _unused)
if type(value) == "table" then
local newEmoteCount = 0
@@ -62,7 +63,7 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
if requiredItem then
if not hasItem(requiredItem, 1) then
triggerNotify(nil, "You need a "..Items[requiredItem].label, "error")
triggerNotify(nil, "You need a "..getItemLabel(requiredItem), "error")
return
else
-- if requiredItem == "lighter" then breakTool({ item = "lighter", damage = math.random(0, 1) }) end
@@ -72,6 +73,7 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
debugPrint("^5Debug^7: ^3Consume^7: ^2Starting event, locking inventory and grabbing data^7..")
tempLockInv(true)
local Player = PlayerPedId()
local pedCoords = GetEntityCoords(Player)
local emote = Emotes[consumable.emote] or Emotes["crisps"]
if isAnimal then --- Animal ped adjustments
local presets = {
@@ -127,25 +129,23 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
}
end
local returnItem = consumable.returnItem or nil
local animDict, anim = tostring(emote[1]), tostring(emote[2])
local model, model2, bone, bone2, drugeffect, stress
local P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12 = table.unpack({0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}) -- Default placement coord cariable
local RewardItem = consumable.rewards or nil
local type = consumable.type or ""
local pack = consumable.pack or nil
local string = "Using "
local canRun = consumable.canRun
local stats = consumable.stats
local time, stress, heal, armor, needStats = GenerateRandomValues({
local time, heal, armor, needStats = GenerateRandomValues({
time = consumable.time or { 5000, 6000 },
stress = consumable.stress or 0,
heal = consumable.heal or 0,
armor = consumable.armor or 0,
hunger = consumable.stats and consumable.stats.hunger or 0,
thirst = consumable.stats and consumable.stats.thirst or 0,
stress = consumable.stress or 0,
})
if emote.AnimationOptions.Prop then
model = emote.AnimationOptions.Prop
bone = GetPedBoneIndex(Player, emote.AnimationOptions.PropBone)
@@ -172,7 +172,7 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
debugPrint("^5Debug^7: ^3Consume^7: ^2Event already started^7, ^1Cancelling^7.")
tempLockInv(false)
if Config.UseProgbar then
stopPropgressBar()
stopProgressBar()
else
triggerNotify(nil, "Stopped "..string, "error")
end
@@ -208,13 +208,21 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
debugPrint("^5Debug^7: ^3Consume^7: ^2Player Movement Flag^7 - ^6"..json.encode(MovementType).." ^7")
if Config.Main.UseProgbar then
CreateThread(function()
if progressBar({ time = time, label = string..Items[itemName].label.."..", dead = false, cancel = false}) then
if progressBar({
time = time,
label = string..getItemLabel(itemName).."..",
dead = false,
disableMovement = false,
disableCombat = true,
cancel = false
}) then
consuming = false
else
consuming = false
end
end)
else
triggerNotify(nil, string..Items[itemName].label.."..", "success")
triggerNotify(nil, string..getItemLabel(itemName).."..", "success")
end
consuming = true
@@ -224,11 +232,11 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
if model then
if IsModelValid(model) == 1 then
debugPrint("^5Debug^7: ^3PropSpawn^7: ^2Spawning consumable prop^7...")
attachProp = makeProp({ prop = model, coords = vector4(0.0,0.0,0.0,0.0)}, 1, 1)
attachProp = makeProp({ prop = model, coords = vec4(pedCoords.x, pedCoords.y, pedCoords.z, 0.0)}, 1, 1, true)
AttachEntityToEntity(attachProp, Player, bone, P1, P2, P3, P4, P5, P6, true, true, false, true, 1, true)
if model2 then
if IsModelValid(model2) == 1 then
attachProp2 = makeProp({ prop = model2, coords = vector4(0.0,0.0,0.0,0.0)}, 1, 1)
attachProp2 = makeProp({ prop = model2, coords = vec4(pedCoords.x, pedCoords.y, pedCoords.z, 0.0)}, 1, 1)
AttachEntityToEntity(attachProp2, Player, bone2, P7, P8, P9, P10, P11, P12, true, true, false, true, 1, true)
else
print("^5Debug^7: ^3PropSpawn^7: ^2Second prop model isn't valid/found^7.")
@@ -242,7 +250,7 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
if DoesEntityExist(attachProp2) then
destroyProp(attachProp2)
attachProp2 = nil
end
end
else
print("^5Debug^7: ^3PropSpawn^7: ^2Prop model isn't valid/found^7.")
end
@@ -256,14 +264,14 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
"Type: "..(type or ""),
"Hunger: "..(needStats.hunger or 0).."%",
"Thirst: "..(needStats.thirst or 0).."%",
"Stress: "..(stress or 0).."%",
"Stress: "..(needStats.stress or 0).."%",
"Heal: "..(heal or 0).."%",
"Armour: "..(armor or 0).."%",
}, nil, nil)
end
makeInstructionalButtons({
{ keys = { 194 }, text = "Stop Consuming" },
})
})
if time <= 0 then
consuming = false
end
@@ -273,71 +281,23 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
tempLockInv(false)
hideText()
if Config.Main.UseProgbar then
stopPropgressBar()
stopProgressBar()
else
triggerNotify(nil, "Cancelled "..string, "error")
end
TriggerServerEvent(getScript()..":server:stopConsume")
end
Wait(0)
time -= 12
end
StopEntityAnim(Player, anim, animDict, 1.0)
unloadAnimDict(animDict)
if not cancelled then
hideText()
removeItem(itemName, 1)
if returnItem ~= nil then
debugPrint("returnItem detected")
currentToken = triggerCallback(AuthEvent)
addItem(returnItem.item, returnItem.amount)
end
-- Reward Item calculations
CreateThread(function()
if RewardItem then
debugPrint("Reward Item detected")
for i = 1, consumable.amounttogive do
local rarity = math.random(1, 4) -- rarity calculation
while true do
local item = math.random(1, countTable(RewardItem)) -- random item in the list to pick
if RewardItem[item].rarity >= rarity then
currentToken = triggerCallback(AuthEvent)
addItem(RewardItem[item].item, math.random(1, RewardItem[item].max or 1))
debugPrint("^5Debug^7: ^2Given reward prize^7: '^6"..RewardItem[item].item.."^7'")
break
end
Wait(100)
end
Wait(1500)
end
end
end)
if needStats then
if needStats.hunger then
local hunger = 0
if Core.Functions and Core.Functions.GetPlayerData then
hunger = Core.Functions.GetPlayerData().metadata["hunger"] or 0
elseif ESX and ESX.GetPlayerData then
hunger = ESX.GetPlayerData().hunger or 0
end
TriggerServerEvent(getScript()..":server:addNeed", hunger + needStats.hunger, "hunger")
end
TriggerServerEvent(getScript()..":server:finishConsume", needStats)
if needStats.thirst then
local thirst = 0
if Core.Functions and Core.Functions.GetPlayerData then
thirst = Core.Functions.GetPlayerData().metadata["thirst"] or 0
elseif ESX and ESX.GetPlayerData then
thirst = ESX.GetPlayerData().thirst or 0
end
TriggerServerEvent(getScript()..":server:addNeed", thirst + needStats.thirst, "thirst")
end
end
debugPrint("^5Debug^7: ^2Hunger^7: [^6"..(needStats.hunger or 0).."^7] ^2Thrist^7: [^6"..(needStats.thirst or 0).."^7]" )
if stress and stress ~= 0 then
debugPrint("^5Debug^7: ^3Consume^7: ^2Relieving ^6"..stress.." ^2stress^7.")
TriggerServerEvent('hud:server:RelieveStress', stress)
end
if heal and heal ~= 0 then
debugPrint("^5Debug^7: ^3Consume^7: ^2Healing player by^7: ^6"..heal)
SetEntityHealth(Player, GetEntityHealth(Player) + heal)
@@ -347,20 +307,42 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
TriggerServerEvent('hospital:server:SetArmor', (GetPedArmour(Player) + armor)) SetPedArmour(Player, (GetPedArmour(Player) + armor))
end
if type == "alcohol" then
alcoholCount += 1
debugPrint("^5Debug^7: ^3Consume^7: ^2Current ^4alcoholCount^7: ^6"..alcoholCount)
if alcoholCount > 1 and alcoholCount < 4 then
TriggerEvent("evidence:client:SetStatus", "alcohol", 200)
elseif alcoholCount >= 4 then
TriggerEvent("evidence:client:SetStatus", "heavyalcohol", 200)
CreateThread(function()
AlienEffect()
end) -- Used as overdosing/too drunk effect
if checkExportExists("jim_bridge", "addAlcoholCount") then
exports.jim_bridge:addAlcoholCount(1, stats.canOD)
else
alcoholCount = alcoholCount + 1
debugPrint("^5Debug^7: ^3Consume^7: ^2Current ^4alcoholCount^7: ^6"..alcoholCount)
if alcoholCount > 1 and alcoholCount <= 4 then
TriggerEvent("evidence:client:SetStatus", "alcohol", 200)
elseif alcoholCount >= 4 then
TriggerEvent("evidence:client:SetStatus", "heavyalcohol", 200)
CreateThread(function()
AlienEffect()
end)
end
if stats.canOD and alcoholCount >= 5 then
SetEntityHealth(Player, GetEntityHealth(Player) - math.random(5, 10))
end
end
end
if pack then
currentToken = triggerCallback(AuthEvent)
addItem(pack.item, pack.amount)
if type == "drug" then
if checkExportExists("jim_bridge", "addDrugCount") then
exports.jim_bridge:addDrugCount(1, stats.canOD or false)
else
drugCount = drugCount + 1
debugPrint("^5Debug^7: ^3Consume^7: ^2Current ^4drugCount^7: ^6"..drugCount)
if drugCount > 3 and drugCount < 7 then
elseif drugCount >= 7 then
CreateThread(function()
AlienEffect()
end)
end
if stats.canOD and drugCount >= 4 then
SetEntityHealth(Player, GetEntityHealth(Player) - math.random(5, 10))
end
end
end
if stats then
if stats.screen then -- Screen effect activation
@@ -381,14 +363,8 @@ RegisterNetEvent(getScript()..':Consume', function(itemName)
end
end
if stats.canOD then
drugCount += 1
debugPrint("^5Debug^7: ^3Consume^7: ^2Current ^4drugCount^7: ^6"..drugCount)
if drugCount >= 4 then
debugPrint("^5Debug^7: ^3Consume^7: ^2Current ^4drugCount^7: ^6"..drugCount.."^7 - ^2 removing health")
SetEntityHealth(PlayerPedId(), GetEntityHealth(Player) - math.random(10, 15))
if drugCount >= 7 then
CreateThread(function() AlienEffect() end) -- If too many drugs, if not dead will make you stumble
end
if drugCount >= 4 or alcoholCount >= 5 then
SetEntityHealth(Player, GetEntityHealth(Player) - math.random(5, 10))
end
end
if stats.effect then

View File

@@ -10,7 +10,7 @@ Config = {
},
Main = {
UseProgbar = false, -- Disabled this, progress bars stop all anims when complete.
UseProgbar = false, -- Recommended to disable this, progress bars stop ALL anims when complete.
-- This is intended to create a progressbar to show consuming but it was usually forces animations to end weirdly
},
Crafting = {

View File

@@ -1,6 +1,6 @@
name "Jim-Consumables"
author "Jimathy"
version "2.0.03"
version "2.0.08"
description "Consumables Script"
fx_version "cerulean"
game "gta5"

View File

@@ -1,13 +1,50 @@
local Consumables = Config.Consumables
local Emotes = Config.Emotes
local isConsuming = {}
local function massMakeUseable()
for k, v in pairs(Config.Consumables) do
createUseableItem(k, function(source, item)
local src = source
if not isConsuming[src] and hasItem(item.name, 1, src) then
registerConsume(src, item.name)
TriggerClientEvent(getScript()..':Consume', src, item.name)
end
end)
end
end
function registerConsume(src, item)
-- Start building server sided item return table
local consumable = Consumables[item]
isConsuming[src] = {
item = item,
rewardItem = checkReward(consumable) or nil,
returnItem = checkReturnItem(consumable) or nil,
packItem = checkPackItem(consumable) or nil
}
debugPrint("^5Debug^7: ^2Player ^3"..src.." ^2started consuming ^7'^2"..item.."^7'")
end
RegisterNetEvent(getScript()..":RegisterConsuming", function(item)
local src = source
registerConsume(src, item)
end)
onResourceStart(function()
for k, v in pairs(Config.Consumables) do
createUseableItem(k, function(source, item) TriggerClientEvent(getScript()..':Consume', source, item.name) end)
if not Items[k] then print("^1Debug^7: ^2Item check ^7- '^1"..k.."^7' ^2not found in the shared lua^7") end
if not Config.Emotes[v.emote] then print("^1Debug^7: ^2Emote check ^7- '^1"..k.."^7' ^2requested emote ^7'^6"..v.emote.."^7' - ^2not found in config^7.^2lua^7") end
if not Items[k] then
print("^1Debug^7: ^2Item check ^7- '^1"..k.."^7' ^2not found in the shared lua^7")
end
if not Config.Emotes[v.emote] then
print("^1Debug^7: ^2Emote check ^7- '^1"..k.."^7' ^2requested emote ^7'^6"..v.emote.."^7' - ^2not found in config^7.^2lua^7")
end
end
massMakeUseable()
--Export Import System--
GlobalState.jimConsumableItems = Consumables
GlobalState.jimConsumableEmotes = Emotes
@@ -18,43 +55,10 @@ onResourceStop(function()
GlobalState.jimConsumableEmotes = Emotes
end)
RegisterNetEvent(getScript()..':server:addNeed', function(amount, type)
local src = source
if Core.Functions and Core.Functions.GetPlayer then -- QBCore/QBox
local Player = Core.Functions.GetPlayer(src)
if not Player then return end
if type == "thirst" then
Player.Functions.SetMetaData('thirst', amount)
TriggerClientEvent('hud:client:UpdateNeeds', src, Player.PlayerData.metadata.hunger, amount)
elseif type == "hunger" then
Player.Functions.SetMetaData('hunger', amount)
TriggerClientEvent('hud:client:UpdateNeeds', src, amount, Player.PlayerData.metadata.thirst)
end
elseif ESX and ESX.GetPlayerFromId then -- ESX
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return end
local hunger = xPlayer.get('hunger') or 0
local thirst = xPlayer.get('thirst') or 0
if type == "thirst" then
thirst = amount
xPlayer.set('thirst', thirst)
elseif type == "hunger" then
hunger = amount
xPlayer.set('hunger', hunger)
end
TriggerClientEvent('hud:client:UpdateNeeds', src, hunger, thirst)
end
end)
local syncScheduled = false
function syncConsumables()
debugPrint("^5Statebag^7: ^2Sending ^6"..countTable(Consumables).." ^3Consumables ^2to all clients^7")
massMakeUseable()
GlobalState.jimConsumableItems = Consumables
syncScheduled = false
end
@@ -66,6 +70,101 @@ function syncEmotes()
emoteSyncScheduled = false
end
-- Return item
function checkPackItem(consumable)
local result = nil
if consumable.pack then
result = { item = consumable.pack.item, amount = consumable.pack.amount }
end
return result
end
-- Return item
function checkReturnItem(consumable)
local result = nil
if consumable.returnItem then
result = { item = consumable.returnItem.item, amount = consumable.returnItem.amount }
end
return result
end
-- Reward items
function checkReward(consumable)
local result = nil
local rewardItem = consumable.rewards or nil
if rewardItem then
debugPrint("Reward Item detected")
for i = 1, consumable.amounttogive or 1 do
local rarity = math.random(1, 4) -- rarity calculation
while true do
local item = math.random(1, countTable(rewardItem)) -- random item in the list to pick
if rewardItem[item].rarity >= rarity then
result = result or {}
result[#result+1] = { item = rewardItem[item].item, amount = math.random(1, rewardItem[item].max or 1) }
debugPrint("^5Debug^7: ^2Cachced reward prize^7: '^6"..rewardItem[item].item.."^7'")
break
end
Wait(10)
break
end
end
end
return result
end
RegisterNetEvent(getScript()..":server:finishConsume", function(needTypes)
local src = source
if isConsuming[src] ~= nil then
removeItem(isConsuming[src].item, 1, src)
if isConsuming[src].rewardItem then
debugPrint("^5Debug^7: ^2Giving player ^3"..src.." ^2reward items^7")
for i = 1, #isConsuming[src].rewardItem do
local item = isConsuming[src].rewardItem[i]
addItem(item.item, item.amount, nil, src)
end
end
if isConsuming[src].returnItem then
debugPrint("^5Debug^7: ^2Giving player ^3"..src.." ^2return item^7")
for i = 1, #isConsuming[src].returnItem do
local item = isConsuming[src].returnItem[i]
addItem(item.item, item.amount, nil, src)
end
end
if isConsuming[src].packItem then
for i = 1, #isConsuming[src].packItem do
debugPrint("^5Debug^7: ^2Giving player ^3"..src.." ^2Pack items^7")
local item = isConsuming[src].packItem[i]
addItem(item.item, item.amount, nil, src)
end
end
-- Needs
if needTypes.thirst then
debugPrint("^5Debug^7: ^2Thrist^7: [^6"..(needTypes.thirst or 0).."^7]")
setThirst(src, needTypes.thirst)
end
if needTypes.hunger then
debugPrint("^5Debug^7: ^2Hunger^7: [^6"..(needTypes.hunger or 0).."^7]")
setHunger(src, needTypes.hunger)
end
if needTypes.stress then
debugPrint("^5Debug^7: ^2Stress^7: [^6"..(needTypes.stress or 0).."^7]")
setStress(src, needTypes.stress)
end
isConsuming[src] = nil
else
return
end
end)
RegisterNetEvent(getScript()..":server:stopConsume", function()
local src = source
debugPrint("^5Player stopped consuming early^7", src)
isConsuming[src] = nil
end)
RegisterNetEvent(getScript()..':server:syncAddItem', function(itemName, data)
if not Consumables[itemName] then
Consumables[itemName] = data

View File

@@ -47,7 +47,7 @@ Config.Consumables = {
-- heal = 0, -- Set amount to heal by after consuming
-- armor = 5, -- Amount of armor to add
-- type = "food", -- Type: "alcohol" / "drink" / "food"
-- canRun = true, -- If true player can run while using the item, not to it will cancel the event
-- canRun = true, -- If true player can run while using the item, if not it will cancel the event
--
-- stats = {
-- screen = "thermal", -- The screen effect to be played when after consuming the item "rampage" "turbo" "focus" "weed" "trevor" "nightvision" "thermal"
@@ -74,7 +74,7 @@ Config.Consumables = {
-- Example Box Item
-- ["9_box"] = { -- Name of the box item in the shared
-- emote = "uncuff", -- The emote than should run when "unboxing"
-- canRun = true, -- If true player can run while using the item, not to it will cancel the event
-- canRun = true, -- If true player can run while using the item, if not it will cancel the event
-- time = 3500, -- How long it takes to use the item
-- type = "pack", -- Designate it as a "pack" to the script knows what to do
-- pack = {
@@ -83,4 +83,18 @@ Config.Consumables = {
-- },
-- },
-- Example Cigar Item wiht requirements
-- ["cigar"] = { -- Name of the item in your shared items
-- emote = "smokecigar", -- The emote than should run when "smoking"
-- canRun = true, -- If true player can run while using the item, if not it will cancel the event
-- time = math.random(5000, 6000), -- How long it takes to use the item
-- type = "smoke", -- Designate it as a "smoke" to the script knows what to do
-- requiredItem = "lighter", -- Set a required item making it unsable if they don't have it
-- stats = {
-- effect = "stress",
-- time = 5000,
-- amount = math.random(10, 15),
-- canOD = false
-- }
-- },
}

View File

@@ -15,9 +15,23 @@ function GenerateRandomValues(data)
transData[k] = v
end
end
return transData["time"],
transData["stress"],
transData["heal"],
transData["armor"],
{ hunger = transData["hunger"], thirst = transData["thirst"] }
if transData.hunger > 0 then
transData.hunger = transData.hunger > 100 and 100 or transData.hunger
end
if transData.thirst > 0 then
transData.thirst = transData.thirst > 100 and 100 or transData.thirst
end
if transData.stress > 0 then
transData.stress = transData.stress > 100 and 100 or transData.stress
end
return transData["time"],
transData["heal"],
transData["armor"],
{
hunger = transData["hunger"],
thirst = transData["thirst"],
stress = transData["stress"]
}
end

View File

@@ -1,7 +1,7 @@
2.0.03
2.0.08
- Convert to Global Statebags for optimized data syncing
- Fix hunger/thirst for esx
- Possible fix for imported items not being usable
- Fix issues with stress calculations
- Separates "drug control" from canOD boolean
- Adds support for jim_bridge built-in synchronized alcohol/drug effects
https://github.com/jimathy/jim-consumables
https://github.com/jimathy/jim-consumables/releases/latest