298 lines
11 KiB
Lua
298 lines
11 KiB
Lua
-----------------For support, scripts, and more----------------
|
|
--------------- https://discord.gg/wasabiscripts -------------
|
|
---------------------------------------------------------------
|
|
local fishing = false
|
|
|
|
if Config.sellShop.enabled then
|
|
CreateThread(function()
|
|
local ped, textUI
|
|
CreateBlip(Config.sellShop.coords, 356, 1, Strings.sell_shop_blip, 0.80)
|
|
local point = lib.points.new({
|
|
coords = Config.sellShop.coords,
|
|
distance = 30
|
|
})
|
|
|
|
function point:nearby()
|
|
if self.currentDistance < self.distance then
|
|
if not ped then
|
|
lib.requestAnimDict('mini@strip_club@idles@bouncer@base', 100)
|
|
lib.requestModel(Config.sellShop.ped, 100)
|
|
ped = CreatePed(28, Config.sellShop.ped, Config.sellShop.coords.x, Config.sellShop.coords.y, Config.sellShop.coords.z, Config.sellShop.heading, false, false)
|
|
FreezeEntityPosition(ped, true)
|
|
SetEntityInvincible(ped, true)
|
|
SetBlockingOfNonTemporaryEvents(ped, true)
|
|
TaskPlayAnim(ped, 'mini@strip_club@idles@bouncer@base', 'base', 8.0, 0.0, -1, 1, 0, 0, 0, 0)
|
|
end
|
|
if self.currentDistance <= 1.8 then
|
|
if not textUI then
|
|
lib.showTextUI(Strings.sell_fish)
|
|
textUI = true
|
|
end
|
|
if IsControlJustReleased(0, 38) then
|
|
FishingSellItems()
|
|
end
|
|
elseif self.currentDistance >= 1.9 and textUI then
|
|
lib.hideTextUI()
|
|
textUI = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function point:onExit()
|
|
if ped then
|
|
local model = GetEntityModel(ped)
|
|
SetModelAsNoLongerNeeded(model)
|
|
DeletePed(ped)
|
|
SetPedAsNoLongerNeeded(ped)
|
|
RemoveAnimDict('mini@strip_club@idles@bouncer@base')
|
|
ped = nil
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Function to select bait using ox_lib menu
|
|
local function SelectBait()
|
|
local availableBaits = {}
|
|
|
|
-- Check all bait types
|
|
for _, bait in pairs(Config.bait.types) do
|
|
local hasItem = lib.callback.await('wasabi_fishing:checkItem', 100, bait.itemName)
|
|
if hasItem then
|
|
table.insert(availableBaits, bait)
|
|
end
|
|
end
|
|
|
|
if #availableBaits == 0 then
|
|
return nil
|
|
end
|
|
|
|
-- If only one bait type is available, use it directly
|
|
if #availableBaits == 1 then
|
|
return availableBaits[1]
|
|
end
|
|
|
|
-- Create menu options for bait selection
|
|
local options = {}
|
|
for i, bait in ipairs(availableBaits) do
|
|
table.insert(options, {
|
|
title = bait.label,
|
|
description = 'Catch Bonus: +' .. bait.catchBonus .. '% | Loss Chance: ' .. bait.loseChance .. '%',
|
|
icon = 'fish',
|
|
onSelect = function()
|
|
-- This will be handled by the menu's onClose callback
|
|
end
|
|
})
|
|
end
|
|
|
|
-- Create a variable to store the selected bait
|
|
local selectedIndex = 1
|
|
|
|
-- Register the menu
|
|
lib.registerMenu({
|
|
id = 'bait_selection_menu',
|
|
title = 'Select Fishing Bait',
|
|
position = 'top-right',
|
|
options = options,
|
|
onClose = function(selected)
|
|
selectedIndex = selected or 1
|
|
end
|
|
})
|
|
|
|
-- Show the menu
|
|
lib.showMenu('bait_selection_menu')
|
|
|
|
-- Wait for menu to close
|
|
while lib.getOpenMenu() == 'bait_selection_menu' do
|
|
Wait(100)
|
|
end
|
|
|
|
-- Return the selected bait
|
|
return availableBaits[selectedIndex]
|
|
end
|
|
|
|
-- Function to handle the fishing process
|
|
local function StartFishingProcess(selectedBait, waterLoc)
|
|
fishing = true
|
|
|
|
-- Create fishing rod prop
|
|
local model = `prop_fishing_rod_01`
|
|
lib.requestModel(model, 100)
|
|
local pole = CreateObject(model, GetEntityCoords(cache.ped), true, false, false)
|
|
AttachEntityToEntity(pole, cache.ped, GetPedBoneIndex(cache.ped, 18905), 0.1, 0.05, 0, 80.0, 120.0, 160.0, true, true, false, true, 1, true)
|
|
SetModelAsNoLongerNeeded(model)
|
|
|
|
-- Load animations
|
|
lib.requestAnimDict('mini@tennis', 100)
|
|
lib.requestAnimDict('amb@world_human_stand_fishing@idle_a', 100)
|
|
|
|
-- Initial casting animation
|
|
TaskPlayAnim(cache.ped, 'mini@tennis', 'forehand_ts_md_far', 1.0, -1.0, 1.0, 48, 0, 0, 0, 0)
|
|
Wait(3000)
|
|
TaskPlayAnim(cache.ped, 'amb@world_human_stand_fishing@idle_a', 'idle_c', 1.0, -1.0, 1.0, 11, 0, 0, 0, 0)
|
|
|
|
-- Main fishing loop
|
|
while fishing do
|
|
Wait(0)
|
|
local unarmed = `WEAPON_UNARMED`
|
|
SetCurrentPedWeapon(cache.ped, unarmed)
|
|
ShowHelp(Strings.intro_instruction)
|
|
DisableControlAction(0, 24, true)
|
|
|
|
-- Cast line
|
|
if IsDisabledControlJustReleased(0, 24) then
|
|
-- Casting animation
|
|
TaskPlayAnim(cache.ped, 'mini@tennis', 'forehand_ts_md_far', 1.0, -1.0, 1.0, 48, 0, 0, 0, 0)
|
|
TriggerEvent('wasabi_fishing:notify', Strings.waiting_bite, Strings.waiting_bite_desc, 'inform')
|
|
|
|
-- Wait for fish to bite
|
|
local waitTime = math.random(Config.timeForBite.min, Config.timeForBite.max)
|
|
Wait(waitTime)
|
|
|
|
-- Check if player is still fishing
|
|
if not fishing then
|
|
break
|
|
end
|
|
|
|
TriggerEvent('wasabi_fishing:notify', Strings.got_bite, Strings.got_bite_desc, 'inform')
|
|
Wait(1000)
|
|
|
|
-- Get fish data based on selected bait
|
|
local fishData = lib.callback.await('wasabi_fishing:getFishData', 100, selectedBait.itemName)
|
|
|
|
-- Skill check to catch fish
|
|
if lib.skillCheck(fishData.difficulty) then
|
|
ClearPedTasks(cache.ped)
|
|
TryFish(fishData)
|
|
TaskPlayAnim(cache.ped, 'amb@world_human_stand_fishing@idle_a', 'idle_c', 1.0, -1.0, 1.0, 11, 0, 0, 0, 0)
|
|
|
|
-- Check for bait loss
|
|
local loseChance = math.random(1,100)
|
|
if loseChance <= selectedBait.loseChance then
|
|
TriggerServerEvent('wasabi_fishing:loseBait', selectedBait.itemName)
|
|
TriggerEvent('wasabi_fishing:notify', Strings.bait_lost, Strings.bait_lost_desc, 'error')
|
|
|
|
-- Check if we still have this bait
|
|
local hasBait = lib.callback.await('wasabi_fishing:checkItem', 100, selectedBait.itemName)
|
|
if not hasBait then
|
|
-- Try to select a new bait
|
|
local newBait = SelectBait()
|
|
if newBait then
|
|
selectedBait = newBait
|
|
TriggerEvent('wasabi_fishing:notify', 'New Bait', 'Using ' .. selectedBait.label .. ' as bait', 'inform')
|
|
else
|
|
TriggerEvent('wasabi_fishing:notify', Strings.no_bait, Strings.no_bait_desc, 'error')
|
|
fishing = false
|
|
break
|
|
end
|
|
end
|
|
end
|
|
else
|
|
-- Failed to catch fish
|
|
local breakChance = math.random(1,100)
|
|
if breakChance < Config.fishingRod.breakChance then
|
|
TriggerServerEvent('wasabi_fishing:rodBroke')
|
|
TriggerEvent('wasabi_fishing:notify', Strings.rod_broke, Strings.rod_broke_desc, 'error')
|
|
ClearPedTasks(cache.ped)
|
|
fishing = false
|
|
break
|
|
end
|
|
TriggerEvent('wasabi_fishing:notify', Strings.failed_fish, Strings.failed_fish_desc, 'error')
|
|
end
|
|
elseif IsControlJustReleased(0, 194) then
|
|
-- Cancel fishing with backspace
|
|
ClearPedTasks(cache.ped)
|
|
TriggerEvent('wasabi_fishing:notify', 'Fishing Canceled', 'You stopped fishing', 'inform')
|
|
break
|
|
elseif #(GetEntityCoords(cache.ped) - waterLoc) > 30 then
|
|
-- Too far from water
|
|
TriggerEvent('wasabi_fishing:notify', 'Too Far', 'You moved too far from the water', 'error')
|
|
break
|
|
end
|
|
end
|
|
|
|
-- Clean up
|
|
fishing = false
|
|
DeleteObject(pole)
|
|
RemoveAnimDict('mini@tennis')
|
|
RemoveAnimDict('amb@world_human_stand_fishing@idle_a')
|
|
end
|
|
|
|
RegisterNetEvent('wasabi_fishing:startFishing', function()
|
|
-- Check if player is in a valid state to fish
|
|
if IsPedInAnyVehicle(cache.ped) or IsPedSwimming(cache.ped) then
|
|
TriggerEvent('wasabi_fishing:notify', Strings.cannot_perform, Strings.cannot_perform_desc, 'error')
|
|
return
|
|
end
|
|
|
|
-- Check if already fishing
|
|
if fishing then
|
|
TriggerEvent('wasabi_fishing:notify', 'Already Fishing', 'You are already fishing', 'error')
|
|
return
|
|
end
|
|
|
|
-- Check for water
|
|
local water, waterLoc = WaterCheck()
|
|
if not water then
|
|
TriggerEvent('wasabi_fishing:notify', Strings.no_water, Strings.no_water_desc, 'error')
|
|
return
|
|
end
|
|
|
|
-- Select bait
|
|
local selectedBait = SelectBait()
|
|
if not selectedBait then
|
|
TriggerEvent('wasabi_fishing:notify', Strings.no_bait, Strings.no_bait_desc, 'error')
|
|
return
|
|
end
|
|
|
|
-- Start fishing process
|
|
TriggerEvent('wasabi_fishing:notify', 'Bait Selected', 'Using ' .. selectedBait.label .. ' as bait', 'inform')
|
|
StartFishingProcess(selectedBait, waterLoc)
|
|
end)
|
|
|
|
-- Process fish with knife
|
|
RegisterNetEvent('wasabi_fishing:processFish', function(fishItem)
|
|
-- Check if player has knife
|
|
local hasKnife = lib.callback.await('wasabi_fishing:checkItem', 100, Config.processing.knifeItem)
|
|
if not hasKnife then
|
|
TriggerEvent('wasabi_fishing:notify', 'No Knife', 'You need a knife to process fish', 'error')
|
|
return
|
|
end
|
|
|
|
-- Start processing animation
|
|
local playerPed = cache.ped
|
|
|
|
lib.requestAnimDict('anim@amb@business@coc@coc_unpack_cut@', 100)
|
|
TaskPlayAnim(playerPed, 'anim@amb@business@coc@coc_unpack_cut@', 'fullcut_cycle_v6_cokecutter', 8.0, -8.0, -1, 1, 0, false, false, false)
|
|
|
|
-- Processing progress bar
|
|
if lib.progressBar({
|
|
duration = 5000,
|
|
label = 'Processing Fish',
|
|
useWhileDead = false,
|
|
canCancel = true,
|
|
disable = {
|
|
car = true,
|
|
move = true,
|
|
combat = true
|
|
},
|
|
anim = {
|
|
dict = 'anim@amb@business@coc@coc_unpack_cut@',
|
|
clip = 'fullcut_cycle_v6_cokecutter'
|
|
},
|
|
}) then
|
|
-- Success - server handles the actual item processing
|
|
TriggerServerEvent('wasabi_fishing:processItem', fishItem)
|
|
else
|
|
-- Cancelled
|
|
TriggerEvent('wasabi_fishing:notify', 'Canceled', 'Fish processing canceled', 'error')
|
|
end
|
|
|
|
ClearPedTasks(playerPed)
|
|
RemoveAnimDict('anim@amb@business@coc@coc_unpack_cut@')
|
|
end)
|
|
|
|
RegisterNetEvent('wasabi_fishing:interupt', function()
|
|
fishing = false
|
|
ClearPedTasks(cache.ped)
|
|
end)
|