├── README.md └── s_fishing ├── fishes.sql ├── fxmanifest.lua ├── html ├── index.html ├── reset.css ├── index.css └── index.js ├── config └── config.lua ├── cl ├── skillcheck.lua ├── cl.lua └── shops.lua └── sv └── sv.lua /README.md: -------------------------------------------------------------------------------- 1 | # s_fishing 2 | Fishing script for FiveM 3 | 4 | Probably better than most paid ones out there, definitely better than most free releases. 5 | -------------------------------------------------------------------------------- /s_fishing/fishes.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO `items` (`name`, `label`, `weight`) VALUES 2 | ('pike', 'Pike', 1), 3 | ('bream', 'Bream', 1), 4 | ('pike_berch', 'pike_perch', 1), 5 | ('salmon', 'Salmon', 1), 6 | ('trout', 'Trout', 1), 7 | ('herring', 'Herring', 1), 8 | ('cod', 'Cod', 1), 9 | ('tuna', 'Tuna', 1), 10 | ('rod', 'Fishing rod', 1) 11 | ; -------------------------------------------------------------------------------- /s_fishing/fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'adamant' 2 | 3 | game 'gta5' 4 | 5 | description 's_fishing' --Made by Slerbamonsteri#5636 6 | 7 | version '1.0.0' 8 | 9 | ui_page 'html/index.html' 10 | 11 | files { 12 | 'html/index.html', 13 | 'html/index.js', 14 | 'html/index.css', 15 | 'html/reset.css' 16 | } 17 | 18 | client_scripts { 19 | 'cl/cl.lua', 20 | 'cl/skillcheck.lua', 21 | 'cl/shops.lua', 22 | 'config/config.lua' 23 | } 24 | 25 | server_scripts { 26 | 'sv/sv.lua', 27 | 'sv/config.lua', 28 | 'config/config.lua' 29 | } -------------------------------------------------------------------------------- /s_fishing/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 |
11 |
12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /s_fishing/html/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } -------------------------------------------------------------------------------- /s_fishing/config/config.lua: -------------------------------------------------------------------------------- 1 | Config = {} 2 | 3 | Config.fishwebhook = 'WEBHOOK HERE' --Caught fishes -log 4 | Config.sellwebhook = 'WEBHOOK HERE' --Shopselling -log 5 | Config.licenses = true --Set to false if you do not use esx_license, this is used to add fishing licenses(permits) for players. 6 | 7 | Config.sellitemprices = { --You can add here other stuff too if you i.e add more variety of fishes 8 | pike = 12, 9 | bream = 8, 10 | pike_berch = 20, 11 | salmon = 19, 12 | trout = 17, 13 | cod = 10, 14 | herring = 7, 15 | } 16 | 17 | Config.fishes = { 18 | --Here are some examples, you can add unlimited brackets 19 | [1] = { 20 | { itemName = 'pike', howmany = 1, type = 'item'}, 21 | }, 22 | 23 | [2] = { 24 | { itemName = 'bream', howmany = 1, type = 'item'}, 25 | }, 26 | 27 | [3] = { 28 | { itemName = 'pike_berch', howmany = 1, type = 'item'}, 29 | }, 30 | 31 | [4] = { 32 | { itemName = 'salmon', howmany = 1, type = 'item'}, 33 | }, 34 | 35 | [5] = { 36 | { itemName = 'trout', howmany = 1, type = 'item'}, 37 | }, 38 | 39 | [6] = { 40 | { itemName = 'cod', howmany = 1, type = 'item'}, 41 | }, 42 | 43 | [7] = { 44 | { itemName = 'herring', howmany = 1, type = 'item'}, 45 | }, 46 | 47 | [8] = { 48 | { itemName = 'tuna', howmany = 1, type = 'item'}, 49 | }, 50 | } -------------------------------------------------------------------------------- /s_fishing/html/index.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | background: none !important; 4 | } 5 | 6 | #container { 7 | font-size: 20px; 8 | padding: 25px; 9 | color: white; 10 | position: relative; 11 | top: 50%; 12 | left: 50%; 13 | transform: translate(-50%, -50%); 14 | background-color: rgba(44, 44, 44, 0); 15 | } 16 | 17 | 18 | 19 | .Buttons { 20 | width: 75px; 21 | height: 75px; 22 | background-color: rgba(79, 79, 79, 150); 23 | border-radius: 10px 10px; 24 | border: 1px solid rgb(163, 163, 163); 25 | box-shadow: 5px; 26 | padding: 1px; 27 | font-size: 30px; 28 | font-weight: bold; 29 | color: white; 30 | -webkit-box-shadow: inset 0 0px 0 #000000, 4px 8px 0 #000000; 31 | margin-left: 60%; 32 | } 33 | 34 | .timer1 { 35 | margin-top: 30px; 36 | height: 5px; 37 | width: 500px; 38 | position: absolute; 39 | z-index: 2; 40 | background-color: rgb(143, 98, 0); 41 | margin-left: 36.9791666667%; 42 | margin-top: 25%; 43 | border-radius: 10px 10px; 44 | } 45 | 46 | .timer2 { 47 | margin-top: 30px; 48 | height: 5px; 49 | width: 100px; 50 | position: absolute; 51 | z-index: 3; 52 | background-color: rgb(255, 174, 0); 53 | margin-left: 36.9791666667%; 54 | margin-top: 25%; 55 | border-radius: 10px 10px; 56 | } -------------------------------------------------------------------------------- /s_fishing/cl/skillcheck.lua: -------------------------------------------------------------------------------- 1 | 2 | --skillcheck stuff 3 | 4 | local display = false 5 | local notComplete = false 6 | local failure = false 7 | local Callback = {} 8 | 9 | 10 | RegisterNUICallback("exit", function(data) 11 | chat("Failed!", {0,255,0}) 12 | SetDisplay(false) 13 | end) 14 | 15 | 16 | RegisterNUICallback("error", function(data) 17 | if data.error == 'Complete!' then 18 | SetDisplay(false) 19 | notComplete = false 20 | else 21 | SetDisplay(false) 22 | notComplete = false 23 | failure = true 24 | end 25 | end) 26 | 27 | function SetDisplay(bool) 28 | SetNuiFocus(bool, false) 29 | SendNUIMessage({ 30 | type = "ui", 31 | status = bool, 32 | }) 33 | end 34 | 35 | RegisterNetEvent('s_fishing:minigame') 36 | AddEventHandler('s_fishing:minigame', function(func) 37 | Callback = func 38 | SetDisplay(not display) 39 | notComplete = true 40 | failure = false 41 | while notComplete do 42 | Citizen.Wait(100) 43 | end 44 | if failure then 45 | Callback(false) 46 | else 47 | Callback(true) 48 | end 49 | end) 50 | 51 | Citizen.CreateThread(function() 52 | while display do 53 | Citizen.Wait(0) 54 | -- https://runtime.fivem.net/doc/natives/#_0xFE99B66D079CF6BC 55 | --[[ 56 | inputGroup -- integer , 57 | control --integer , 58 | disable -- boolean 59 | ]] 60 | DisableControlAction(0, 1, display) -- LookLeftRight 61 | DisableControlAction(0, 2, display) -- LookUpDown 62 | DisableControlAction(0, 142, display) -- MeleeAttackAlternate 63 | DisableControlAction(0, 18, display) -- Enter 64 | DisableControlAction(0, 322, display) -- ESC 65 | DisableControlAction(0, 106, display) -- VehicleMouseControlOverride 66 | end 67 | end) 68 | 69 | function chat(str, color) 70 | TriggerEvent( 71 | 'chat:addMessage', 72 | { 73 | color = color, 74 | multiline = true, 75 | args = {str} 76 | } 77 | ) 78 | end -------------------------------------------------------------------------------- /s_fishing/html/index.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | function display(bool) { 3 | if (bool) { 4 | $("#container").show(); 5 | } else { 6 | $("#container").hide(); 7 | } 8 | } 9 | function sleep(ms) { 10 | return new Promise(resolve => setTimeout(resolve, ms)); 11 | } 12 | 13 | let progress = 0; 14 | let divide = 0; 15 | let doTimer = false; 16 | 17 | 18 | 19 | async function countdown() { 20 | //document.getElementById('timer').style.width = '480px'; 21 | let timerWidth = '500'; 22 | for (i = 0; i < 500; i++) { 23 | if (doTimer) { 24 | timerWidth = timerWidth - 1 25 | document.getElementById('timer').style.width = timerWidth + 'px'; 26 | await sleep(8) 27 | if (timerWidth === 0) { 28 | playingGame = false; 29 | timerStarted = false; 30 | $.post("https://s_fishing/error", JSON.stringify({ 31 | error: "You took too long!" 32 | })) 33 | document.getElementById('1').style.backgroundColor = ''; 34 | } 35 | } else { 36 | break; 37 | } 38 | } 39 | } 40 | 41 | display(false) 42 | 43 | window.addEventListener('message', function(event) { 44 | var item = event.data; 45 | if (item.type === "ui") { 46 | if (item.status == true) { 47 | display(true) 48 | progress = 0; 49 | divide = Math.floor(Math.random()*5)*5 + 5 50 | if (divide < 10) { 51 | divide = 10 52 | } 53 | document.getElementById('timer').style.width = '500px'; 54 | doTimer = true; 55 | countdown() 56 | } else { 57 | display(false) 58 | } 59 | } 60 | }) 61 | 62 | 63 | // if the person uses the escape key, it will exit the resource 64 | document.onkeyup = function (data) { 65 | if (data.which == 27) { 66 | doTimer = false; 67 | $.post('https://s_fishing/exit', JSON.stringify({})); 68 | return 69 | } else if (data.which == 69) { 70 | progress = progress + divide; 71 | $("button").css("-webkit-box-shadow", "inset 4px 4px 0 #000000, 2px 4px 0 #000000"); 72 | setTimeout(function(){ 73 | $("button").css("-webkit-box-shadow", ""); 74 | }, 30); 75 | if (progress > 255) { 76 | doTimer = false; 77 | $("button").css("background-color", ""); 78 | $.post("https://s_fishing/error", JSON.stringify({ 79 | error: "Complete!" 80 | })) 81 | } else { 82 | $("button").css("background-color", "rgb(" + progress + "," + progress+ "," + progress + ")"); 83 | } 84 | } 85 | }; 86 | 87 | }) -------------------------------------------------------------------------------- /s_fishing/sv/sv.lua: -------------------------------------------------------------------------------- 1 | ESX = nil 2 | 3 | TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) 4 | 5 | ESX.RegisterUsableItem('rod', function(source) 6 | TriggerClientEvent('s_fishing:start', source) 7 | end) 8 | 9 | AddEventHandler('esx:playerLoaded', function(source) 10 | print('playerloaded') 11 | TriggerEvent('pkrp_license:getLicenses', source, function(licenses) 12 | TriggerClientEvent('s_fishing:loadLicenses', source, licenses) 13 | end) 14 | end) 15 | 16 | 17 | --Fishing stuff 18 | RegisterServerEvent('s_fishing:caught') 19 | AddEventHandler('s_fishing:caught', function() 20 | local _source = source 21 | local xPlayer = ESX.GetPlayerFromId(_source) 22 | local RBrackets = math.random(1, #Config.fishes) 23 | local name = GetPlayerName(source) 24 | if xPlayer ~=nil then 25 | for k,v in pairs(Config.fishes[RBrackets]) do 26 | if v.type == 'item' then 27 | xPlayer.addInventoryItem(v.itemName, v.howmany) 28 | sendToDiscord(66666, "Fishing", name .. " Caught: " ..v.itemName.. 'x ' ..v.howmany..'.', "s_fishingLOG") 29 | elseif v.type == 'weapon' then 30 | for i=1, v.howmany, 1 do 31 | xPlayer.addWeapon(v.itemName, v.ammo) 32 | sendToDiscord(66666, "Fishing", name .. " Caught: " ..v.itemName.. 'x ' ..v.ammo..'.', "s_fishingLOG") 33 | end 34 | elseif v.type == 'money' then 35 | xPlayer.addMoney(v.howmany) 36 | sendToDiscord(66666, "Fishing", name .. " Caught some money: "..v.howmany..'.', "s_fishingLOG") 37 | end 38 | end 39 | end 40 | end) 41 | 42 | --Selling stuff 43 | RegisterServerEvent('s_fishing:sell') 44 | AddEventHandler('s_fishing:sell', function() 45 | local _source = source 46 | local xPlayer = ESX.GetPlayerFromId(_source) 47 | local name = GetPlayerName(_source) 48 | for q,p in pairs(Config.sellitemprices) do 49 | local item = xPlayer.getInventoryItem(q) 50 | if item.count >= 1 then 51 | xPlayer.addMoney(item.count * p) 52 | xPlayer.removeInventoryItem(q, item.count) 53 | xPlayer.showNotification('Sold fish ~b~' ..item.label.. '~s~ for ~g~'..item.count * p ..'$') 54 | sendToDiscord2(56222, 'Fish market', '**'..name.. '** | **Sold:** [*' ..item.label.. '*]** for:** [' ..item.count * p.. '$]', 's_fishingLOG') 55 | end 56 | end 57 | end) 58 | 59 | --Purcahse fishing rod 60 | RegisterServerEvent("s_fishing:buyrod") 61 | AddEventHandler("s_fishing:buyrod", function() 62 | local xPlayer = ESX.GetPlayerFromId(source) 63 | if xPlayer.getAccount('bank').money >= 200 then 64 | xPlayer.removeAccountMoney('bank', 200) 65 | xPlayer.addInventoryItem('rod', 1) 66 | else 67 | xPlayer.showNotification('Not enough money (200$)') 68 | end 69 | end) 70 | 71 | --License stuff 72 | ESX.RegisterServerCallback('s_fishing:buyLicense', function(source, cb) 73 | local xPlayer = ESX.GetPlayerFromId(source) 74 | 75 | if xPlayer.getAccount('bank').money >= 250 then 76 | xPlayer.removeAccountMoney('bank', 250) 77 | 78 | TriggerEvent('pkrp_license:addLicense', source, 'fishing', function() 79 | xPlayer.showNotification('You now own fishing permits') 80 | cb(true) 81 | end) 82 | else 83 | xPlayer.showNotification('Not enough money') 84 | cb(false) 85 | end 86 | end) 87 | 88 | function sendToDiscord(color, name, message, footer) 89 | local embed = { 90 | { 91 | ["color"] = color, 92 | ["title"] = "**".. name .."**", 93 | ["description"] = message, 94 | ["footer"] = { 95 | ["text"] = footer, 96 | }, 97 | } 98 | } 99 | PerformHttpRequest(Config.fishwebhook, function(err, text, headers) end, 'POST', json.encode({username = name, embeds = embed}), { ['Content-Type'] = 'application/json' }) 100 | end 101 | 102 | function sendToDiscord2(color, name, message, footer) 103 | local embed = { 104 | { 105 | ["color"] = color, 106 | ["title"] = "**".. name .."**", 107 | ["description"] = message, 108 | ["footer"] = { 109 | ["text"] = footer, 110 | }, 111 | } 112 | } 113 | PerformHttpRequest(Config.sellwebhook, function(err, text, headers) end, 'POST', json.encode({username = name, embeds = embed}), { ['Content-Type'] = 'application/json' }) 114 | end 115 | 116 | -------------------------------------------------------------------------------- /s_fishing/cl/cl.lua: -------------------------------------------------------------------------------- 1 | ESX = nil 2 | 3 | Citizen.CreateThread(function() 4 | while ESX == nil do 5 | TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) 6 | Citizen.Wait(0) 7 | end 8 | end) 9 | 10 | --Some code i found in vrP_fishing 11 | function AttachEntityToPed(prop,bone_ID,x,y,z,RotX,RotY,RotZ) 12 | BoneID = GetPedBoneIndex(PlayerPedId(), bone_ID) 13 | obj = CreateObject(GetHashKey(prop), 1729.73, 6403.90, 34.56, true, true, true) 14 | vX,vY,vZ = table.unpack(GetEntityCoords(PlayerPedId())) 15 | xRot, yRot, zRot = table.unpack(GetEntityRotation(PlayerPedId(),2)) 16 | AttachEntityToEntity(obj, PlayerPedId(), BoneID, x,y,z, RotX,RotY,RotZ, false, false, false, false, 2, true) 17 | return obj 18 | end 19 | 20 | local draw = false 21 | local rng22 = false 22 | 23 | --starting up 24 | RegisterNetEvent('s_fishing:start') 25 | AddEventHandler('s_fishing:start', function() 26 | local pedc = GetEntityCoords(PlayerPedId()) 27 | local boat = GetClosestVehicle(pedc.x, pedc.y, pedc.z, 5.0, 0, 12294) 28 | if IsEntityInWater(PlayerPedId()) or IsEntityInWater(boat) then 29 | if not IsPedInAnyVehicle(PlayerPedId(), false) then 30 | if not IsPedSwimming(PlayerPedId()) then 31 | ESX.UI.Menu.CloseAll() 32 | draw = true 33 | rng22 = true 34 | ESX.ShowNotification('Fishing...') 35 | TriggerEvent('s_fishing:rng') 36 | fishing() 37 | else 38 | ESX.ShowNotification('You have to decide, whether you want to swim or fish') 39 | end 40 | end 41 | else 42 | ESX.ShowNotification('I can´t fish here...') 43 | end 44 | end) 45 | 46 | --Anim & Prop & Triggering them fishy fishes 47 | function fishing() 48 | RequestAnimDict('amb@world_human_stand_fishing@idle_a') 49 | while not HasAnimDictLoaded('amb@world_human_stand_fishing@idle_a') do 50 | Citizen.Wait(1) 51 | end 52 | rod = AttachEntityToPed('prop_fishing_rod_01',60309, 0,0,0, 0,0,0) 53 | TaskPlayAnim(PlayerPedId(), 'amb@world_human_stand_fishing@idle_a', 'idle_b', 8.0, 8.0, -1, 1, 1, 0, 0, 0) 54 | drawtext() 55 | end 56 | 57 | --Drawing function, added as an extra spice inventory disabling.. Just to make sure players wont fuck anything up or exploit anything 58 | function drawtext() 59 | local pedcoords = GetEntityCoords(PlayerPedId()) 60 | while draw do 61 | w = 5 62 | DisableControlAction(0, 288, true) -- F1 63 | DisableControlAction(0, 289, true) -- F2 64 | Draw3DText(pedcoords.x - 1, pedcoords.y, pedcoords.z + 1,'Press [~r~X~s~] to stop fishing') 65 | if IsControlJustPressed(0, 73) then 66 | ESX.ShowNotification('Stopped fishing') 67 | DeleteEntity(rod) 68 | DeleteObject(rod) 69 | rng22 = false 70 | TriggerEvent('s_fishing:rng') 71 | cancel() 72 | ClearPedTasks(PlayerPedId()) 73 | break 74 | end 75 | Citizen.Wait(w) 76 | end 77 | while not draw do 78 | break 79 | end 80 | end 81 | 82 | AddEventHandler('s_fishing:rng', function() 83 | while rng22 do 84 | Wait(math.random(13000, 32000)) 85 | catchfish() 86 | ClearPedTasks(PlayerPedId()) 87 | DeleteObject(rod) 88 | DeleteEntity(rod) 89 | break 90 | end 91 | while not rng22 do 92 | catchfish() 93 | break 94 | end 95 | end) 96 | 97 | function catchfish() 98 | if rng22 then 99 | TriggerEvent('s_fishing:minigame', function(success) 100 | if success then 101 | TriggerServerEvent('s_fishing:caught') 102 | cancel() 103 | Citizen.Wait(10) 104 | TriggerEvent('s_fishing:start') 105 | else 106 | rng22 = false 107 | cancel() 108 | ClearPedTasks(PlayerPedId()) 109 | TriggerEvent('s_fishing:rng') 110 | ESX.ShowNotification("You didn't catch anything, try again") 111 | end 112 | end) 113 | end 114 | end 115 | 116 | function cancel() 117 | draw = false 118 | DeleteObject(rod) 119 | DeleteEntity(rod) 120 | drawtext() 121 | ClearPedTasks(PlayerPedId()) 122 | end 123 | 124 | --Drawtext 125 | function Draw3DText(x,y,z, text) 126 | local onScreen,_x,_y=World3dToScreen2d(x,y,z) 127 | local px,py,pz=table.unpack(GetGameplayCamCoords()) 128 | 129 | SetTextScale(0.35, 0.35) 130 | SetTextFont(8) 131 | SetTextProportional(1) 132 | SetTextColour(255, 255, 255, 215) 133 | SetTextEntry("STRING") 134 | SetTextCentre(1) 135 | SetTextOutline() 136 | AddTextComponentString(text) 137 | DrawText(_x,_y) 138 | end 139 | -------------------------------------------------------------------------------- /s_fishing/cl/shops.lua: -------------------------------------------------------------------------------- 1 | ESX = nil 2 | local Licenses = {} 3 | --Make peds face playerped 4 | Citizen.CreateThread(function() 5 | while ESX == nil do 6 | TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) 7 | Citizen.Wait(0) 8 | end 9 | ESX.Game.MakeEntityFaceEntity = function(entity1, entity2) 10 | local p1 = GetEntityCoords(entity1, true) 11 | local p2 = GetEntityCoords(entity2, true) 12 | 13 | local dx = p2.x - p1.x 14 | local dy = p2.y - p1.y 15 | 16 | local heading = GetHeadingFromVector_2d(dx, dy) 17 | SetEntityHeading( entity1, heading ) 18 | end 19 | end) 20 | 21 | 22 | --Add as many sellpoints as you wish 23 | local shopnpc = { 24 | {x =-1845.49, y = -1196.50, z = 18.18}, 25 | --{x =-1845.49, y = -1196.50, z = 18.18}, 26 | --{x =-1845.49, y = -1196.50, z = 18.18} 27 | } 28 | 29 | --Function to spawn shopnpc 30 | function spawnshopnpc() 31 | Citizen.CreateThread(function() 32 | local sleep = 1000 33 | local ped = GetHashKey("s_m_m_linecook") 34 | RequestModel(ped) 35 | while not HasModelLoaded(ped) do 36 | Citizen.Wait(1) 37 | end 38 | for k,v in pairs(shopnpc) do 39 | shop = CreatePed(4, ped, v.x, v.y, v.z, 78.20, false, true) 40 | local npc = GetEntityCoords(shop) 41 | local playerped = GetEntityCoords(PlayerPedId()) 42 | local dist = #(npc - playerped) 43 | SetEntityInvincible(shop, true) 44 | PlaceObjectOnGroundProperly(shop) 45 | TaskSetBlockingOfNonTemporaryEvents(shop, true) 46 | Citizen.Wait(1000) 47 | FreezeEntityPosition(shop, true) 48 | while true do 49 | Citizen.Wait(50) 50 | playerped = GetEntityCoords(PlayerPedId()) 51 | dist = #(npc - playerped) 52 | if dist < 5 then 53 | ESX.Game.MakeEntityFaceEntity(shop, PlayerPedId()) 54 | else 55 | Citizen.Wait(sleep) 56 | end 57 | end 58 | end 59 | end) 60 | end 61 | 62 | --Shop purchase 63 | function fishshop() 64 | local ownedLicenses = {} 65 | for i=1, #Licenses, 1 do 66 | ownedLicenses[Licenses[i].type] = true 67 | end 68 | ESX.UI.Menu.CloseAll() 69 | FreezeEntityPosition(PlayerPedId(),true) 70 | local elements = {} 71 | table.insert(elements, {label = 'Purchase fishing rod - 200$', value = 'buyrod'}) 72 | if Config.licenses then 73 | if not ownedLicenses['fishing'] then 74 | table.insert(elements, {label = 'Purchase Fishing Permit - 250$', value = 'buylice'}) 75 | else 76 | table.insert(elements, {label = 'You already own Fishing permits', value = 'exit'}) 77 | end 78 | end 79 | table.insert(elements, {label = 'Exit', value = 'exit'}) 80 | ESX.UI.Menu.Open( 81 | 'default', GetCurrentResourceName(), 'fishingshop', 82 | { 83 | title = 'Fish shop', 84 | align = 'center', 85 | elements = elements 86 | }, 87 | function(data, menu) 88 | if data.current.value == 'buyrod' then 89 | TriggerServerEvent("s_fishing:buyrod") 90 | elseif data.current.value == 'buylice' then 91 | ESX.TriggerServerCallback('s_fishing:buyLicense', function(bought) 92 | if bought then 93 | menu.close() 94 | end 95 | end) 96 | elseif data.current.value == 'exit' then 97 | ESX.UI.Menu.CloseAll() 98 | end 99 | FreezeEntityPosition(PlayerPedId(),false) 100 | ESX.UI.Menu.CloseAll() 101 | end) 102 | end 103 | 104 | --Shop sell 105 | function shopsell() 106 | ESX.UI.Menu.CloseAll() 107 | FreezeEntityPosition(PlayerPedId(),true) 108 | ESX.UI.Menu.Open( 109 | 'default', GetCurrentResourceName(), 'fshop', 110 | { 111 | title = 'Fish market', 112 | align = 'center', 113 | elements = { 114 | {label = 'Sell fish', value = 'sell'}, 115 | {label = 'Exit', value = 'exit'}, 116 | }, 117 | }, 118 | function(data, menu) 119 | if data.current.value == 'sell' then 120 | TriggerServerEvent("s_fishing:sell", source) 121 | ESX.UI.Menu.CloseAll() 122 | elseif data.current.value == 'exit' then 123 | ESX.UI.Menu.CloseAll() 124 | end 125 | FreezeEntityPosition(PlayerPedId(),false) 126 | ESX.UI.Menu.CloseAll() 127 | end) 128 | end 129 | 130 | --Store stuff 131 | Citizen.CreateThread(function() 132 | while true do 133 | Citizen.Wait(5) 134 | local playerped = GetEntityCoords(PlayerPedId()) 135 | for k,v in pairs(shopnpc) do 136 | local dist = #(vector3(v.x, v.y, v.z) - playerped) 137 | local ClockTime = GetClockHours() 138 | local w = 1000 139 | if dist < 5 then 140 | Draw3DText2(v.x, v.y, v.z + 0.5, "[~r~E~w~] Open shop | [~g~G~w~] Sell your fishes") 141 | if IsControlJustReleased(0, 38) then 142 | if ClockTime >= 6 -1 and ClockTime < 22 then 143 | fishshop() 144 | else 145 | TriggerEvent('mythic_notify:client:slerba', { type = 'error', length = 7000, text = 'Shop is currently unavailable' }) 146 | end 147 | elseif IsControlJustPressed(0, 47) then 148 | shopsell() 149 | end 150 | else 151 | Citizen.Wait(w) 152 | end 153 | end 154 | end 155 | end) 156 | 157 | --License stuff from copied from esx_dmvschool 158 | RegisterNetEvent('s_fishing:loadLicenses') 159 | AddEventHandler('s_fishing:loadLicenses', function(licenses) 160 | Licenses = licenses 161 | end) 162 | 163 | --Blip and npc stuff 164 | Citizen.CreateThread(function() 165 | spawnshopnpc() 166 | Wait(300) 167 | for k,v in pairs(shopnpc) do 168 | sellblip = AddBlipForCoord(v.x, v.y, v.z) 169 | SetBlipSprite(sellblip, 356) 170 | SetBlipColour(sellblip, 83) 171 | SetBlipScale(sellblip, 0.8) 172 | SetBlipAsShortRange(sellblip, true) 173 | BeginTextCommandSetBlipName('STRING') 174 | AddTextComponentString('Fish market') -- set blip's "name" 175 | EndTextCommandSetBlipName(sellblip) 176 | end 177 | end) 178 | 179 | --3D text stuff 180 | function Draw3DText2(x,y,z, text) 181 | local onScreen,_x,_y=World3dToScreen2d(x,y,z) 182 | local px,py,pz=table.unpack(GetGameplayCamCoords()) 183 | 184 | SetTextScale(0.35, 0.35) 185 | SetTextFont(4) 186 | SetTextProportional(1) 187 | SetTextColour(255, 255, 255, 215) 188 | SetTextEntry("STRING") 189 | SetTextCentre(1) 190 | AddTextComponentString(text) 191 | DrawText(_x,_y) 192 | local factor = (string.len(text)) / 370 193 | DrawRect(_x,_y+0.0125, 0.015+ factor, 0.03, 0, 0, 0, 68) 194 | end 195 | --------------------------------------------------------------------------------