diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/ESX/ox_inventory.txt b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/ESX/ox_inventory.txt new file mode 100644 index 000000000..00eee0e6e --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/ESX/ox_inventory.txt @@ -0,0 +1,42 @@ +-- Place in ox_inventory/data/items.lua + ['tuna'] = { + label = 'Tuna', + weight = 650, + stack = true, + close = false, + }, + + ['salmon'] = { + label = 'Salmon', + weight = 350, + stack = true, + close = false, + }, + + ['trout'] = { + label = 'Trout', + weight = 250, + stack = true, + close = false, + }, + + ['anchovy'] = { + label = 'Anchovy', + weight = 50, + stack = true, + close = false, + }, + + ['fishbait'] = { + label = 'Fish Bait', + weight = 50, + stack = true, + close = false, + }, + + ['fishingrod'] = { + label = 'Fishing Rod', + weight = 800, + stack = true, + close = true, + }, \ No newline at end of file diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/ESX/sql/wasabi_fishing_limit.sql b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/ESX/sql/wasabi_fishing_limit.sql new file mode 100644 index 000000000..277d33f78 --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/ESX/sql/wasabi_fishing_limit.sql @@ -0,0 +1,8 @@ +INSERT INTO `items` (`name`, `label`, `limit`) VALUES + ('fishingrod', 'Fishing Rod', 20), + ('fishbait', 'Fish Bait', 20), + ('anchovy', 'Anchovy', 20), + ('trout', 'Trout', 20), + ('salmon', 'Salmon', 20), + ('tuna', 'Tuna', 40) +; diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/ESX/sql/wasabi_fishing_weight.sql b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/ESX/sql/wasabi_fishing_weight.sql new file mode 100644 index 000000000..6cc2fb54e --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/ESX/sql/wasabi_fishing_weight.sql @@ -0,0 +1,8 @@ +INSERT INTO `items` (`name`, `label`, `weight`) VALUES + ('fishingrod', 'Fishing Rod', 20), + ('fishbait', 'Fish Bait', 20), + ('anchovy', 'Anchovy', 20), + ('trout', 'Trout', 20), + ('salmon', 'Salmon', 20), + ('tuna', 'Tuna', 40) +; diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/anchovy.png b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/anchovy.png new file mode 100644 index 000000000..29bf86ac4 Binary files /dev/null and b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/anchovy.png differ diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/fishbait.png b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/fishbait.png new file mode 100644 index 000000000..71e78ffa8 Binary files /dev/null and b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/fishbait.png differ diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/fishingrod.png b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/fishingrod.png new file mode 100644 index 000000000..d5f064bc1 Binary files /dev/null and b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/fishingrod.png differ diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/salmon.png b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/salmon.png new file mode 100644 index 000000000..3302e20e5 Binary files /dev/null and b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/salmon.png differ diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/trout.png b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/trout.png new file mode 100644 index 000000000..dbb24edcf Binary files /dev/null and b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/trout.png differ diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/tuna.png b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/tuna.png new file mode 100644 index 000000000..32e7f8f8d Binary files /dev/null and b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/InventoryImages/tuna.png differ diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/QBCore/items.txt b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/QBCore/items.txt new file mode 100644 index 000000000..4dca2d1ef --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/QBCore/items.txt @@ -0,0 +1,7 @@ +-- Add to qb-core/shared/items.lua + ['fishingrod'] = {['name'] = 'fishingrod', ['label'] = 'Fishing Rod', ['weight'] = 250, ['type'] = 'item', ['image'] = 'fishingrod.png', ['unique'] = false, ['useable'] = true, ['shouldClose'] = true, ['combinable'] = nil, ['description'] = 'Use this with bait to catch fish.'}, + ['fishbait'] = {['name'] = 'fishbait', ['label'] = 'Fishing Bait', ['weight'] = 5, ['type'] = 'item', ['image'] = 'fishbait.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = true, ['description'] = 'With a fishing rod this can catch some fish.'}, + ['anchovy'] = {['name'] = 'anchovy', ['label'] = 'Anchovy', ['weight'] = 35, ['type'] = 'item', ['image'] = 'anchovy.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = true, ['description'] = 'A breed of fish.'}, + ['trout'] = {['name'] = 'trout', ['label'] = 'Trout', ['weight'] = 85, ['type'] = 'item', ['image'] = 'trout.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = true, ['description'] = 'A breed of fish.'}, + ['salmon'] = {['name'] = 'salmon', ['label'] = 'Salmon', ['weight'] = 125, ['type'] = 'item', ['image'] = 'salmon.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = true, ['description'] = 'A breed of fish.'}, + ['tuna'] = {['name'] = 'tuna', ['label'] = 'Tuna', ['weight'] = 225, ['type'] = 'item', ['image'] = 'tuna.png', ['unique'] = false, ['useable'] = false, ['shouldClose'] = true, ['combinable'] = true, ['description'] = 'A breed of fish.'}, \ No newline at end of file diff --git a/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/QBCore/ox_inventory.txt b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/QBCore/ox_inventory.txt new file mode 100644 index 000000000..00eee0e6e --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/Inventory_Items/QBCore/ox_inventory.txt @@ -0,0 +1,42 @@ +-- Place in ox_inventory/data/items.lua + ['tuna'] = { + label = 'Tuna', + weight = 650, + stack = true, + close = false, + }, + + ['salmon'] = { + label = 'Salmon', + weight = 350, + stack = true, + close = false, + }, + + ['trout'] = { + label = 'Trout', + weight = 250, + stack = true, + close = false, + }, + + ['anchovy'] = { + label = 'Anchovy', + weight = 50, + stack = true, + close = false, + }, + + ['fishbait'] = { + label = 'Fish Bait', + weight = 50, + stack = true, + close = false, + }, + + ['fishingrod'] = { + label = 'Fishing Rod', + weight = 800, + stack = true, + close = true, + }, \ No newline at end of file diff --git a/resources/[jobs]/[civ]/wasabi_fishing/README.md b/resources/[jobs]/[civ]/wasabi_fishing/README.md new file mode 100644 index 000000000..357874a31 --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/README.md @@ -0,0 +1,44 @@ +# wasabi_fishing + +This resource was created as a free interactive fishing script for ESX/QBCore servers. + +## Features +- Out of the box compatible with ESX and QBCore +- Optimized 0.00ms usage on idle +- Skill-check based success +- Full animations and props +- Chance of fishing rod breaking upon failing skill-check(Can be changed in config) +- Configurable random wait time for getting bite on line +- Configurable fishing rewards(4 by default included) +- Configurable prices to sell fishing rewards +- Configurable skill-check difficulty per fishing reward +- Ability to fish from boat, pier, or anywhere with a body of water +- No job requirement +- Fully configurable fish buyer to sell fish + +## Dependencies +- es_extended OR qb-core +- ox_lib - https://github.com/overextended/ox_lib/releases + + +## Installation + +- Make sure you have dependencies + +- Make sure items are added to server(Check `Inventory_Items` directory for images/examples + +- Put script in your `resources` directory + +- Add `ensure wasabi_fishing` in your `server.cfg` (*After* dependencies) + +### Extra Information +- Make sure `ox_lib` starts before `wasabi_fishing` +- Inventory images included in the `Inventory_Items/InventoryImages` directory +- You must add the item `fishingrod` and `fishbait` to one of your in-game shops or have a place for your players to obtain. + +## Preview +https://www.youtube.com/watch?v=kLLPGJIK3Q0 + + +# Support +![Discord Banner 2](https://discordapp.com/api/guilds/1025493337031049358/widget.png?style=banner2) diff --git a/resources/[jobs]/[civ]/wasabi_fishing/bridge/esx/client.lua b/resources/[jobs]/[civ]/wasabi_fishing/bridge/esx/client.lua new file mode 100644 index 000000000..b03910a9f --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/bridge/esx/client.lua @@ -0,0 +1,65 @@ +-----------------For support, scripts, and more---------------- +--------------- https://discord.gg/wasabiscripts ------------- +--------------------------------------------------------------- +if GetResourceState('es_extended') ~= 'started' then return end +ESX = exports['es_extended']:getSharedObject() +Framework, PlayerLoaded, PlayerData = 'esx', nil, {} + +RegisterNetEvent('esx:playerLoaded', function(xPlayer) + PlayerData = xPlayer + PlayerLoaded = true +end) + +RegisterNetEvent('esx:onPlayerSpawn', function() + TriggerEvent('wasabi_fishing:onPlayerSpawn') +end) + +AddEventHandler('esx:onPlayerDeath', function(data) + TriggerEvent('wasabi_fishing:onPlayerDeath') +end) + +RegisterNetEvent('esx:onPlayerLogout', function() + table.wipe(PlayerData) + PlayerLoaded = false +end) + +RegisterNetEvent('esx:setJob', function(job) + PlayerData.job = job +end) + +AddEventHandler('onResourceStart', function(resourceName) + if GetCurrentResourceName() ~= resourceName or not ESX.PlayerLoaded then return end + PlayerData = ESX.GetPlayerData() + PlayerLoaded = true +end) + +AddEventHandler('esx:setPlayerData', function(key, value) + if GetInvokingResource() ~= 'es_extended' then return end + PlayerData[key] = value +end) + +function HasGroup(filter) + local type = type(filter) + + if type == 'string' then + if PlayerData.job.name == filter then + return PlayerData.job.name, PlayerData.job.grade + end + else + local tabletype = table.type(filter) + + if tabletype == 'hash' then + local grade = filter[PlayerData.job.name] + + if grade and grade <= PlayerData.job.grade then + return PlayerData.job.name, PlayerData.job.grade + end + elseif tabletype == 'array' then + for i = 1, #filter do + if PlayerData.job.name == filter[i] then + return PlayerData.job.name, PlayerData.job.grade + end + end + end + end +end diff --git a/resources/[jobs]/[civ]/wasabi_fishing/bridge/esx/server.lua b/resources/[jobs]/[civ]/wasabi_fishing/bridge/esx/server.lua new file mode 100644 index 000000000..a345578a1 --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/bridge/esx/server.lua @@ -0,0 +1,85 @@ +if GetResourceState('es_extended') ~= 'started' then return end +ESX = exports['es_extended']:getSharedObject() +Framework = 'esx' + +function GetPlayer(source) + return ESX.GetPlayerFromId(source) +end + +function KickPlayer(source, reason) + local player = GetPlayer(source) + return player.kick(reason) +end + +function HasGroup(source, filter) + local player = GetPlayer(source) + local type = type(filter) + + if type == 'string' then + if player.job.name == filter then + return player.job.name, player.job.grade + end + else + local tabletype = table.type(filter) + + if tabletype == 'hash' then + local grade = filter[player.job.name] + + if grade and grade <= player.job.grade then + return player.job.name, player.job.grade + end + elseif tabletype == 'array' then + for i = 1, #filter do + if player.job.name == filter[i] then + return player.job.name, player.job.grade + end + end + end + end +end + +function GetIdentifier(source) + local xPlayer = ESX.GetPlayerFromId(source) + return xPlayer.identifier +end + +function GetName(source) + local xPlayer = ESX.GetPlayerFromId(source) + return xPlayer.getName() +end + +function RegisterUsableItem(item, cb) + ESX.RegisterUsableItem(item, cb) +end + +function HasItem(source, item) + local player = GetPlayer(source) + local item = player.getInventoryItem(item) + if item ~= nil then + return item.count + else + return 0 + end +end + +function AddItem(source, item, count, slot, metadata) + local player = GetPlayer(source) + return player.addInventoryItem(item, count, metadata, slot) +end + +function RemoveItem(source, item, count, slot, metadata) + local player = GetPlayer(source) + player.removeInventoryItem(item, count, metadata, slot) +end + +function AddMoney(source, type, amount) + if type == 'cash' then type = 'money' end + local player = GetPlayer(source) + player.addAccountMoney(type, amount) +end + +function RemoveMoney(source, type, amount) + if type == 'cash' then type = 'money' end + local player = GetPlayer(source) + player.removeAccountMoney(type, amount) +end diff --git a/resources/[jobs]/[civ]/wasabi_fishing/bridge/qb/client.lua b/resources/[jobs]/[civ]/wasabi_fishing/bridge/qb/client.lua new file mode 100644 index 000000000..b94470352 --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/bridge/qb/client.lua @@ -0,0 +1,78 @@ +if GetResourceState('qb-core') ~= 'started' then return end +QBCore = exports['qb-core']:GetCoreObject() +Framework, PlayerLoaded, PlayerData = 'qb', nil, {} + +AddStateBagChangeHandler('isLoggedIn', '', function(_bagName, _key, value, _reserved, _replicated) + if value then + PlayerData = QBCore.Functions.GetPlayerData() + else + table.wipe(PlayerData) + end + PlayerLoaded = value +end) + +AddEventHandler('onResourceStart', function(resourceName) + if GetCurrentResourceName() ~= resourceName or not LocalPlayer.state.isLoggedIn then return end + PlayerData = QBCore.Functions.GetPlayerData() + PlayerLoaded = true +end) + + +AddEventHandler('gameEventTriggered', function(event, data) + if event ~= 'CEventNetworkEntityDamage' then return end + local victim, victimDied = data[1], data[4] + if not IsPedAPlayer(victim) then return end + local player = PlayerId() + if victimDied and NetworkGetPlayerIndexFromPed(victim) == player and (IsPedDeadOrDying(victim, true) or IsPedFatallyInjured(victim)) then + TriggerEvent('wasabi_fishing:onPlayerDeath') + end +end) + +RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() + TriggerEvent('wasabi_fishing:onPlayerSpawn') +end) + +RegisterNetEvent('QBCore:Player:SetPlayerData', function(newPlayerData) + if source ~= '' and GetInvokingResource() ~= 'qb-core' then return end + PlayerData = newPlayerData +end) + +function HasGroup(filter) + local groups = { 'job', 'gang' } + local type = type(filter) + + if type == 'string' then + for i = 1, #groups do + local data = PlayerData[groups[i]] + + if data.name == filter then + return data.name, data.grade.level + end + end + else + local tabletype = table.type(filter) + + if tabletype == 'hash' then + for i = 1, #groups do + local data = PlayerData[groups[i]] + local grade = filter[data.name] + + if grade and grade <= data.grade.level then + return data.name, data.grade.level + end + end + elseif tabletype == 'array' then + for i = 1, #filter do + local group = filter[i] + + for j = 1, #groups do + local data = PlayerData[groups[j]] + + if data.name == group then + return data.name, data.grade.level + end + end + end + end + end +end diff --git a/resources/[jobs]/[civ]/wasabi_fishing/bridge/qb/server.lua b/resources/[jobs]/[civ]/wasabi_fishing/bridge/qb/server.lua new file mode 100644 index 000000000..8d272bd35 --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/bridge/qb/server.lua @@ -0,0 +1,98 @@ +if GetResourceState('qb-core') ~= 'started' then return end +QBCore = exports['qb-core']:GetCoreObject() +Framework = 'qb' + +function GetPlayer(source) + return QBCore.Functions.GetPlayer(source) +end + +function KickPlayer(source, reason) + QBCore.Functions.Kick(source, reason, true, true) +end + +function HasGroup(source, filter) + local groups = { 'job', 'gang' } + local player = GetPlayer(source) + local type = type(filter) + + if type == 'string' then + for i = 1, #groups do + local data = player.PlayerData[groups[i]] + + if data.name == filter then + return data.name, data.grade.level + end + end + else + local tabletype = table.type(filter) + + if tabletype == 'hash' then + for i = 1, #groups do + local data = player.PlayerData[groups[i]] + local grade = filter[data.name] + + if grade and grade <= data.grade.level then + return data.name, data.grade.level + end + end + elseif tabletype == 'array' then + for i = 1, #filter do + local group = filter[i] + + for j = 1, #groups do + local data = player.PlayerData[groups[j]] + + if data.name == group then + return data.name, data.grade.level + end + end + end + end + end +end + +function GetIdentifier(source) + local xPlayer = QBCore.Functions.GetPlayer(source) + return xPlayer.PlayerData.citizenid +end + +function GetName(source) + local xPlayer = QBCore.Functions.GetPlayer(source) + return xPlayer.PlayerData.charinfo.firstname..' '..xPlayer.PlayerData.charinfo.lastname +end + +function RegisterUsableItem(item, cb) + QBCore.Functions.CreateUseableItem(item, cb) +end + +function HasItem(source, item) + local player = GetPlayer(source) + local item = player.Functions.GetItemByName(item) + if GetResourceState('ox_inventory') == 'started' then + return item?.count or 0 + else + return item?.amount or 0 + end +end + +function AddItem(source, item, count, slot, metadata) + local player = GetPlayer(source) + return player.Functions.AddItem(item, count, slot, metadata) +end + +function RemoveItem(source, item, count, slot, metadata) + local player = GetPlayer(source) + player.Functions.RemoveItem(item, count, slot, metadata) +end + +function AddMoney(source, type, amount) + if type == 'money' then type = 'cash' end + local player = GetPlayer(source) + player.Functions.AddMoney(type, amount) +end + +function RemoveMoney(source, type, amount) + if type == 'money' then type = 'cash' end + local player = GetPlayer(source) + player.Functions.RemoveMoney(type, amount) +end diff --git a/resources/[jobs]/[civ]/wasabi_fishing/client/client.lua b/resources/[jobs]/[civ]/wasabi_fishing/client/client.lua new file mode 100644 index 000000000..9a28b18e8 --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/client/client.lua @@ -0,0 +1,303 @@ +-----------------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 from available options +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 a menu for bait selection + local options = {} + for _, bait in pairs(availableBaits) do + table.insert(options, { + title = bait.label, + description = 'Use as fishing bait', + metadata = { + {label = 'Catch Bonus', value = '+' .. bait.catchBonus .. '%'}, + {label = 'Loss Chance', value = bait.loseChance .. '%'} + } + }) + end + + local selectedIndex = lib.showContext('bait_selection_menu', { + id = 'bait_selection_menu', + title = 'Select Fishing Bait', + options = options + }) + + if selectedIndex then + return availableBaits[selectedIndex] + else + return nil + end +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 bait + local hasBait = lib.callback.await('wasabi_fishing:checkItem', 100, selectedBait.itemName) + if not hasBait then + TriggerEvent('wasabi_fishing:notify', Strings.no_more_bait, Strings.no_more_bait_desc, 'error') + + -- Try to select a new bait + local newBait = SelectBait() + if newBait then + selectedBait = newBait + TriggerEvent('wasabi_fishing:notify', Strings.new_bait, string.format(Strings.new_bait_desc, selectedBait.label), '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', Strings.fishing_canceled, Strings.fishing_canceled_desc, 'inform') + break + elseif #(GetEntityCoords(cache.ped) - waterLoc) > 30 then + -- Too far from water + TriggerEvent('wasabi_fishing:notify', Strings.too_far, Strings.too_far_desc, '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', Strings.already_fishing, Strings.already_fishing_desc, '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', Strings.bait_selected, string.format(Strings.bait_selected_desc, selectedBait.label), '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', Strings.no_knife, Strings.no_knife_desc, 'error') + return + end + + -- Find processing data for this fish + local processData = nil + for _, data in pairs(Config.processing.products) do + if data.sourceItem == fishItem then + processData = data + break + end + end + + if not processData then + TriggerEvent('wasabi_fishing:notify', Strings.cannot_process, Strings.cannot_process_desc, 'error') + return + end + + -- Start processing animation + local playerPed = cache.ped + local coords = GetEntityCoords(playerPed) + + 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 = Strings.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', Strings.canceled, Strings.canceled_desc, 'error') + end + + ClearPedTasks(playerPed) + RemoveAnimDict('anim@amb@business@coc@coc_unpack_cut@') +end) + +RegisterNetEvent('wasabi_fishing:interupt', function() + fishing = false + ClearPedTasks(cache.ped) +end) + diff --git a/resources/[jobs]/[civ]/wasabi_fishing/client/functions.lua b/resources/[jobs]/[civ]/wasabi_fishing/client/functions.lua new file mode 100644 index 000000000..351213a56 --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/client/functions.lua @@ -0,0 +1,36 @@ +-----------------For support, scripts, and more---------------- +--------------- https://discord.gg/wasabiscripts ------------- +--------------------------------------------------------------- + +ShowHelp = function(msg) + BeginTextCommandDisplayHelp('STRING') + AddTextComponentSubstringPlayerName(msg) + EndTextCommandDisplayHelp(0, false, true, -1) +end + +WaterCheck = function() + local headPos = GetPedBoneCoords(cache.ped, 31086, 0.0, 0.0, 0.0) + local offsetPos = GetOffsetFromEntityInWorldCoords(cache.ped, 0.0, 50.0, -25.0) + local water, waterPos = TestProbeAgainstWater(headPos.x, headPos.y, headPos.z, offsetPos.x, offsetPos.y, offsetPos.z) + return water, waterPos +end + +CreateBlip = function(coords, sprite, colour, text, scale) + local blip = AddBlipForCoord(coords) + SetBlipSprite(blip, sprite) + SetBlipColour(blip, colour) + SetBlipAsShortRange(blip, true) + SetBlipScale(blip, scale) + AddTextEntry(text, text) + BeginTextCommandSetBlipName(text) + EndTextCommandSetBlipName(blip) + return blip +end + +TryFish = function(data) + TriggerServerEvent('wasabi_fishing:tryFish', data) +end + +FishingSellItems = function() + TriggerServerEvent('wasabi_fishing:sellFish') +end diff --git a/resources/[jobs]/[civ]/wasabi_fishing/configuration/config.lua b/resources/[jobs]/[civ]/wasabi_fishing/configuration/config.lua new file mode 100644 index 000000000..0cf64147c --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/configuration/config.lua @@ -0,0 +1,146 @@ +-----------------For support, scripts, and more---------------- +--------------- https://discord.gg/wasabiscripts ------------- +--------------------------------------------------------------- + +local seconds, minutes = 1000, 60000 +Config = {} + +Config.checkForUpdates = true -- Check for updates? +Config.oldESX = false -- Nothing to do with qb / Essentially when set to true it disables the check of if player can carry item + +Config.sellShop = { + enabled = true, + coords = vec3(-1612.19, -989.18, 13.01-0.9), -- X, Y, Z Coords of where fish buyer will spawn + heading = 45.3, -- Heading of fish buyer ped + ped = 'cs_old_man2' -- Ped name here +} + +Config.bait = { + types = { + { + itemName = 'fishbait', + label = 'Standard Bait', + loseChance = 65, + catchBonus = 0 -- base chance + }, + { + itemName = 'worm_bait', + label = 'Worm', + loseChance = 50, + catchBonus = 10 -- 10% better catch chance + }, + { + itemName = 'bread_bait', + label = 'Bread', + loseChance = 75, + catchBonus = 5 -- 5% better catch chance + }, + { + itemName = 'artificial_lure', + label = 'Artificial Lure', + loseChance = 30, -- harder to lose + catchBonus = 15 -- 15% better catch chance + }, + { + itemName = 'young_salmon', + label = 'Young Salmon', + loseChance = 60, + catchBonus = 20, -- 20% better catch chance + exclusive = {'pufferfish'} -- can only catch pufferfish with this + } + }, + defaultBait = 'fishbait' -- Default bait item name +} + +Config.processing = { + knifeItem = 'weapon_knife', + products = { + { + sourceItem = 'tuna', + yield = { + { item = 'fish_fillet', amount = {3, 5} }, + { item = 'caviar', chance = 5 } -- 5% chance + } + }, + { + sourceItem = 'salmon', + yield = { + { item = 'fish_fillet', amount = {2, 4} }, + { item = 'caviar', chance = 15 } -- 15% chance + } + }, + { + sourceItem = 'trout', + yield = { + { item = 'fish_fillet', amount = {1, 3} }, + { item = 'caviar', chance = 3 } -- 3% chance + } + }, + { + sourceItem = 'anchovy', + yield = { + { item = 'fish_fillet', amount = {1, 2} } + -- No caviar from anchovy + } + }, + { + sourceItem = 'young_salmon', + yield = { + { item = 'fish_fillet', amount = {1, 1} } + -- No caviar from young salmon + } + }, + { + sourceItem = 'pufferfish', + yield = { + { item = 'fish_fillet', amount = {1, 3} }, + { item = 'caviar', chance = 25 } -- 25% chance + } + } + } +} + +Config.fish = { + { item = 'tuna', label = 'Tuna', price = {300, 550}, difficulty = {'medium', 'easy', 'easy'} }, + { item = 'salmon', label = 'Salmon', price = {235, 300}, difficulty = {'medium', 'easy'} }, + { item = 'trout', label = 'Trout', price = {190, 235}, difficulty = {'easy', 'easy'} }, + { item = 'anchovy', label = 'Anchovy', price = {100, 190}, difficulty = {'easy'} }, + { item = 'young_salmon', label = 'Young Salmon', price = {50, 100}, difficulty = {'easy'} }, + { item = 'pufferfish', label = 'Pufferfish', price = {500, 800}, difficulty = {'hard', 'hard', 'medium'} }, +} + +-- Add prices for processed items +Config.processedItems = { + { item = 'fish_fillet', label = 'Fish Fillet', price = {50, 100} }, + { item = 'caviar', label = 'Caviar', price = {300, 500} }, +} + + +Config.fishingRod = { + itemName = 'fishingrod', -- Item name of fishing rod + breakChance = 25 --Chance of breaking pole when failing skillbar (Setting to 0 means never break) +} + +Config.timeForBite = { -- Set min and max random range of time it takes for fish to be on the line. + min = 2 * seconds, + max = 20 * seconds +} + + +RegisterNetEvent('wasabi_fishing:notify') +AddEventHandler('wasabi_fishing:notify', function(title, message, msgType) + -- Place notification system info here, ex: exports['mythic_notify']:SendAlert('inform', message) + if not msgType then + lib.notify({ + title = title, + description = message, + type = 'inform' + }) + else + lib.notify({ + title = title, + description = message, + type = msgType + }) + end +end) diff --git a/resources/[jobs]/[civ]/wasabi_fishing/configuration/strings.lua b/resources/[jobs]/[civ]/wasabi_fishing/configuration/strings.lua new file mode 100644 index 000000000..c2d373a03 --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/configuration/strings.lua @@ -0,0 +1,38 @@ +-----------------For support, scripts, and more---------------- +--------------- https://discord.gg/wasabiscripts ------------- +--------------------------------------------------------------- +Strings = { + intro_instruction = 'Press ~INPUT_ATTACK~ to cast line, ~INPUT_FRONTEND_RRIGHT~ to cancel.', + rod_broke = 'Rod Snapped', + rod_broke_desc = 'You pulled to hard and your fishing rod snapped!', + cannot_perform = 'Action Incomplete', + cannot_perform_desc = 'You cannot do this right now.', + failed = 'Failed', + failed_fish = 'You failed to catch fish!', + no_water = 'No Water', + no_water_desc = 'You are not facing any water.', + no_bait = 'Missing Bait', + no_bait_desc = 'You don\'t have fishing bait.', + bait_lost = 'Bait Lost', + bait_lost_desc = 'Fishing bait was lost.', + fish_success = 'Caught Fish', + fish_success_desc = 'You caught a %s!', + sell_shop_blip = 'Fish Market', + sell_fish = '[E] - Sell Fish', + kicked = 'Nice try, please do not attempt to exploit!', + sold_for = 'Sold Fish', + sold_for_desc = 'You sold %sx %s for $%s', + got_bite = 'Bite Detected', + got_bite_desc = 'Your pole has a fish on the line, get ready!', + waiting_bite = 'Awaiting Bite', + waiting_bite_desc = 'Please wait for a fish to bite your hook.', + cannot_carry = 'Cannot Carry', + cannot_carry_desc = 'You cannot carry reward!' + Strings.no_knife = 'No Knife' + Strings.no_knife_desc = 'You need a knife to process this fish.' + Strings.processing_success = 'Fish Processed' + Strings.processing_success_desc = 'You obtained %d %s from processing the fish.' + Strings.caviar_found = 'Caviar Found!' + Strings.caviar_found_desc = 'You found some valuable caviar while processing the fish!' + +} \ No newline at end of file diff --git a/resources/[jobs]/[civ]/wasabi_fishing/fxmanifest.lua b/resources/[jobs]/[civ]/wasabi_fishing/fxmanifest.lua new file mode 100644 index 000000000..9d4b7aa4c --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/fxmanifest.lua @@ -0,0 +1,19 @@ +-----------------For support, scripts, and more---------------- +--------------- https://discord.gg/wasabiscripts ------------- +--------------------------------------------------------------- + +fx_version 'cerulean' +game 'gta5' +lua54 'yes' + +version '2.0.7' +author 'wasabirobby' +description 'Wasabi ESX/QBCore Skill Based Fishing' + +shared_scripts { '@ox_lib/init.lua', 'configuration/*.lua' } + +client_scripts { 'bridge/**/client.lua', 'client/*.lua' } + +server_scripts { 'bridge/**/server.lua', 'server/*.lua' } + +dependencies { 'ox_lib' } diff --git a/resources/[jobs]/[civ]/wasabi_fishing/server/server.lua b/resources/[jobs]/[civ]/wasabi_fishing/server/server.lua new file mode 100644 index 000000000..8640b63b8 --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/server/server.lua @@ -0,0 +1,241 @@ +-----------------For support, scripts, and more---------------- +--------------- https://discord.gg/wasabiscripts ------------- +--------------------------------------------------------------- +local addCommas = function(n) + return tostring(math.floor(n)):reverse():gsub("(%d%d%d)","%1,") + :gsub(",(%-?)$","%1"):reverse() +end + +lib.callback.register('wasabi_fishing:checkItem', function(source, itemname) + local item = HasItem(source, itemname) + if item >= 1 then + return true + else + return false + end +end) + +lib.callback.register('wasabi_fishing:getFishData', function(source) + local data = Config.fish[math.random(#Config.fish)] + return data +end) + +RegisterNetEvent('wasabi_fishing:rodBroke', function() + RemoveItem(source, Config.fishingRod.itemName, 1) + TriggerClientEvent('wasabi_fishing:interupt', source) +end) + +RegisterNetEvent('wasabi_fishing:tryFish', function(data) + local xPole = HasItem(source, Config.fishingRod.itemName) + local xBait = HasItem(source, Config.bait.itemName) + if xPole > 0 and xBait > 0 then + local chance = math.random(1,100) + if chance <= Config.bait.loseChance then + RemoveItem(source, Config.bait.itemName, 1) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.bait_lost, Strings.bait_lost_desc, 'error') + end + if Framework == 'esx' and not Config.oldESX then + local player = GetPlayer(source) + if player.canCarryItem(data.item, 1) then + AddItem(source, data.item, 1) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.fish_success, string.format(Strings.fish_success_desc, data.label), 'success') + else + TriggerClientEvent('wasabi_fishing:notify', source, Strings.cannot_carry, Strings.cannot_carry_desc, 'error') + end + else + AddItem(source, data.item, 1) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.fish_success, string.format(Strings.fish_success_desc, data.label), 'success') + end + elseif xPole > 0 and xBait < 1 then + TriggerClientEvent('wasabi_fishing:interupt', source) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.no_bait, Strings.no_bait_desc, 'error') + elseif xPole < 1 then + KickPlayer(source, Strings.kicked) + end +end) + +RegisterNetEvent('wasabi_fishing:sellFish', function() + local playerPed = GetPlayerPed(source) + local playerCoord = GetEntityCoords(playerPed) + local distance = #(playerCoord - Config.sellShop.coords) + if distance == nil then + KickPlayer(source, Strings.kicked) + return + end + if distance > 3 then + KickPlayer(source, Strings.kicked) + return + end + for i=1, #Config.fish do + if HasItem(source, Config.fish[i].item) > 0 then + local rewardAmount = 0 + for j=1, HasItem(source, Config.fish[i].item) do + rewardAmount = rewardAmount + math.random(Config.fish[i].price[1], Config.fish[i].price[2]) + end + if rewardAmount > 0 then + AddMoney(source, 'money', rewardAmount) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.sold_for, (Strings.sold_for_desc):format(HasItem(source, Config.fish[i].item), Config.fish[i].label, addCommas(rewardAmount)), 'success') + RemoveItem(source, Config.fish[i].item, HasItem(source, Config.fish[i].item)) + end + end + end +end) + +RegisterUsableItem(Config.fishingRod.itemName, function(source) + TriggerClientEvent('wasabi_fishing:startFishing', source) +end) +-- Register usable items for all fish types for processing +for _, fish in pairs(Config.processing.products) do + RegisterUsableItem(fish.sourceItem, function(source) + local hasKnife = HasItem(source, Config.processing.knifeItem) + if hasKnife > 0 then + ProcessFish(source, fish) + else + TriggerClientEvent('wasabi_fishing:notify', source, Strings.no_knife, Strings.no_knife_desc, 'error') + end + end) +end + +-- Function to process fish +function ProcessFish(source, fishData) + -- Remove the fish + RemoveItem(source, fishData.sourceItem, 1) + + -- Add fish fillets + local filletYield = fishData.yield[1] + local filletAmount = math.random(filletYield.amount[1], filletYield.amount[2]) + + if Framework == 'esx' and not Config.oldESX then + local player = GetPlayer(source) + if player.canCarryItem(filletYield.item, filletAmount) then + AddItem(source, filletYield.item, filletAmount) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.processing_success, + string.format(Strings.processing_success_desc, filletAmount, GetItemLabel(filletYield.item)), 'success') + else + TriggerClientEvent('wasabi_fishing:notify', source, Strings.cannot_carry, Strings.cannot_carry_desc, 'error') + -- Give back the fish if they can't carry the fillets + AddItem(source, fishData.sourceItem, 1) + return + end + else + AddItem(source, filletYield.item, filletAmount) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.processing_success, + string.format(Strings.processing_success_desc, filletAmount, GetItemLabel(filletYield.item)), 'success') + end + + -- Check for caviar + for i=2, #fishData.yield do + local extraYield = fishData.yield[i] + if extraYield.item == 'caviar' and extraYield.chance then + local chance = math.random(1, 100) + if chance <= extraYield.chance then + if Framework == 'esx' and not Config.oldESX then + local player = GetPlayer(source) + if player.canCarryItem(extraYield.item, 1) then + AddItem(source, extraYield.item, 1) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.caviar_found, Strings.caviar_found_desc, 'success') + end + else + AddItem(source, extraYield.item, 1) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.caviar_found, Strings.caviar_found_desc, 'success') + end + end + end + end +end + +-- Modify the sellFish event to include processed items +RegisterNetEvent('wasabi_fishing:sellFish', function() + local playerPed = GetPlayerPed(source) + local playerCoord = GetEntityCoords(playerPed) + local distance = #(playerCoord - Config.sellShop.coords) + if distance == nil or distance > 3 then + KickPlayer(source, Strings.kicked) + return + end + + -- Sell fish + for i=1, #Config.fish do + SellItem(source, Config.fish[i]) + end + + -- Sell processed items + for i=1, #Config.processedItems do + SellItem(source, Config.processedItems[i]) + end +end) + +-- Helper function to sell items +function SellItem(source, itemData) + if HasItem(source, itemData.item) > 0 then + local rewardAmount = 0 + for j=1, HasItem(source, itemData.item) do + rewardAmount = rewardAmount + math.random(itemData.price[1], itemData.price[2]) + end + if rewardAmount > 0 then + AddMoney(source, 'money', rewardAmount) + TriggerClientEvent('wasabi_fishing:notify', source, Strings.sold_for, + (Strings.sold_for_desc):format(HasItem(source, itemData.item), itemData.label, addCommas(rewardAmount)), 'success') + RemoveItem(source, itemData.item, HasItem(source, itemData.item)) + end + end +end + +-- Modify the getFishData callback to handle bait types +lib.callback.register('wasabi_fishing:getFishData', function(source, baitType) + local baitData = nil + + -- Find the bait data + for _, bait in pairs(Config.bait.types) do + if bait.itemName == baitType then + baitData = bait + break + end + end + + if not baitData then + -- Use default bait data if the provided bait type is not found + for _, bait in pairs(Config.bait.types) do + if bait.itemName == Config.bait.defaultBait then + baitData = bait + break + end + end + end + + -- If using illegal bait, only catch pufferfish + if baitData.exclusive then + for _, fishType in pairs(baitData.exclusive) do + for _, fish in pairs(Config.fish) do + if fish.item == fishType then + return fish + end + end + end + end + + -- Otherwise, random fish with catch bonus + local availableFish = {} + for _, fish in pairs(Config.fish) do + -- Don't include exclusive fish types unless using the right bait + local isExclusive = false + for _, bait in pairs(Config.bait.types) do + if bait.exclusive then + for _, exclusiveFish in pairs(bait.exclusive) do + if fish.item == exclusiveFish then + isExclusive = true + break + end + end + end + if isExclusive then break end + end + + if not isExclusive then + table.insert(availableFish, fish) + end + end + + -- Apply catch bonus logic here if needed + return availableFish[math.random(#availableFish)] +end) diff --git a/resources/[jobs]/[civ]/wasabi_fishing/server/updater.lua b/resources/[jobs]/[civ]/wasabi_fishing/server/updater.lua new file mode 100644 index 000000000..4ccf173fe --- /dev/null +++ b/resources/[jobs]/[civ]/wasabi_fishing/server/updater.lua @@ -0,0 +1,63 @@ +-----------------For support, scripts, and more---------------- +--------------- https://discord.gg/wasabiscripts ------------- +--------------------------------------------------------------- + +local curVersion = GetResourceMetadata(GetCurrentResourceName(), "version") +local resourceName = "wasabi_fishing" + +if Config.checkForUpdates then + CreateThread(function() + if GetCurrentResourceName() ~= "wasabi_fishing" then + resourceName = "wasabi_fishing (" .. GetCurrentResourceName() .. ")" + end + end) + + CreateThread(function() + while true do + PerformHttpRequest("https://api.github.com/repos/wasabirobby/wasabi_fishing/releases/latest", CheckVersion, "GET") + Wait(3600000) + end + end) + + CheckVersion = function(err, responseText, headers) + local repoVersion, repoURL, repoBody = GetRepoInformations() + + CreateThread(function() + if curVersion ~= repoVersion then + Wait(4000) + print("^0[^3WARNING^0] " .. resourceName .. " is ^1NOT ^0up to date!") + print("^0[^3WARNING^0] Your Version: ^2" .. curVersion .. "^0") + print("^0[^3WARNING^0] Latest Version: ^2" .. repoVersion .. "^0") + print("^0[^3WARNING^0] Get the latest Version from: ^2" .. repoURL .. "^0") + print("^0[^3WARNING^0] Changelog:^0") + print("^1" .. repoBody .. "^0") + else + Wait(4000) + print("^0[^2INFO^0] " .. resourceName .. " is up to date! (^2" .. curVersion .. "^0)") + end + end) + end + + GetRepoInformations = function() + local repoVersion, repoURL, repoBody = nil, nil, nil + + PerformHttpRequest("https://api.github.com/repos/wasabirobby/wasabi_fishing/releases/latest", function(err, response, headers) + if err == 200 then + local data = json.decode(response) + + repoVersion = data.tag_name + repoURL = data.html_url + repoBody = data.body + else + repoVersion = curVersion + repoURL = "https://github.com/wasabirobby/wasabi_fishing" + end + end, "GET") + + repeat + Wait(50) + until (repoVersion and repoURL and repoBody) + + return repoVersion, repoURL, repoBody + end +end \ No newline at end of file