Skip to content

Double Ped & Target Bug Fixed Files Are Here #100

@mamunbiswash986-web

Description

@mamunbiswash986-web

-- client.lua
local Props, Targets, Peds, Blip, soundId = {}, {}, {}, {}, GetSoundId()

local MiningLoaded = false

Mining = {
Functions = {},
MineOre = {},
Other = {},
Menus = {},
}

local propTable = {
{ full = "cs_x_rubweec", empty = "prop_rock_5_a" },
}
if Config.General.K4MB1Prop then
propTable = {
{ full = "cs_x_rubweec", empty = "prop_rock_5_a" },
{ full = "k4mb1_crystalblue", empty = "k4mb1_crystalempty" },
{ full = "k4mb1_crystalgreen", empty = "k4mb1_crystalempty" },
{ full = "k4mb1_crystalred", empty = "k4mb1_crystalempty" },
{ full = "k4mb1_bauxiteore2", empty = "k4mb1_emptyore2" },
{ full = "k4mb1_coal2", },
{ full = "k4mb1_copperore2", empty = "k4mb1_emptyore2" },
{ full = "k4mb1_ironore2", empty = "k4mb1_emptyore2" },
{ full = "k4mb1_goldore2", empty = "k4mb1_emptyore2" },
{ full = "k4mb1_leadore2", empty = "k4mb1_emptyore2" },
{ full = "k4mb1_tinore2", empty = "k4mb1_emptyore2" },
{ full = "k4mb1_diamond", },
}
end

MiningLoaded = MiningLoaded or false

Mining.Functions.checkForJob = function()

if Config.General.requiredJob then

	if hasJob(Config.General.requiredJob) then

		-- 🔥 Prevent double spawn
		if not MiningLoaded then
			MiningLoaded = true
			Mining.Functions.makeJob()
		end

	else
		-- 🔥 Remove everything properly
		if MiningLoaded then
			MiningLoaded = false
			Mining.Functions.removeJob()
		end
	end

else
	-- 🔥 No job required, still prevent duplicates
	if not MiningLoaded then
		MiningLoaded = true
		Mining.Functions.makeJob()
	end
end

end

Mining.Functions.weightedRandomReward = function()
local totalWeight, weightedTable = 0, {}
for _, item in ipairs(Config.setMiningTable) do
local weight = item.rarity == "common" and 5 or item.rarity == "rare" and 3 or 1
totalWeight += weight
local prop = item.prop
if not Config.General.K4MB1Prop then
prop = "cs_x_rubweec"
end
table.insert(weightedTable, {name = item.name, weight = totalWeight, prop = prop})
end

local randValue = math.random(1, totalWeight)
for _, item in ipairs(weightedTable) do
	if randValue <= item.weight then
		return item
	end
end

end

Mining.Functions.spawnProp = function(coords, propName, adjustHeight)
local propCoords = vec4(coords.x, coords.y, coords.z + adjustHeight, coords.a)
local prop = makeProp({coords = propCoords, prop = propName}, 1, false)
local rot = GetEntityRotation(prop)
SetEntityRotation(prop, rot.x - math.random(60,100), rot.y, rot.z, 0, 0)
return prop
end

Mining.Functions.setupMiningTarget = function(name, coords, prop, emptyProp, setReward, job)
Targets[name] = createCircleTarget({name, vec3(coords.x, coords.y, coords.z), 1.2, {name = name, debugPoly = debugMode, useZ = true}}, {
{ action = function()
Mining.MineOre.pickaxe({stone = prop, name = name, coords = coords, emptyProp = emptyProp, setReward = setReward})
end,
icon = "fas fa-hammer",
item = "pickaxe",
label = locale("info", "mine_ore")..
" ("..(Items["pickaxe"] and Items["pickaxe"].label or "pickaxe❌")..") "..
(Config.General.AltMining and Items[setReward].label or "")..
(debugMode and " ["..name.."]" or ""),
job = job,
canInteract = function()
return not isMining
end,
},
{ action = function()
Mining.MineOre.miningDrill({stone = prop, name = name, coords = coords, emptyProp = emptyProp, setReward = setReward})
end,
icon = "fas fa-screwdriver",
item = "miningdrill",
label = locale("info", "mine_ore")..
" ("..(Items["miningdrill"] and Items["miningdrill"].label or "miningdrill❌")..")"..
(Config.General.AltMining and Items[setReward].label or "")..
(debugMode and " ["..name.."]" or ""),
job = job,
canInteract = function()
return not isMining
end,
},
{ action = function()
Mining.MineOre.miningLaser({stone = prop, name = name, coords = coords, emptyProp = emptyProp, setReward = setReward})
end,
icon = "fas fa-screwdriver-wrench",
item = "mininglaser",
label = locale("info", "mine_ore")..
" ("..(Items["mininglaser"] and Items["mininglaser"].label or "mininglaser❌")..")"..
(Config.General.AltMining and Items[setReward].label or "")..
(debugMode and " ["..name.."]" or ""),
job = job,
canInteract = function()
return not isMining
end,
},
}, 1.7)
end

