├── .github ├── FUNDING.yml └── workflows │ └── notify-discord.yml ├── README.md ├── client.lua ├── config.lua ├── fxmanifest.lua ├── images └── notepad.png ├── locales ├── cn.lua ├── da.lua └── en.lua ├── server.lua └── version.txt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: jixelpatterns 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://jimathy666.tebex.io/'] 13 | -------------------------------------------------------------------------------- /.github/workflows/notify-discord.yml: -------------------------------------------------------------------------------- 1 | name: Discord Commit Notifier 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' # triggers on all branches 7 | 8 | jobs: 9 | notify: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Discord Commits 13 | uses: Sniddl/discord-commits@v1.6 14 | with: 15 | webhook: ${{ secrets.DISCORD_WEBHOOK }} 16 | template: "avatar-with-link" 17 | include-extras: true -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | I hope you have fun with this script and that it brings jobs and RP to your server 2 | 3 | If you need support I now have a discord available, it helps me keep track of issues and give better support. 4 | 5 | https://discord.gg/xKgQZ6wZvS 6 | 7 | # Jim-NotePad 8 | 9 | ## What Is it? 10 | Simple notepad script 11 | 12 | Allows players to place notes on the ground as crumpled pieces of paper (the prop) and other players can view them 13 | 14 | Good for leaving info behind, eg for people roleplaying serial killers or whatever, or just telling people they need to do something 15 | 16 | The notes will also be removed at server/script restart 17 | 18 | ## Dependencies 19 | - [`jim_bridge`](https://github.com/jimathy/jim_bridge) - https://github.com/jimathy/jim_bridge 20 | 21 | https://streamable.com/pt3e0n 22 | 23 | ## Install 24 | 25 | ### QB: 26 | - Add the script to your resources eg. `resources/[jim]` 27 | - Add this to your server.cfg: `ensure jim-notepad` 28 | - Add the images to you inventory script eg `[qb]/qb-inventory/html/images` 29 | - Add the item to your core eg. `[qb]/qb-core/shared/items.lua` 30 | ```lua 31 | notepad = { name = "notepad", label = "Notepad", weight = 100, type = "item", image = "notepad.png", unique = false, useable = false, shouldClose = true, combinable = nil, description = "A pad of blank notes" }, 32 | ``` 33 | 34 | ### OX: 35 | - Add the script to your resources eg. `resources/[jim]` 36 | - Add this to your server.cfg: `ensure jim-notepad` 37 | - Add the images to you inventory script eg `[ox]/ox_inventory/web/images` 38 | - Add the item to your inventory eg. `[ox]/ox_inventory/data/items.lua` 39 | ```lua 40 | ["notepad"] = { 41 | label = "Notepad", 42 | weight = 100, 43 | stack = true, 44 | close = true, 45 | description = "A pad of blank notes", 46 | client = { 47 | image = "notepad.png", 48 | event = "jim-notepad:Client:CreateNote" 49 | } 50 | }, 51 | ``` 52 | 53 | ## ChangeLog 54 | 55 | ### v2.0 56 | - Updated to use `jim_bridge` allowing for better support for other scripts/frameworks 57 | - Changed around the create note function 58 | - Remove the image option as the notes now accepts text and url then extracts that url to make 59 | - It takes the url as well as the text to show them separately in the "show note" part 60 | - Added options to enable a /command so players can type /notepad instead of having the item 61 | - Added option to disable the createUsableItem function from making notepad usable 62 | - Better support for ox_lib menus 63 | - Paper prop forced to be slightly larger to be more visible -------------------------------------------------------------------------------- /client.lua: -------------------------------------------------------------------------------- 1 | local Props, Targets, Notes = {}, {}, {} 2 | 3 | onPlayerLoaded(function() 4 | TriggerEvent("jim-notepad:Client:SyncNotes") 5 | end, true) 6 | 7 | RegisterNetEvent("jim-notepad:Client:SyncNotes", function(newNotes) 8 | if not newNotes then 9 | Notes = triggerCallback("jim-notepad:Server:SyncNotes") 10 | 11 | else 12 | Notes = newNotes 13 | end 14 | 15 | for k, v in pairs(Notes) do 16 | 17 | if not Props[k] and Notes[k] then 18 | Props[k] = makeProp({prop = "prop_amanda_note_01b", coords = vec4(v.coords.x, v.coords.y, v.coords.z+0.07, v.coords.w)}, true, false) 19 | 20 | -- Make the paper prop larder so easier to see 21 | SetEntityScale(Props[k], 1.5) 22 | 23 | Targets[k] = 24 | createCircleTarget({k, vec3(v.coords.x, v.coords.y, v.coords.z-1.1), 0.5, {name = k, debugPoly = debugMode, useZ = true}}, { 25 | { 26 | icon = "fas fa-receipt", 27 | label = Loc[Config.Lan].targetinfo["read"], 28 | action = function() 29 | TriggerServerEvent("jim-notepad:Server:ReadNote", { noteid = k }) 30 | end, 31 | } 32 | }, 1.5) 33 | end 34 | end 35 | for k in pairs(Props) do 36 | if not Notes[k] then 37 | removeZoneTarget(Targets[k]) 38 | destroyProp(Props[k]) 39 | end 40 | end 41 | end) 42 | 43 | RegisterNetEvent("jim-notepad:Client:CreateNote", function() 44 | local Ped = PlayerPedId() 45 | ExecuteCommand("e notepad") 46 | 47 | local dialog = createInput(Loc[Config.Lan].menu["make_a_note"], { 48 | { text = Loc[Config.Lan].text["enter_message"], name = "note", type = "text", isRequired = true }, 49 | { text = "test", name = "checkbox", type = "checkbox", 50 | options = { { value = "isAnon", text = "Anonymous", } } 51 | }, 52 | }) 53 | 54 | if dialog then 55 | 56 | local text = dialog.note or dialog[1] 57 | local image 58 | 59 | -- Extract image URL if present 60 | local url = text:match("(https?://%S+)") 61 | if url then 62 | -- Remove the URL from the image 63 | text = text:gsub("([Hh][Tt][Tt][Pp][Ss]?://%S+)", "") 64 | -- Convert to an image the menu's can read 65 | 66 | if Config.System.Menu == "ox" then 67 | image = '!['..''.. ']('..url..')' 68 | else 69 | image = "" 70 | end 71 | end 72 | 73 | local c = GetOffsetFromEntityInWorldCoords(Ped, 0.0, 0.6, 0.0) 74 | playAnim("pickup_object", "pickup_low", -1, 0) 75 | ExecuteCommand("e c") 76 | Wait(900) 77 | TriggerServerEvent("jim-notepad:Server:CreateNote", { 78 | coords = vec4(c.x, c.y, c.z, GetEntityHeading(Ped)), 79 | message = text, 80 | anon = dialog.isAnon or dialog[2], 81 | image = image or nil -- Pass image separately 82 | }) 83 | end 84 | end) 85 | 86 | RegisterNetEvent("jim-notepad:Client:ReadNote", function(data) 87 | local notepad = {} 88 | notepad[#notepad+1] = { 89 | icon = "fas fa-receipt", 90 | isMenuHeader = true, 91 | header = Loc[Config.Lan].menu["message"], 92 | txt = data.message, 93 | } 94 | if data.image then 95 | notepad[#notepad+1] = { 96 | isMenuHeader = true, 97 | header = Config.System.Menu == "ox" and data.image or "", text = data.image, 98 | } 99 | end 100 | notepad[#notepad+1] = { 101 | icon = "fas fa-person", 102 | isMenuHeader = true, 103 | header = "", 104 | txt = Loc[Config.Lan].menu["written_by"]..data.creator, 105 | } 106 | notepad[#notepad+1] = { 107 | icon = "fas fa-hand-scissors", 108 | header = "", 109 | txt = Loc[Config.Lan].menu["tear_up_note"], 110 | onSelect = function() 111 | playAnim("pickup_object", "pickup_low", -1, 0) 112 | Wait(900) 113 | TriggerServerEvent("jim-notepad:Server:SyncEffect", data.coords) 114 | TriggerServerEvent("jim-notepad:Server:DestroyNote", data.id) 115 | end 116 | } 117 | openMenu(notepad, { header = "Note", canClose = true }) 118 | end) 119 | 120 | RegisterNetEvent("jim-notepad:Client:SyncEffect", function(coords) 121 | UseParticleFxAssetNextCall("core") 122 | local dust = StartNetworkedParticleFxNonLoopedAtCoord("ent_sht_paper_bails", vec3(coords.x, coords.y, coords.z-1.03), 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0) 123 | end) -------------------------------------------------------------------------------- /config.lua: -------------------------------------------------------------------------------- 1 | Config = { 2 | Lan = "en", -- Pick your language here 3 | 4 | System = { 5 | Debug = false, -- enable debug mode 6 | 7 | Menu = "ox", 8 | }, 9 | 10 | General = { 11 | usableItem = true, -- if true, players can use the "notepad" item to create notes 12 | command = true, -- if ture, players can type /notepad to 13 | 14 | }, 15 | } -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | name "Jim-Notepad" 2 | author "Jimathy" 3 | version "2.0" 4 | description "Notepad Script" 5 | fx_version "cerulean" 6 | game "gta5" 7 | lua54 'yes' 8 | 9 | server_script '@oxmysql/lib/MySQL.lua' 10 | 11 | shared_scripts { 12 | 'locales/*.lua', 13 | 'config.lua', 14 | 15 | --Jim Bridge 16 | '@jim_bridge/starter.lua', 17 | } 18 | client_scripts { 19 | 'client.lua' 20 | } 21 | 22 | server_script 'server.lua' 23 | 24 | dependency 'jim_bridge' -------------------------------------------------------------------------------- /images/notepad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimathy/jim-notepad/dcd9036cab5dbb09865fab1f831289eb83595a28/images/notepad.png -------------------------------------------------------------------------------- /locales/cn.lua: -------------------------------------------------------------------------------- 1 | Loc = Loc or {} 2 | 3 | Loc["cn"] = { 4 | error = { 5 | 6 | }, 7 | success = { 8 | 9 | }, 10 | info = { 11 | 12 | }, 13 | targetinfo = { 14 | ["read"] = "阅读纸条", 15 | }, 16 | text = { 17 | ["enter_message"] = "在这里输入你的消息", 18 | }, 19 | menu = { 20 | ["make_a_note"] = "制作一个纸条", 21 | ["message"] = "消息:", 22 | ["written_by"] = "作者: ", 23 | ["tear_up_note"] = "撕下纸条", 24 | }, 25 | commands = { 26 | 27 | }, 28 | progressbar = { 29 | 30 | }, 31 | warning = {}, 32 | } -------------------------------------------------------------------------------- /locales/da.lua: -------------------------------------------------------------------------------- 1 | Loc["da"] = { 2 | error = { 3 | 4 | }, 5 | success = { 6 | 7 | }, 8 | info = { 9 | 10 | }, 11 | targetinfo = { 12 | ["read"] = "Læs memo", 13 | }, 14 | text = { 15 | ["enter_message"] = "Skriv din besked her", 16 | }, 17 | menu = { 18 | ["make_a_note"] = "Lav et memo", 19 | ["message"] = "Besked:", 20 | ["written_by"] = "Skrevet af: ", 21 | ["tear_up_note"] = "Riv memo itu", 22 | }, 23 | commands = { 24 | 25 | }, 26 | progressbar = { 27 | 28 | }, 29 | warning = {}, 30 | } 31 | -------------------------------------------------------------------------------- /locales/en.lua: -------------------------------------------------------------------------------- 1 | Loc = Loc or {} 2 | 3 | Loc["en"] = { 4 | error = { 5 | 6 | }, 7 | success = { 8 | 9 | }, 10 | info = { 11 | 12 | }, 13 | targetinfo = { 14 | ["read"] = "Read Note", 15 | }, 16 | text = { 17 | ["enter_message"] = "Enter your message here", 18 | }, 19 | menu = { 20 | ["make_a_note"] = "Make a note", 21 | ["message"] = "Message:", 22 | ["written_by"] = "Written By: ", 23 | ["tear_up_note"] = "Tear up note", 24 | }, 25 | commands = { 26 | 27 | }, 28 | progressbar = { 29 | 30 | }, 31 | warning = {}, 32 | } -------------------------------------------------------------------------------- /server.lua: -------------------------------------------------------------------------------- 1 | local cachedNotes = {} 2 | 3 | onResourceStart(function() 4 | 5 | if Config.General.command then 6 | registerCommand("notepad", { 7 | "Make a note", 8 | {}, false, 9 | function(source, args) 10 | TriggerClientEvent("jim-notepad:Client:CreateNote", source) 11 | end, 12 | nil, 13 | }) 14 | end 15 | 16 | if Config.General.usableItem then 17 | createUseableItem("notepad", function(source, item) 18 | TriggerClientEvent("jim-notepad:Client:CreateNote", source) 19 | end) 20 | end 21 | 22 | createCallback('jim-notepad:Server:SyncNotes', function(source) 23 | return cachedNotes 24 | end) 25 | 26 | end, true) 27 | 28 | RegisterNetEvent("jim-notepad:Server:CreateNote", function(data) 29 | local GeneratedID = keyGen()..keyGen() 30 | 31 | local creator = getPlayer(source).name 32 | 33 | DiscordLog(creator, data.message, 14177041) 34 | 35 | if tostring(data.anon) == "true" then creator = "Anonymous" end 36 | 37 | cachedNotes[GeneratedID] = { 38 | id = GeneratedID, 39 | coords = data.coords, 40 | message = data.message, 41 | image = data.image or nil, 42 | creator = creator, 43 | } 44 | 45 | TriggerClientEvent("jim-notepad:Client:SyncNotes", -1, cachedNotes) 46 | end) 47 | 48 | RegisterNetEvent("jim-notepad:Server:DestroyNote", function(data) 49 | cachedNotes[data] = nil 50 | TriggerClientEvent("jim-notepad:Client:SyncNotes", -1, cachedNotes) 51 | end) 52 | 53 | RegisterNetEvent("jim-notepad:Server:ReadNote", function(data) 54 | local src = source 55 | TriggerClientEvent("jim-notepad:Client:ReadNote", src, cachedNotes[data.noteid]) 56 | end) 57 | 58 | RegisterNetEvent("jim-notepad:Server:SyncEffect", function(coords) 59 | TriggerClientEvent("jim-notepad:Client:SyncEffect", -1, coords) 60 | end) 61 | 62 | discord = { 63 | ['webhook'] = "", 64 | ['name'] = 'Notepad', 65 | ['image'] = "https://i.imgur.com/G3jeSZv.png" 66 | } 67 | 68 | function DiscordLog(name, message, color) 69 | local embed = { 70 | { 71 | ["color"] = 04255, 72 | ["title"] = "**Note Dropped:**", 73 | ["description"] = message, 74 | ["url"] = "", 75 | ["footer"] = { 76 | ["text"] = "Dropped by: "..name, 77 | ["icon_url"] = "" 78 | }, 79 | ["thumbnail"] = { 80 | ["url"] = "", 81 | }, 82 | } 83 | } 84 | PerformHttpRequest(discord['webhook'], function(err, text, headers) end, 85 | 'POST', 86 | json.encode({ 87 | username = discord['name'], 88 | embeds = embed, 89 | avatar_url = discord['image'] 90 | }), { 91 | ['Content-Type'] = 'application/json' 92 | }) 93 | end 94 | -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | 2.0 --------------------------------------------------------------------------------