Skip to content

Commit

Permalink
Bug fixes and general update (#41)
Browse files Browse the repository at this point in the history
* Delete functions.lua

* Delete controllers.lua

* Delete functions.lua

* Update version

* Update README.md

* Update fxmanifest.lua

- updated folder structure

* Update config.lua

- add blip settings

* Update usableItems.lua

- add user check
- housekeeping

* Update main.lua

- fixed plant count when client connects
- add inventory item checks
- fixed if missing water bucket it doesn't play anim or set as watered
- housekeeping

* Update main.lua

- update bucket scenario to smooth out the finish
- housekeeping

* Update planting.lua

- add native prompts
- housekeeping

* Update planted.lua

- add native prompts
- fix plant blips not showing
- add native plant blips
- add native plant object creation
- add water bucket item check before running anim and setting plant as watered
- moved seed removal to end of planting process
- housekeeping
  • Loading branch information
JusCampin authored Oct 16, 2024
1 parent 62b0a6f commit 26f1d81
Show file tree
Hide file tree
Showing 12 changed files with 478 additions and 361 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
- Restart server

## Side notes
- Make sure all items set exist in your database
- Make sure all items exist in your database.
- This script is written from scratch, but took a heavy inspiration from prp_farming.
- You can edit the code obviously. All I ask is that you release the edits to the community freely.

Expand Down
44 changes: 0 additions & 44 deletions client/helpers/functions.lua

This file was deleted.

45 changes: 44 additions & 1 deletion client/main.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
VORPcore = exports.vorp_core:GetCore()

RegisterNetEvent('vorp:SelectedCharacter', function()
TriggerServerEvent('bcc-farming:NewClientConnected')
end)
end)

function ScenarioInPlace(hash, time)
local playerPed = PlayerPedId()
FreezeEntityPosition(playerPed, true)
TaskStartScenarioInPlace(playerPed, joaat(hash), time, true, false, false, false)
Wait(time)
ClearPedTasks(playerPed)
Wait(4000)
HidePedWeapons(playerPed, 2, true)
FreezeEntityPosition(playerPed, false)
end

function PlayAnim(animDict, animName, time, raking, loopUntilTimeOver) --function to play an animation
local animTime = time
RequestAnimDict(animDict)
while not HasAnimDictLoaded(animDict) do
Wait(10)
end

local flag = 16
-- if time is -1 then play the animation in an infinite loop which is not possible with flag 16 but with 1
-- if time is -1 the caller has to deal with ending the animation by themselve
if loopUntilTimeOver then
flag = 1
animTime = -1
end

local playerPed = PlayerPedId()
TaskPlayAnim(playerPed, animDict, animName, 1.0, 1.0, animTime, flag, 0, true, 0, false, 0, false)
if raking then
local playerCoords = GetEntityCoords(playerPed)
local rakeObj = CreateObject('p_rake02x', playerCoords.x, playerCoords.y, playerCoords.z, true, true, false)
AttachEntityToEntity(rakeObj, playerPed, GetEntityBoneIndexByName(playerPed, 'PH_R_Hand'), 0.0, 0.0, 0.19,
0.0, 0.0, 0.0, false, false, true, false, 0, true, false, false)
Wait(time)
DeleteObject(rakeObj)
else
Wait(time)
end
ClearPedTasks(playerPed)
end
153 changes: 103 additions & 50 deletions client/services/planted.lua
Original file line number Diff line number Diff line change
@@ -1,35 +1,81 @@
local WaterPrompt, DestroyPromptWG
local WaterGroup = GetRandomIntInRange(0, 0xffffff)

local HarvestPrompt, DestroyPromptHG
local HarvestGroup = GetRandomIntInRange(0, 0xffffff)

local PromptsStarted = false
local Crops = {}

---@param plantId integer
---@param plantData table
---@param plantCoords vector3
---@param timeLeft integer --May be nil if called from addplant event only used in neew client connected event
---@param watered boolean --Boolean string
---@param source integer
local function StartPrompts()
WaterPrompt = PromptRegisterBegin()
PromptSetControlAction(WaterPrompt, Config.keys.water)
PromptSetText(WaterPrompt, CreateVarString(10, 'LITERAL_STRING', _U('useBucket')))
PromptSetVisible(WaterPrompt, true)
PromptSetEnabled(WaterPrompt, true)
PromptSetHoldMode(WaterPrompt, 2000)
PromptSetGroup(WaterPrompt, WaterGroup, 0)
PromptRegisterEnd(WaterPrompt)

DestroyPromptWG = PromptRegisterBegin()
PromptSetControlAction(DestroyPromptWG, Config.keys.destroy)
PromptSetText(DestroyPromptWG, CreateVarString(10, 'LITERAL_STRING', _U('destroyPlant')))
PromptSetVisible(DestroyPromptWG, true)
PromptSetEnabled(DestroyPromptWG, true)
PromptSetHoldMode(DestroyPromptWG, 2000)
PromptSetGroup(DestroyPromptWG, WaterGroup, 0)
PromptRegisterEnd(DestroyPromptWG)

HarvestPrompt = PromptRegisterBegin()
PromptSetControlAction(HarvestPrompt, Config.keys.harvest)
PromptSetText(HarvestPrompt, CreateVarString(10, 'LITERAL_STRING', _U('harvest')))
PromptSetVisible(HarvestPrompt, true)
PromptSetEnabled(HarvestPrompt, true)
PromptSetHoldMode(HarvestPrompt, 2000)
PromptSetGroup(HarvestPrompt, HarvestGroup, 0)
PromptRegisterEnd(HarvestPrompt)

DestroyPromptHG = PromptRegisterBegin()
PromptSetControlAction(DestroyPromptHG, Config.keys.destroy)
PromptSetText(DestroyPromptHG, CreateVarString(10, 'LITERAL_STRING', _U('destroyPlant')))
PromptSetVisible(DestroyPromptHG, true)
PromptSetEnabled(DestroyPromptHG, true)
PromptSetHoldMode(DestroyPromptHG, 2000)
PromptSetGroup(DestroyPromptHG, HarvestGroup, 0)
PromptRegisterEnd(DestroyPromptHG)

PromptsStarted = true
end

RegisterNetEvent('bcc-farming:PlantPlanted', function(plantId, plantData, plantCoords, timeLeft, watered, source)
local plantObj = BccUtils.Objects:Create(plantData.plantProp, plantCoords.x, plantCoords.y, plantCoords.z, GetEntityHeading(PlayerPedId()), false, 'standard')
plantObj:PlaceOnGround(true)
if plantData.plantOffset ~= 0 then
SetEntityCoords(plantObj:GetObj(), plantCoords.x, plantCoords.y, plantCoords.z - plantData.plantOffset, false, false, false, true)
local hash = joaat(plantData.plantProp)
RequestModel(hash, false)
while not HasModelLoaded(hash) do
Wait(10)
end

local plantObj = Citizen.InvokeNative(0x509D5878EB39E842, hash, plantCoords.x, plantCoords.y, plantCoords.z - plantData.plantOffset, false, false, false, false, false) -- CreateObject
SetEntityHeading(plantObj, GetEntityHeading(PlayerPedId()))
PlaceObjectOnGroundProperly(plantObj, true)
FreezeEntityPosition(plantObj, true)

Crops[plantId] = { plantId = plantId, removePlant = false, watered = tostring(watered)}

local blip = nil
if Config.plantSetup.blips then -- Make a check on server to only have blip show for planter not everyone otherwise blips would be for everyone if its not locked to planter
if GetPlayerServerId(PlayerPedId()) == source then -- Only show blip for planter not all clients
blip = BccUtils.Blip:SetBlip(_U('plant'), 'blip_mp_spawnpoint', 0.2, plantCoords.x, plantCoords.y, plantCoords.z)
if Config.plantSetup.blips.enabled then
if GetPlayerServerId(PlayerId()) == source then -- Only show blip for planter not all clients
blip = Citizen.InvokeNative(0x554d9d53f696d002, 1664425300, plantCoords.x, plantCoords.y, plantCoords.z) -- BlipAddForCoords
SetBlipSprite(blip, joaat(Config.plantSetup.blips.sprite), true)
Citizen.InvokeNative(0x9CB1A1623062F402, blip, Config.plantSetup.blips.name) -- SetBlipName
Citizen.InvokeNative(0x662D364ABF16DE2F, blip, joaat(Config.BlipColors[Config.plantSetup.blips.color])) -- BlipAddModifier
end
end

local waterGroup = BccUtils.Prompt:SetupPromptGroup()
local waterPrompt = waterGroup:RegisterPrompt(_U('useBucket'), Config.keys.water, 1, 1, true, 'hold', { timedeventhash = 'MEDIUM_TIMED_EVENT' })
local destroyPromptWG = waterGroup:RegisterPrompt(_U('destroyPlant'), Config.keys.destroy, 1, 1, true, 'hold', { timedeventhash = 'MEDIUM_TIMED_EVENT'})
local doWaterAnim = false -- Used to play the anim after the watered status is changed (Cant be done where serv event is triggered as you may not have the buckets this stops it from playing unless you have the buckets)
local harvestGroup = BccUtils.Prompt:SetupPromptGroup()
local harvestPrompt = harvestGroup:RegisterPrompt(_U('harvest'), Config.keys.harvest, 1, 1, true, 'hold', { timedeventhash = 'MEDIUM_TIMED_EVENT' })
local destroyPromptHG = harvestGroup:RegisterPrompt(_U('destroyPlant'), Config.keys.destroy, 1, 1, true, 'hold', { timedeventhash = 'MEDIUM_TIMED_EVENT'})
if not PromptsStarted then
StartPrompts()
end

CreateThread(function() -- I normally hate doing layered threads in an event or function but this is the best way to keep the time synced with the database and accurate
CreateThread(function() -- keep the time synced with the database
while tonumber(timeLeft) > 0 and Crops[plantId] do
if Crops[plantId].removePlant then break end
if Crops[plantId].watered == 'true' then
Expand All @@ -43,14 +89,14 @@ RegisterNetEvent('bcc-farming:PlantPlanted', function(plantId, plantData, plantC

while true do
local sleep = 1000

if Crops[plantId].removePlant then
Crops[plantId] = false
if Config.plantSetup.blips then
if blip then
blip:Remove()
end
if blip then
RemoveBlip(blip)
end
plantObj:Remove() break
DeleteObject(plantObj)
break
end

if tostring(Crops[plantId].watered) ~= tostring(watered) then
Expand All @@ -59,28 +105,28 @@ RegisterNetEvent('bcc-farming:PlantPlanted', function(plantId, plantData, plantC

local dist = #(GetEntityCoords(PlayerPedId()) - vector3(plantCoords.x, plantCoords.y, plantCoords.z))
if tostring(watered) ~= 'false' then
if doWaterAnim and Crops[plantId].watered == 'true' then
ScenarioInPlace('WORLD_HUMAN_BUCKET_POUR_LOW', 5000)
doWaterAnim = false
end

if dist <= 1.5 then
sleep = 0

if tonumber(timeLeft) > 0 then
local minutes = math.floor(timeLeft / 60)
local seconds = timeLeft % 60
harvestPrompt:EnabledPrompt(false)
harvestGroup:ShowGroup(_U('plant') .. ' ' .. plantData.plantName..' | ' .. _U('secondsUntilharvest')..string.format('%02d:%02d', minutes, seconds))
PromptSetEnabled(HarvestPrompt, false)
local noHarvest = _U('plant') .. ': ' .. plantData.plantName..' | ' .. _U('secondsUntilharvest')..string.format('%02d:%02d', minutes, seconds)
PromptSetActiveGroupThisFrame(HarvestGroup, CreateVarString(10, 'LITERAL_STRING', noHarvest), 1, 0, 0, 0)

elseif tonumber(timeLeft) <= 0 then
harvestPrompt:EnabledPrompt(true)
harvestGroup:ShowGroup(_U('plant') .. ' ' .. plantData.plantName..' ' .. _U('secondsUntilharvestOver'))
if harvestPrompt:HasCompleted() then
PromptSetEnabled(HarvestPrompt, true)
local harvest = _U('plant') .. ': ' .. plantData.plantName..' ' .. _U('secondsUntilharvestOver')
PromptSetActiveGroupThisFrame(HarvestGroup, CreateVarString(10, 'LITERAL_STRING', harvest), 1, 0, 0, 0)

if Citizen.InvokeNative(0xE0F65F0640EF0617, HarvestPrompt) then -- PromptHasHoldModeCompleted
for _, reward in pairs(plantData.rewards) do
local canCarry = VORPcore.Callback.TriggerAwait('bcc-farming:CanCarryCheck', reward.itemName, reward.amount)
if canCarry then
PlayAnim('mech_pickup@plant@berries', 'base', 2500)
if blip then
blip:Remove()
RemoveBlip(blip)
end
VORPcore.NotifyRightTip(_U('harvested'), 4000)
TriggerServerEvent('bcc-farming:HarvestPlant', plantId, plantData, false)
Expand All @@ -91,32 +137,41 @@ RegisterNetEvent('bcc-farming:PlantPlanted', function(plantId, plantData, plantC
end
end
end
if destroyPromptHG:HasCompleted() then

if Citizen.InvokeNative(0xE0F65F0640EF0617, DestroyPromptHG) then -- PromptHasHoldModeCompleted
if blip then
blip:Remove()
RemoveBlip(blip)
end
PlayAnim('amb_camp@world_camp_fire@stomp@male_a@wip_base', 'wip_base', 10000)
PlayAnim('amb_camp@world_camp_fire@stomp@male_a@wip_base', 'wip_base', 8000)
TriggerServerEvent('bcc-farming:HarvestPlant', plantId, plantData, true)
end
end

else
if dist <= 1.5 and tostring(watered) == 'false' then
sleep = 0
local isRaining = GetRainLevel()
if isRaining > 0 then
Crops[plantId].watered = 'true'
TriggerServerEvent('bcc-farming:UpdatePlantWateredStatus', plantId, isRaining)

else
waterGroup:ShowGroup(_U('waterPlant'))
if waterPrompt:HasCompleted() then
doWaterAnim = true
TriggerServerEvent('bcc-farming:UpdatePlantWateredStatus', plantId, isRaining)
PromptSetActiveGroupThisFrame(WaterGroup, CreateVarString(10, 'LITERAL_STRING', _U('waterPlant')), 1, 0, 0, 0)
if Citizen.InvokeNative(0xE0F65F0640EF0617, WaterPrompt) then -- PromptHasHoldModeCompleted
local hasWaterBucket = VORPcore.Callback.TriggerAwait('bcc-farming:CheckHasItem', Config.fullWaterBucket, 1)
if hasWaterBucket then
ScenarioInPlace('WORLD_HUMAN_BUCKET_POUR_LOW', 5000)
TriggerServerEvent('bcc-farming:UpdatePlantWateredStatus', plantId, isRaining)
else
VORPcore.NotifyRightTip(_U('noWaterBucket'), 4000)
end
end
if destroyPromptWG:HasCompleted() then

if Citizen.InvokeNative(0xE0F65F0640EF0617, DestroyPromptWG) then -- PromptHasHoldModeCompleted
if blip then
blip:Remove()
RemoveBlip(blip)
end
PlayAnim('amb_camp@world_camp_fire@stomp@male_a@wip_base', 'wip_base', 10000)
PlayAnim('amb_camp@world_camp_fire@stomp@male_a@wip_base', 'wip_base', 8000)
TriggerServerEvent('bcc-farming:HarvestPlant', plantId, plantData, true)
end
end
Expand All @@ -126,16 +181,14 @@ RegisterNetEvent('bcc-farming:PlantPlanted', function(plantId, plantData, plantC
end
end)

---@param plantId integer
RegisterNetEvent('bcc-farming:RemovePlantClient', function(plantId)
if Crops[plantId] then
Crops[plantId].removePlant = true
end
end)

---@param plantId integer
RegisterNetEvent('bcc-farming:UpdatePlantWateredStatus', function (plantId)
if Crops[plantId] then
Crops[plantId].watered = 'true'
end
end)
end)
Loading

0 comments on commit 26f1d81

Please sign in to comment.