Mining.Functions.makeJob = function()
Mining.Functions.removeJob()
if Locations["Mines"]["MineShaft"].Enable then
CreateModelHide(vec3(-596.04, 2089.01, 131.41), 10.5, prop_mineshaft_door, true)
end

--Ore Spawning
for mine, loc in pairs(Locations["Mines"]) do
	if loc.Enable then

		if loc["OrePositions"] then
			for i, coords in ipairs(loc["OrePositions"]) do
				local name = "Ore".."_"..mine.."_"..i
				local chosenProp, reward = propTable[math.random(#propTable)], "stone"

				if Config.General.AltMining then
					local weightedReward = Mining.Functions.weightedRandomReward()
					chosenProp = {
						full = weightedReward.prop,
						empty = nil
					}
					reward = weightedReward.name
				end
				local mainProp = Mining.Functions.spawnProp(coords, chosenProp.full, Config.General.K4MB1Prop and 0.8 or 1.1)
				local emptyProp
				if chosenProp.empty then
					emptyProp = Mining.Functions.spawnProp(coords, chosenProp.empty, Config.General.K4MB1Prop and 0.8 or 1.1)
				end
				Mining.Functions.setupMiningTarget(name, coords, mainProp, emptyProp, reward, loc.Job)
			end
		end
	--[[Blips]]--
		if loc.Blip.Enable then
			Blip[#Blip+1] = makeBlip(loc["Blip"])
		end

	--[[LIGHTS]]--
		if loc["Lights"] then
			if loc["Lights"].Enable then
				for i = 1, #loc["Lights"].positions do
					makeDistProp({coords = loc["Lights"].positions[i], prop = loc["Lights"].prop}, 1, false)
				end
			end
		end
	--[[Stores]]--
		if loc["Store"] then
			for i = 1, #loc["Store"] do
			local name = getScript()..":Store:"..mine..":"..i
				Peds[#Peds+1] = makePed(loc["Store"][i].model, loc["Store"][i].coords, 1, 1, loc["Store"][i].scenario)
				Targets[name] =
					createCircleTarget({name, loc["Store"][i].coords.xyz, 1.0, { name=name, debugPoly = debugMode, useZ=true, }, }, {
						{ 	action = function()
								openShop({ items = Config.Items, shop = "miningShop", coords = loc["Store"][i].coords })
							end,
							icon = "fas fa-store",
							label = locale("info", "browse_store")..(debugMode and " ["..name.."]" or ""),
							job = loc.Job,
						},
						(( mine == "K4MB1Shaft" and Config.General.K4MB1Cart ) and
							{	action = function()
									mineCartMenu(true)
								end,
								icon = "fas fa-wheelchair",
								label = "Minecart",
								job = loc.Job,
							} or nil
						),
					}, 2.0)
			end
		end
	--[[Smelting]]--
		if loc["Smelting"] then
			for i = 1, #loc["Smelting"] do
				local name = getScript()..":Smelting:"..i
				if loc["Smelting"][i].Enable then
					Blip[#Blip+1] = makeBlip(loc["Smelting"][i])
				end
				Targets[name] =
					createCircleTarget({name, loc["Smelting"][i].coords.xyz, 3.0, { name=name, debugPoly = debugMode, useZ=true, }, }, {
						{ 	action = function()
								craftingMenu({ craftable = Crafting.SmeltMenu, coords = loc["Smelting"][i].coords }) end,
								icon = "fas fa-fire-burner",
								label = locale("info", "use_smelter")..(debugMode and " ["..name.."]" or ""),
								job = loc.Job,
								canInteract = function()
									return not CraftLock
								end,
						},
					}, 10.0)
			end
		end
	--[[Cracking]]--
		if loc["Cracking"] then
			for i = 1, #loc["Cracking"] do
				local name = getScript()..":Cracking:"..mine..":"..i
				if loc["Cracking"][i].Enable then
					Blip[#Blip+1] = makeBlip(loc["Cracking"][i])
				end
				Props[#Props+1] = makeProp(loc["Cracking"][i], 1, false)
				local bench = Props[#Props]
				Targets[name] =
					createCircleTarget({name, loc["Cracking"][i].coords.xyz, 1.2, { name=name, debugPoly = debugMode, useZ=true, }, }, {
						{ 	action = function()
								Mining.Other.crackStart({ bench = bench })
							end,
							icon = "fas fa-compact-disc",
							label = locale("info", "crackingbench")..(debugMode and " ["..name.."]" or ""),
							item = "stone",
							job = loc.Job,
							canInteract = function()
								return not Cracking
							end,
						},
					}, 2.0)
			end
		end
	--[[Ore Buyer]]--
		if loc["OreBuyer"] then
			for i = 1, #loc["OreBuyer"] do
				local name = getScript()..":OreBuyer:"..mine..":"..i
				Peds[#Peds+1] = makePed(loc["OreBuyer"][i].model, loc["OreBuyer"][i].coords, 1, 1, loc["OreBuyer"][i].scenario)
				local ped = Peds[#Peds]
				if loc["OreBuyer"][i].Enable then
					Blip[#Blip+1] = makeBlip(loc["OreBuyer"][i])
				end
				Targets[name] =
					createCircleTarget({name, loc["OreBuyer"][i].coords.xyz, 0.9, { name = name, debugPoly = debugMode, uzeZ = true }, }, {
						{	action = function()
								sellMenu({
									name = name,
									ped = ped,
									sellTable = Selling["OreSell"]
								})
							end,
							icon = "fas fa-sack-dollar",
							label = locale("info", "sell_ores")..(debugMode and " ["..name.."]" or ""),
							job = Config.General.requiredJob
						},
					}, 2.0)
			end
		end
	--[[Jewel Cutting]]--
		if loc["JewelCut"] then
			for i = 1, #loc["JewelCut"] do
				local name = getScript()..":JewelCut:"..mine..":"..i
				if loc["JewelCut"][i].Enable then
					Blip[#Blip+1] = makeBlip(loc["JewelCut"][i])
				end
				Props[#Props+1] = makeProp(loc["JewelCut"][i], 1, false)
				local bench = Props[#Props]
				Targets[name] =
					createCircleTarget({name, loc["JewelCut"][i].coords.xyz, 1.2, { name = name, debugPoly = debugMode, useZ = true }, }, {
						{ 	action = function()
								Mining.Menus.jewelCut({bench = bench})
							end,
							icon = "fas fa-gem",
							label = locale("info", "jewelcut")..(debugMode and " ["..name.."]" or ""),
							job = Config.General.requiredJob,
							canInteract = function()
								return not CraftLock
							end,
						},
					}, 2.0)
			end
		end
		if (mine == "K4MB1Shaft" and Config.General.K4MB1Cart) then
			local cartCoords = {
				{ 	coords = vec4(-471.6, 2090.23, 120.08, 103.49),
					right = false,
				},
				{ 	coords = vec4(-564.39, 1885.17, 123.04, 22.38),
					right = true,
				},
			}
			for i = 1, #cartCoords do
				local name = getScript()..":Cart:"..mine..":"..i
				Peds[#Peds+1] = makePed("G_M_M_ChemWork_01", cartCoords[i].coords, 1, 1, "WORLD_HUMAN_CLIPBOARD")
				Targets[name] =
					createCircleTarget({name, cartCoords[i].coords.xyz, 1.0, { name=name, debugPoly = debugMode, useZ=true, }, }, {
						{	action = function()
								mineCartMenu(false, cartCoords[i].right)
							end,
							icon = "fas fa-wheelchair", label = "Minecart", job = loc.Job,
						},
					}, 2.0)
			end
		end
	end
end
--[[Stone Washing]]--
if Locations["Washing"].Enable then
	for k, v in pairs(Locations["Washing"].positions) do
		local name = getScript()..":Washing:"..k
		Targets[name] =
			createCircleTarget({ name, v.coords.xyz, 9.0, { name = name, debugPoly = debugMode, usez = true, }, }, {
				{	action = function()
						Mining.Other.washStart({ coords = v.coords })
					end,
					icon = "fas fa-hands-bubbles",
					item = "stone",
					label = locale("info", "washstone")..(debugMode and " ["..name.."]" or ""),
					canInteract = function()
						return not Washing
					end

				},
			}, 2.0)
		if v.blipEnable then
			Blip[#Blip+1] = makeBlip(v)
		end
	end
end
--[[Panning]]--
if Locations["Panning"].Enable then
	for location in pairs(Locations["Panning"].positions) do
		local loc = Locations["Panning"].positions[location]
		if loc.Blip.Enable then Blip[#Blip+1] = makeBlip(loc["Blip"]) end
		for i = 1, #loc.Positions do
			local name = getScript()..":Panning:"..location..":"..i
			Targets[name] =
				createBoxTarget( { name, loc.Positions[i].coords.xyz, loc.Positions[i].w, loc.Positions[i].d, { name=name, heading = loc.Positions[i].coords.w, debugPoly = debugMode, minZ=loc.Positions[i].coords.z-10.0, maxZ=loc.Positions[i].coords.z+10.0 }, }, {
					{ 	action = function()
							Mining.Other.panStart({ coords = loc.Positions[i].coords })
						end,
						icon = "fas fa-ring",
						item = "goldpan",
						label = locale("info", "goldpan"),
						canInteract = function()
							return not Panning
						end,
					},
				}, 2.0)
		end
	end
end
--[[Jewel Buyer]]--
if Locations["JewelBuyer"].Enable then
	for k, v in pairs(Locations["JewelBuyer"].positions) do
		local name = getScript()..":JewelBuyer:"..k
		if v.blipTrue then Blip[#Blip+1] = makeBlip(v) end
		Peds[#Peds+1] = makePed(v.model, v.coords, 1, 1, v.scenario)
		local ped = Peds[#Peds]
		Targets[name] =
			createCircleTarget({ name, v.coords.xyz, 1.2, { name = name, debugPoly = debugMode, useZ = true }, }, {
				{	action = function()
						sellMenu({
                    		name = name,
							ped = ped,
							sellTable = Selling["JewelSell"]
						})
					end,
					icon = "fas fa-gem", label = locale("info", "jewelbuyer")..(debugMode and " ["..name.."]" or ""), job = Config.General.requiredJob
				},
			}, 2.0)
	end
end

end


Mining.Other.stoneBreak = function(name, stone, coords, job, rot, empty)
CreateThread(function()
local prop, emptyProp, setReward = stone, empty, "stone"
removeZoneTarget(Targets[name])
Targets[name] = nil

	if Config.General.AltMining then
		destroyProp(prop)
		Wait(debugMode and 2000 or GetTiming(Config.Timings["OreRespawn"]))

		local weightedReward = Mining.Functions.weightedRandomReward()
		local propPick = { full = weightedReward.prop, empty = nil }
		setReward = weightedReward.name

		prop = Mining.Functions.spawnProp(coords, propPick.full, Config.General.K4MB1Prop and 0.8 or 1.1)
		destroyProp(emptyProp)

		if propPick.empty then
			emptyProp = Mining.Functions.spawnProp(coords, propPick.empty, Config.General.K4MB1Prop and 0.8 or 1.1)
		end
	else
		debugPrint("^5Debug^7: ^2Hiding prop and target^7: '^6"..name.."^7' ^2at coords^7: ^6"..coords)
		SetEntityAlpha(prop, 0)
		Wait(debugMode and 2000 or GetTiming(Config.Timings["OreRespawn"]))
		SetEntityAlpha(prop, 255)
	end

	Mining.Functions.setupMiningTarget(name, coords, prop, emptyProp, setReward, job)

	debugPrint("^5Debug^7: ^2Remaking Prop and Target^7: '^6"..name.."^7' ^2at coords^7: ^6"..coords)
end)

end

isMining = false
Mining.MineOre.pickaxe = function(data)
local Ped = PlayerPedId()
if isMining then return else isMining = true end -- Stop players from doubling up the event
-- Anim Loading
local dict, anim = "amb@world_human_hammering@male@base", "base"
loadDrillSound()
--Create Pickaxe and Attach
local PickAxe = makeProp({ prop = "prop_tool_pickaxe", coords = vec4(0,0,0,0)}, 0, 1)
DisableCamCollisionForObject(PickAxe)
DisableCamCollisionForEntity(PickAxe)
AttachEntityToEntity(PickAxe, Ped, GetPedBoneIndex(Ped, 57005), 0.09, -0.53, -0.22, 252.0, 180.0, 0.0, false, true, true, true, 0, true)
local IsDrilling = true
local rockcoords = GetEntityCoords(data.stone)
--Calculate if you're facing the stone--
lookEnt(data.stone)
if #(rockcoords - GetEntityCoords(Ped)) > 1.5 then TaskGoStraightToCoord(Ped, rockcoords, 0.5, 400, 0.0, 0) Wait(400) end
loadPtfxDict("core")
CreateThread(function()
while IsDrilling do
UseParticleFxAssetNextCall("core")
playAnim(dict, anim, -1, 2)
Wait(200)
local pickcoords = GetOffsetFromEntityInWorldCoords(PickAxe, -0.4, 0.0, 0.7)
local dust = StartNetworkedParticleFxNonLoopedAtCoord("ent_dst_rocks", pickcoords.x, pickcoords.y, pickcoords.z, 0.0, 0.0, 0.0, 0.4, 0.0, 0.0, 0.0)
Wait(350)
end
end)
if progressBar({label = locale("info", "drilling_ore"), time = GetTiming(Config.Timings["Pickaxe"]), cancel = true, icon = "pickaxe"}) then
TriggerServerEvent(getScript()..":Reward", { mine = true, cost = nil, setReward = data.setReward })
Mining.Other.stoneBreak(data.name, data.stone, data.coords, data.job, data.rot, data.emptyProp)
if Config.BreakTool and Config.BreakTool.Pickaxe then
breakTool({ item = "pickaxe", damage = math.random(2, 3) })
end
end
stopAnim(dict, anim)
destroyProp(PickAxe)
unloadPtfxDict("core")
unloadDrillSound()
StopSound(soundId)
IsDrilling, isMining = false, false
end

Mining.MineOre.miningDrill = function(data)
local Ped = PlayerPedId()
if isMining then return else isMining = true end -- Stop players from doubling up the event
if hasItem("drillbit", 1) then
-- Sounds & Anim loading
loadDrillSound()
local dict, anim = "anim@heists@fleeca_bank@drilling", "drill_straight_fail"
--Create Drill and Attach
local DrillObject = makeProp({ prop = "hei_prop_heist_drill", coords = vec4(0,0,0,0)}, 0, 1)
AttachEntityToEntity(DrillObject, Ped, GetPedBoneIndex(Ped, 57005), 0.14, 0, -0.01, 90.0, -90.0, 180.0, true, true, false, true, 1, true)
local IsDrilling = true
local rockcoords = GetEntityCoords(data.stone)
--Calculate if you're heading is within 20.0 degrees -
lookEnt(data.stone)
if #(rockcoords - GetEntityCoords(Ped)) > 1.5 then TaskGoStraightToCoord(Ped, rockcoords, 0.5, 400, 0.0, 0) Wait(400) end
playAnim(dict, anim, -1, 1)
Wait(200)
if Config.General.DrillSound then PlaySoundFromEntity(soundId, "Drill", DrillObject, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0) end
CreateThread(function() -- Dust/Debris Animation
loadPtfxDict("core")
while IsDrilling do
UseParticleFxAssetNextCall("core")
local dust = StartNetworkedParticleFxNonLoopedAtCoord("ent_dst_rocks", rockcoords.x, rockcoords.y, rockcoords.z, 0.0, 0.0, GetEntityHeading(Ped)-180.0, 1.0, 0.0, 0.0, 0.0)
Wait(600)
end
end)
if progressBar({label = locale("info", "drilling_ore"), time = GetTiming(Config.Timings["Mining"]), cancel = true, icon = "miningdrill"}) then
TriggerServerEvent(getScript()..":Reward", { mine = true, cost = nil, setReward = data.setReward })
Mining.Other.stoneBreak(data.name, data.stone, data.coords, data.job, data.rot, data.emptyProp)
if Config.BreakTool and Config.BreakTool.MiningDrill then
breakTool({ item = "miningdrill", damage = math.random(2, 3) })
end
if Config.BreakTool and Config.BreakTool.DrillBit then
breakTool({ item = "drillbit", damage = math.random(2, 3) })
else
--Destroy drill bit chances
local chance = math.random(1, 100)
debugPrint("Debug: crackStart chance: "..chance)
if chance >= 90 then
local breakId = GetSoundId()
PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
removeItem("drillbit", 1)
end
end
end
stopAnim(dict, anim)
unloadDrillSound()
StopSound(soundId)
destroyProp(DrillObject)
unloadPtfxDict("core")
IsDrilling, isMining = false, false
else
triggerNotify(nil, locale("error", "no_drillbit"), nil) isMining = false return
end
end

Mining.MineOre.miningLaser = function(data)
local Ped = PlayerPedId()
if isMining then return else isMining = true end -- Stop players from doubling up the event
-- Sounds & Anim Loading
RequestAmbientAudioBank("DLC_HEIST_BIOLAB_DELIVER_EMP_SOUNDS", 0)
RequestAmbientAudioBank("dlc_xm_silo_laser_hack_sounds", 0)
local dict, anim = "anim@heists@fleeca_bank@drilling", "drill_straight_fail"
--Create Drill and Attach
local DrillObject = makeProp({ prop = "ch_prop_laserdrill_01a", coords = vec4(0,0,0,0)}, 0, 1)
AttachEntityToEntity(DrillObject, Ped, GetPedBoneIndex(Ped, 57005), 0.14, 0, -0.01, 90.0, -90.0, 180.0, true, true, false, true, 1, true)
local IsDrilling = true
local rockcoords = GetEntityCoords(data.stone)
--Calculate if you're facing the stone--
lookEnt(data.stone)
--Activation noise & Anims
playAnim(dict, 'drill_straight_idle', -1, 1)
PlaySoundFromEntity(soundId, "Pass", DrillObject, "dlc_xm_silo_laser_hack_sounds", 1, 0)
Wait(1000)
playAnim(dict, anim, -1, 1)
PlaySoundFromEntity(soundId, "EMP_Vehicle_Hum", DrillObject, "DLC_HEIST_BIOLAB_DELIVER_EMP_SOUNDS", 1, 0) --Not sure about this sound, best one I could find as everything else wouldn't load
--Laser & Debris Effect
local lasercoords = GetOffsetFromEntityInWorldCoords(DrillObject, 0.0,-0.5, 0.02)
CreateThread(function()
loadPtfxDict("core")
while IsDrilling do
UseParticleFxAssetNextCall("core")
local laser = StartNetworkedParticleFxNonLoopedAtCoord("muz_railgun", lasercoords.x, lasercoords.y, lasercoords.z, 0, -10.0, GetEntityHeading(DrillObject)+270, 1.0, 0.0, 0.0, 0.0)
UseParticleFxAssetNextCall("core")
local dust = StartNetworkedParticleFxNonLoopedAtCoord("ent_dst_rocks", rockcoords.x, rockcoords.y, rockcoords.z, 0.0, 0.0, GetEntityHeading(Ped)-180.0, 1.0, 0.0, 0.0, 0.0)
Wait(60)
end
end)
if progressBar({label = locale("info", "drilling_ore"), time = GetTiming(Config.Timings["Laser"]), cancel = true, icon = "mininglaser"}) then
TriggerServerEvent(getScript()..":Reward", { mine = true, cost = nil, setReward = data.setReward })
Mining.Other.stoneBreak(data.name, data.stone, data.coords, data.job, data.rot, data.emptyProp)
if Config.BreakTool and Config.BreakTool.MiningLaser then
breakTool({ item = "mininglaser", damage = math.random(2, 3) })
end
end
IsDrilling, isMining = false, false
stopAnim(dict, anim)
ReleaseAmbientAudioBank("DLC_HEIST_BIOLAB_DELIVER_EMP_SOUNDS")
ReleaseAmbientAudioBank("dlc_xm_silo_laser_hack_sounds")
StopSound(soundId)
destroyProp(DrillObject)
unloadPtfxDict("core")
end


-- Cracking Command / Animations
Cracking = false
Mining.Other.crackStart = function(data)
local Ped = PlayerPedId()
if Cracking then return end
local cost = 1
if hasItem("stone", cost) then
if (Config.General.crackingRequiresDrillbit and not hasItem("drillbit", 1)) then
triggerNotify(nil, locale("error", "no_drillbit"), "error")
return
end
Cracking = true
-- Sounds & Anim Loading
local dict, anim ="amb@prop_human_parking_meter@male@idle_a", "idle_a"
loadDrillSound()
local benchcoords = GetOffsetFromEntityInWorldCoords(data.bench, 0.0, -0.2, 2.08)
--Calculate if you're facing the bench--
lookEnt(data.bench)
lockInv(true)
if #(benchcoords - GetEntityCoords(Ped)) > 1.5 then TaskGoStraightToCoord(Ped, benchcoords, 0.5, 400, 0.0, 0) Wait(400) end
local Rock = makeProp({ prop = "prop_rock_5_smash1", coords = vec4(benchcoords.x, benchcoords.y, benchcoords.z, 0)}, 0, 1)
if Config.General.DrillSound then
PlaySoundFromCoord(soundId, "Drill", benchcoords, "DLC_HEIST_FLEECA_SOUNDSET", 0, 4.5, 0)
end
loadPtfxDict("core")
CreateThread(function()
while Cracking do
UseParticleFxAssetNextCall("core")
local dust = StartNetworkedParticleFxNonLoopedAtCoord("ent_dst_rocks", benchcoords.x, benchcoords.y, benchcoords.z-0.9, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0)
Wait(100)
end
end)
playAnim(dict, anim, -1, 1)
--TaskPlayAnim(Ped, dict, anim, 3.0, 3.0, -1, 1, 0, false, false, false)
if progressBar({label = locale("info", "cracking_stone"), time = GetTiming(Config.Timings["Cracking"]), cancel = true, icon = "stone"}) then
TriggerServerEvent(getScript()..":Reward", { crack = true, cost = cost })
if Config.General.crackingRequiresDrillbit then
if Config.BreakTool and Config.BreakTool.DrillBit then
breakTool({ item = "drillbit", damage = math.random(2, 3) })
else
--Destroy drill bit chances
local chance = math.random(1, 100)
debugPrint("Debug: crackStart chance: "..chance)
if chance >= 90 then
local breakId = GetSoundId()
PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
removeItem("drillbit", 1)
end
end
end
end
StopAnimTask(Ped, dict, anim, 1.0)
unloadDrillSound()
StopSound(soundId)
unloadPtfxDict("core")
unloadAnimDict(dict)
destroyProp(Rock)
lockInv(false)
Cracking = false
else
triggerNotify(nil, locale("error", "no_stone"), 'error')
end
end


-- Washing Command / Animations
Washing = false
Mining.Other.washStart = function(data)
local Ped = PlayerPedId()
if Washing then return end
local cost = 1
if hasItem("stone", cost) then
Washing = true
lockInv(true)
--Create Rock and Attach
local Rock = makeProp({ prop = "prop_rock_5_smash1", coords = vec4(0, 0, 0, 0)}, 0, 1)
AttachEntityToEntity(Rock, Ped, GetPedBoneIndex(Ped, 60309), 0.1, 0.0, 0.05, 90.0, -90.0, 90.0, true, true, false, true, 1, true)
TaskStartScenarioInPlace(Ped, "PROP_HUMAN_BUM_BIN", 0, true)
local water
CreateThread(function()
Wait(3000)
loadPtfxDict("core")
while Washing do
UseParticleFxAssetNextCall("core")
water = StartNetworkedParticleFxLoopedOnEntity("water_splash_veh_out", Ped, 0.0, 1.0, -0.2, 0.0, 0.0, 0.0, 2.0, 0, 0, 0)
Wait(500)
end
end)
if progressBar({ label = locale("info", "washing_stone"), time = GetTiming(Config.Timings["Washing"]), cancel = true, icon = "stone" }) then
TriggerServerEvent(getScript()..":Reward", { wash = true, cost = cost })
end
lockInv(false)
StopParticleFxLooped(water, 0)
destroyProp(Rock)
unloadPtfxDict("core")
Washing = false
ClearPedTasks(Ped)
else
triggerNotify(nil, locale("error", "no_stone"), 'error')
end
end


-- Gold Panning Command / Animations
Panning = false
Mining.Other.panStart = function(data)
local Ped = PlayerPedId()
if Panning then return else Panning = true end
lockInv(true)
--Create Rock and Attach
local trayCoords = GetOffsetFromEntityInWorldCoords(Ped, 0.0, 0.5, -0.9)
Props[#Props+1] = makeProp({ coords = vec4(trayCoords.x, trayCoords.y, trayCoords.z+1.03, GetEntityHeading(Ped)), prop = "bkr_prop_meth_tray_01b"} , 1, 1)
CreateThread(function()
loadPtfxDict("core")
while Panning do
UseParticleFxAssetNextCall("core")
local water = StartNetworkedParticleFxLoopedOnEntity("water_splash_veh_out", Props[#Props], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0, 0, 0)
Wait(100)
end
end)
--Start Anim
TaskStartScenarioInPlace(Ped, "CODE_HUMAN_MEDIC_KNEEL", 0, true)
if progressBar({ label = locale("info", "goldpanning"), time = GetTiming(Config.Timings["Panning"]), cancel = true, icon = "goldpan" }) then
TriggerServerEvent(getScript()..":Reward", { pan = true, cost = nil })
if Config.BreakTool and Config.BreakTool.GoldPan then
breakTool({ item = "goldpan", damage = math.random(2, 3) })
end
end
ClearPedTasksImmediately(Ped)
destroyProp(Props[#Props])
unloadPtfxDict("core")
lockInv(false)
Panning = false
end

--Cutting Jewels
Mining.Menus.jewelCut = function(data)
loadDrillSound()
local Menu = {}
local table = {
{ header = locale("info", "gem_cut"), txt = locale("info", "gem_cut_section"), craftable = Crafting.GemCut, },
{ header = locale("info", "make_ring"), txt = locale("info", "ring_craft_section"), craftable = Crafting.RingCut, },
{ header = locale("info", "make_neck"), txt = locale("info", "neck_craft_section"), craftable = Crafting.NeckCut, },
{ header = locale("info", "make_ear"), txt = locale("info", "ear_craft_section"), craftable = Crafting.EarCut, },
}
for i = 1, #table do
Menu[#Menu+1] = {
header = table[i].header,
txt = table[i].txt,
onSelect = function()
craftingMenu({
craftable = table[i].craftable,
coords = GetEntityCoords(data.bench),
sound = {
soundId = soundId, audioName = "Drill", audioRef = "DLC_HEIST_FLEECA_SOUNDSET"
},
-- requiredItem = function()
-- if Config.BreakTool and Config.BreakTool.DrillBit then
-- breakTool({ item = "drillbit", damage = math.random(2, 3) })
-- else
-- --Destroy drill bit chances
-- if math.random(1, 100) >= 90 then
-- local breakId = GetSoundId()
-- PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
-- removeItem("drillbit", 1)
-- end
-- end
-- end,
onBack = function()
Mining.Menus.jewelCut(data)
end
})
end,
}
end
openMenu(Menu, {
header = locale("info", "craft_bench"),
headertxt = locale("info", "req_drill_bit"),
canClose = true,
})
end

Mining.Functions.removeJob = function()
for k in pairs(Targets) do removeZoneTarget(k) end
for _, v in pairs(Peds) do DeletePed(v) end
for i = 1, #Props do DeleteObject(Props[i]) end
for i = 1, #Blip do RemoveBlip(Blip[i]) end
end

onResourceStop(Mining.Functions.removeJob, true)
onPlayerLoaded(function() Wait(1000) Mining.Functions.checkForJob() end, true)

if Config.General.requiredJob then
RegisterNetEvent('QBCore:Client:OnJobUpdate', Mining.Functions.checkForJob)
end

-- 🔥 Anti Double Spawn Fix

CreateThread(function()
Wait(500)
if Mining and Mining.Functions and Mining.Functions.removeJob then
Mining.Functions.removeJob()
Wait(200)
Mining.Functions.checkForJob()
end
end)

AddEventHandler('onResourceStart', function(res)
if res == GetCurrentResourceName() then
Wait(500)
if Mining and Mining.Functions then
Mining.Functions.removeJob()
Wait(200)
Mining.Functions.checkForJob()
end
end
end)

-- server.lua
local function GetRandItemFromTable(table)
debugPrint("^5Debug^7: ^2Picking random item from table^7")
::start::
local randNum = math.random(1, 100)
local items = {}
for _, item in ipairs(table) do
if randNum <= tonumber(item.rarity) then
if doesItemExist(item.item) then
items[#items+1] = item.item
end
end
end
if #items == 0 then
goto start
end
local rand = math.random(1, #items)
local selectedItem = items[rand]
debugPrint("^5Debug^7: ^2Selected item ^7'^3"..selectedItem.."^7' - ^2rand^7: "..rand.." ^2length^7: "..#items)
return selectedItem
end

RegisterServerEvent(getScript()..":Reward", function(data)
local src = source
local amount = 1

if data.mine then

	local amount = GetTiming(Config.PoolAmounts.Mining.AmountPerSuccess)
	local carryCheck = canCarry({ [data.setReward] = amount }, src)

	if carryCheck[data.setReward] then
		addItem(data.setReward, amount,  nil, src)
	else
		triggerNotify(nil, locale("error", "full"), "error", src)
	end

elseif data.crack then

	local selectedItem = GetRandItemFromTable(Config.CrackPool)
	amount = GetTiming(Config.PoolAmounts.Cracking.AmountPerSuccess)

	local canCarryCheck = canCarry({ [selectedItem] = amount }, src)

	if selectedItem and canCarryCheck[selectedItem] then
		removeItem("stone", data.cost, src)
		addItem(selectedItem, amount, nil, src)
	else
		triggerNotify(nil, locale("error", "full"), "error", src)
	end

elseif data.wash then
	local rewards = {}

	-- Step 1: Determine all reward items
	for i = 1, GetTiming(Config.PoolAmounts.Washing.Successes) do
		local selectedItem = GetRandItemFromTable(Config.WashPool)
		local amount = GetTiming(Config.PoolAmounts.Washing.AmountPerSuccess)

		if selectedItem then
			rewards[selectedItem] = (rewards[selectedItem] or 0) + amount
		end
	end

	-- Step 2: Check if the player can carry all rewards
	local canCarryCheck = canCarry(rewards, src)

	local canCarryAll = true
	for item, _ in pairs(rewards) do
		if not canCarryCheck[item] then
			canCarryAll = false
			break
		end
	end

	-- Step 3: If they can carry, remove and reward. If not, notify.
	if canCarryAll then
		removeItem("stone", data.cost, src)

		for item, amount in pairs(rewards) do
			addItem(item, amount, nil, src)
		end
	else
		triggerNotify(nil, locale("error", "full"), "error", src)
	end

elseif data.pan then

	for i = 1, GetTiming(Config.PoolAmounts.Panning.Successes) do

		local selectedItem = GetRandItemFromTable(Config.PanPool)
		amount = GetTiming(Config.PoolAmounts.Panning.AmountPerSuccess)

		local canCarryCheck = canCarry({ [selectedItem] = amount }, src)

		if selectedItem and canCarryCheck[selectedItem] then
			addItem(selectedItem, amount, nil, src)
		else
			triggerNotify(nil, locale("error", "full"), "error", src)
		end
	end

end

end)

onResourceStart(function()
Wait(1000)
for id, info in pairs(Locations["Mines"]) do
if info.Enable then
if info.Store then
for i = 1, #info.Store do
registerShop("miningShop", Config.Items.label, Config.Items.items, nil, info.Store[i].coords.xyz)
end
end
if info.OreBuyer then
for i = 1, #info.OreBuyer do
local name = getScript()..":OreBuyer:"..id..":"..i
registerSellShop(name, info.OreBuyer[i].coords.xyz)
end
end
end

end

if Locations["JewelBuyer"] and Locations["JewelBuyer"].Enable then
	for i = 1, #Locations["JewelBuyer"].positions do
		local name = getScript()..":JewelBuyer:"..i
		registerSellShop(name, Locations["JewelBuyer"].positions[i].coords.xyz)
	end
end

--registerShop("miningShop", Config.Items.label, Config.Items.items)

for k in pairs(Selling) do
	if Selling[k].Items then
		for b in pairs(Selling[k].Items) do
			if not Items[b] then print("Selling: Missing Item from Items: '"..b.."'") end
		end
	else
		for l in pairs(Selling[k]) do
			if l ~= "Header" then
				for b in pairs(Selling[k][l].Items) do
					if not Items[b] then print("Selling: Missing Item from Items: '"..b.."'") end
				end
			end
		end
	end
end
for i = 1, #Config.CrackPool do if not Items[Config.CrackPool[i].item] then print("CrackPool: Missing Item from Items: '"..Config.CrackPool[i].item.."'") end end
for i = 1, #Config.WashPool do if not Items[Config.WashPool[i].item] then print("WashPool: Missing Item from Items: '"..Config.WashPool[i].item.."'") end end
for i = 1, #Config.PanPool do if not Items[Config.PanPool[i].item] then print("PanPool: Missing Item from Items: '"..Config.PanPool[i].item.."'") end end
for i = 1, #Config.Items.items do if not Items[Config.Items.items[i].name] then print("Shop: Missing Item from Items: '"..Config.Items.items[i].name.."'") end end
local itemcheck = {}
for _, v in pairs(Crafting) do
	if type(v) == "table" then
		for _, b in pairs(v.Recipes) do
			for k, l in pairs(b) do
				if k ~= "amount" then
					itemcheck[k] = {}
					for j in pairs(l) do
						itemcheck[j] = {}
					end
				end
			end
		end
	end
end
for k in pairs(itemcheck) do
	if not Items[k] then print("Crafting recipe couldn't find item '"..k.."' in the shared") end
end

end, true)

-- 🔥 Anti Duplicate Shop Register Fix

local alreadyRegistered = false

AddEventHandler('onResourceStart', function(res)
if res == GetCurrentResourceName() then
if alreadyRegistered then return end
alreadyRegistered = true
end
end)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions