├── .editorconfig ├── .gitignore ├── .vscode └── extensions.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── client.lua ├── data ├── animations.lua ├── crafting.lua ├── evidence.lua ├── items.lua ├── licenses.lua ├── shops.lua ├── stashes.lua ├── vehicles.lua └── weapons.lua ├── fxmanifest.lua ├── init.lua ├── locales ├── ar.json ├── cs.json ├── da.json ├── de.json ├── el.json ├── en.json ├── es.json ├── et.json ├── fi.json ├── fr.json ├── hr.json ├── hu.json ├── id.json ├── it.json ├── ko.json ├── lt.json ├── nl.json ├── no.json ├── pl.json ├── pt-br.json ├── ru.json ├── sl.json ├── sr.json ├── sv.json ├── tr.json ├── zh-cn.json └── zh-tw.json ├── modules ├── bridge │ ├── client.lua │ ├── esx │ │ ├── client.lua │ │ └── server.lua │ ├── nd │ │ ├── client.lua │ │ └── server.lua │ ├── ox │ │ ├── client.lua │ │ └── server.lua │ ├── qb │ │ ├── client.lua │ │ └── server.lua │ └── server.lua ├── crafting │ ├── client.lua │ └── server.lua ├── hooks │ └── server.lua ├── interface │ └── client.lua ├── inventory │ ├── client.lua │ └── server.lua ├── items │ ├── client.lua │ ├── containers.lua │ ├── server.lua │ └── shared.lua ├── mysql │ └── server.lua ├── pefcl │ └── server.lua ├── shops │ ├── client.lua │ └── server.lua ├── utils │ ├── client.lua │ └── server.lua └── weapon │ └── client.lua ├── server.lua ├── setup └── convert.lua └── web ├── .gitignore ├── .prettierrc ├── LICENSE ├── build ├── assets │ ├── LLEG-5ff39a21.png │ ├── RLEG-1dd40978.png │ ├── head-52bdac31.png │ ├── index-109a9bf2.css │ ├── index-e1321e0b.js │ ├── larm-9416bd78.png │ ├── lfoot-6d7768f4.png │ ├── lowerbody-4884bf92.png │ ├── lpalm-cd95b6e0.png │ ├── neck-7fdfc0eb.png │ ├── rarm-7c2e8852.png │ ├── rfoot-df303828.png │ ├── rpalm-fbec58a7.png │ └── upperbody-24b1890e.png └── index.html ├── images ├── CIGARETTE.png ├── LLEG.png ├── RLEG.png ├── WEAPON_ACIDPACKAGE.PNG ├── WEAPON_ADVANCEDRIFLE.png ├── WEAPON_APPISTOL.png ├── WEAPON_ASSAULTRIFLE.png ├── WEAPON_ASSAULTRIFLE_MK2.png ├── WEAPON_ASSAULTSHOTGUN.png ├── WEAPON_ASSAULTSMG.png ├── WEAPON_AUTOSHOTGUN.png ├── WEAPON_BALL.png ├── WEAPON_BAT.png ├── WEAPON_BATTLEAXE.png ├── WEAPON_BOTTLE.png ├── WEAPON_BREAD.PNG ├── WEAPON_BRIEFCASE.PNG ├── WEAPON_BRIEFCASE_02.PNG ├── WEAPON_BULLPUPRIFLE.png ├── WEAPON_BULLPUPRIFLE_MK2.png ├── WEAPON_BULLPUPSHOTGUN.png ├── WEAPON_BZGAS.png ├── WEAPON_CANDYCANE.png ├── WEAPON_CARBINERIFLE.png ├── WEAPON_CARBINERIFLE_MK2.png ├── WEAPON_CERAMICPISTOL.png ├── WEAPON_COMBATMG.png ├── WEAPON_COMBATMG_MK2.png ├── WEAPON_COMBATPDW.png ├── WEAPON_COMBATPISTOL.png ├── WEAPON_COMBATSHOTGUN.png ├── WEAPON_COMPACTLAUNCHER.png ├── WEAPON_COMPACTRIFLE.png ├── WEAPON_CROWBAR.png ├── WEAPON_DAGGER.PNG ├── WEAPON_DBSHOTGUN.png ├── WEAPON_DIGISCANNER.png ├── WEAPON_DOUBLEACTION.png ├── WEAPON_EMPLAUNCHER.png ├── WEAPON_FERTILIZERCAN.png ├── WEAPON_FIREEXTINGUISHER.png ├── WEAPON_FIREWORK.png ├── WEAPON_FLARE.png ├── WEAPON_FLAREGUN.png ├── WEAPON_FLASHLIGHT.png ├── WEAPON_GADGETPISTOL.png ├── WEAPON_GARBAGEBAG.PNG ├── WEAPON_GAS.PNG ├── WEAPON_GOLFCLUB.png ├── WEAPON_GRENADE.png ├── WEAPON_GRENADELAUNCHER.png ├── WEAPON_GRENADELAUNCHER_SMOKE.PNG ├── WEAPON_GUSENBERG.png ├── WEAPON_HAMMER.png ├── WEAPON_HANDCUFFS.PNG ├── WEAPON_HATCHET.png ├── WEAPON_HAZARDCAN.png ├── WEAPON_HEAVYPISTOL.png ├── WEAPON_HEAVYRIFLE.png ├── WEAPON_HEAVYSHOTGUN.png ├── WEAPON_HEAVYSNIPER.png ├── WEAPON_HEAVYSNIPER_MK2.png ├── WEAPON_HOMINGLAUNCHER.png ├── WEAPON_KNIFE.png ├── WEAPON_KNUCKLE.png ├── WEAPON_LICENSE.PNG ├── WEAPON_MACHETE.png ├── WEAPON_MACHINEPISTOL.png ├── WEAPON_MARKSMANPISTOL.png ├── WEAPON_MARKSMANRIFLE.png ├── WEAPON_MARKSMANRIFLE_MK2.png ├── WEAPON_METALDETECTOR.png ├── WEAPON_MG.png ├── WEAPON_MICROSMG.png ├── WEAPON_MILITARYRIFLE.png ├── WEAPON_MINIGUN.png ├── WEAPON_MINISMG.png ├── WEAPON_MOLOTOV.png ├── WEAPON_MUSKET.png ├── WEAPON_NAVYREVOLVER.png ├── WEAPON_NIGHTSTICK.png ├── WEAPON_PETROLCAN.png ├── WEAPON_PIPEBOMB.png ├── WEAPON_PISTOL.png ├── WEAPON_PISTOL50.png ├── WEAPON_PISTOLXM3.png ├── WEAPON_PISTOL_MK2.png ├── WEAPON_POOLCUE.png ├── WEAPON_PRECISIONRIFLE.png ├── WEAPON_PROXMINE.png ├── WEAPON_PUMPSHOTGUN.png ├── WEAPON_PUMPSHOTGUN_MK2.png ├── WEAPON_RAILGUN.png ├── WEAPON_RAILGUNXM3.png ├── WEAPON_RAYCARBINE.png ├── WEAPON_RAYMINIGUN.png ├── WEAPON_RAYPISTOL.png ├── WEAPON_REVOLVER.png ├── WEAPON_REVOLVER_MK2.png ├── WEAPON_RPG.png ├── WEAPON_SAWNOFFSHOTGUN.png ├── WEAPON_SMG.png ├── WEAPON_SMG_MK2.png ├── WEAPON_SMOKEGRENADE.png ├── WEAPON_SNIPERRIFLE.png ├── WEAPON_SNOWBALL.png ├── WEAPON_SNSPISTOL.png ├── WEAPON_SNSPISTOL_MK2.png ├── WEAPON_SPECIALCARBINE.png ├── WEAPON_SPECIALCARBINE_MK2.png ├── WEAPON_STICKYBOMB.png ├── WEAPON_STONE_HATCHET.png ├── WEAPON_STUNGUN.png ├── WEAPON_SWITCHBLADE.png ├── WEAPON_TACTICALRIFLE.png ├── WEAPON_TECPISTOL.png ├── WEAPON_VINTAGEPISTOL.png ├── WEAPON_WRENCH.png ├── advancedkit.png ├── ammo-22.png ├── ammo-38.png ├── ammo-44.png ├── ammo-45.png ├── ammo-50.png ├── ammo-9.png ├── ammo-beanbag.png ├── ammo-emp.png ├── ammo-firework.PNG ├── ammo-flare.png ├── ammo-grenade.png ├── ammo-heavysniper.png ├── ammo-laser.png ├── ammo-musket.png ├── ammo-railgun.png ├── ammo-rifle.png ├── ammo-rifle2.png ├── ammo-rocket.png ├── ammo-shotgun.png ├── ammo-sniper.png ├── armour.png ├── at_barrel.png ├── at_clip_drum.png ├── at_clip_extended.png ├── at_clip_extended2.png ├── at_flashlight.png ├── at_flashlight_rifle.png ├── at_grip.png ├── at_muzzle_bell.png ├── at_muzzle_fat.png ├── at_muzzle_flat.png ├── at_muzzle_heavy.png ├── at_muzzle_precision'.png ├── at_muzzle_slanted.png ├── at_muzzle_split.png ├── at_muzzle_squared.png ├── at_muzzle_tactical.png ├── at_scope_advanced.png ├── at_scope_holo.png ├── at_scope_large.png ├── at_scope_medium.png ├── at_scope_nv.png ├── at_scope_small.png ├── at_scope_thermal.png ├── at_suppressor.png ├── bandage.png ├── beer.png ├── black_money.png ├── bsfries.png ├── burger.png ├── burger_chicken.png ├── candy.png ├── card_bank.png ├── card_id.png ├── carkey.png ├── carokit.png ├── chipscheese.png ├── chipshabanero.png ├── chipsribs.png ├── chipssalt.png ├── cigarettes_redwood.png ├── cocaine.png ├── cola.png ├── copper.png ├── diamond.png ├── donut.png ├── drug_blue.png ├── drug_red.png ├── drug_white.png ├── evidence.png ├── fertilizer.png ├── fixkit.png ├── fries.png ├── garbage.png ├── gold.png ├── head.png ├── hotdog.png ├── iron.png ├── joint.png ├── key.png ├── keys.png ├── larm.png ├── lfoot.png ├── lockpick.png ├── lowerbody.png ├── lpalm.png ├── medikit.png ├── meth.png ├── money.png ├── mustard.png ├── neck.png ├── necklace.png ├── oldkey.png ├── panties.png ├── paperbag.png ├── parachute.png ├── pepperoni.png ├── phone.png ├── pizza_ham.png ├── pizza_ham_box.png ├── pizza_ham_slice.png ├── radio.png ├── ramen.png ├── rarm.png ├── readme.md ├── rfoot.png ├── rolex.png ├── rpalm.png ├── scrapmetal.png ├── silver.png ├── small_armour.png ├── sprunk.png ├── taco.png ├── trash.png ├── trash_bread.png ├── trash_burger.png ├── trash_burgershot.png ├── trash_can.png ├── trash_chips.png ├── trash_coffee.png ├── trash_fags.png ├── trash_newspaper.png ├── trash_paper.png ├── turkey.png ├── upperbody.png ├── usb_black.png ├── water.png ├── weed.png └── ziptie.png ├── index.html ├── package.json ├── src ├── App.tsx ├── SVG │ ├── Arrowleft.tsx │ ├── Arrowright.tsx │ ├── Earings.tsx │ ├── Glasses.tsx │ ├── Gloves.tsx │ ├── Hand.tsx │ ├── Jacket.tsx │ ├── Pants.tsx │ ├── Shirt.tsx │ ├── Shoes.tsx │ ├── Tie.tsx │ ├── Vest.tsx │ ├── durablity.tsx │ └── head.tsx ├── components │ ├── inventory │ │ ├── BodyDamge.tsx │ │ ├── InventoryContext.tsx │ │ ├── InventoryControl.tsx │ │ ├── InventoryGrid.tsx │ │ ├── InventoryHotbar.tsx │ │ ├── InventorySlot.tsx │ │ ├── LeftInventory.tsx │ │ ├── RightInventory.tsx │ │ ├── SlotTooltip.tsx │ │ ├── UsefulControls.tsx │ │ └── index.tsx │ └── utils │ │ ├── Divider.tsx │ │ ├── DragPreview.tsx │ │ ├── ItemNotifications.tsx │ │ ├── KeyPress.tsx │ │ ├── Tooltip.tsx │ │ ├── WeightBar.tsx │ │ ├── icons │ │ └── ClockIcon.tsx │ │ ├── menu │ │ └── Menu.tsx │ │ └── transitions │ │ ├── Fade.tsx │ │ └── SlideUp.tsx ├── dnd │ ├── onBuy.ts │ ├── onCraft.ts │ ├── onDrop.ts │ ├── onGive.ts │ └── onUse.ts ├── helpers │ └── index.ts ├── hooks │ ├── useDebounce.ts │ ├── useExitListener.ts │ ├── useIntersection.ts │ ├── useKeyPress.ts │ ├── useNuiEvent.ts │ └── useQueue.ts ├── index.scss ├── main.tsx ├── reducers │ ├── index.ts │ ├── moveSlots.ts │ ├── refreshSlots.ts │ ├── setupInventory.ts │ ├── stackSlots.ts │ └── swapSlots.ts ├── store │ ├── contextMenu.ts │ ├── damage.ts │ ├── imagepath.ts │ ├── index.ts │ ├── inventory.ts │ ├── items.ts │ ├── locale.ts │ └── tooltip.ts ├── thunks │ ├── buyItem.ts │ ├── craftItem.ts │ └── validateItems.ts ├── typings │ ├── dnd.ts │ ├── index.ts │ ├── inventory.ts │ ├── item.ts │ ├── slot.ts │ └── state.ts ├── utils │ ├── Body.tsx │ ├── debugData.ts │ ├── fetchNui.ts │ ├── img │ │ ├── LLEG.png │ │ ├── RLEG.png │ │ ├── head.png │ │ ├── larm.png │ │ ├── lfoot.png │ │ ├── lowerbody.png │ │ ├── lpalm.png │ │ ├── neck.png │ │ ├── rarm.png │ │ ├── rfoot.png │ │ ├── rpalm.png │ │ └── upperbody.png │ ├── misc.ts │ └── setClipboard.ts └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | insert_final_newline = true 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | indent_size = 2 12 | indent_style = space 13 | 14 | [*.lua] 15 | indent_size = 4 16 | indent_style = space 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | modules/logs/**/ 2 | .cfg 3 | node_modules 4 | .idea -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["overextended.cfxlua-vscode", "sumneko.lua"] 3 | } 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Found a bug? 2 | - Check if the bug has already been reported under under [Issues](https://github.com/overextended/ox_inventory/issues). 3 | - If an **active** issue matches your own, provide additional information on the existing issue. 4 | - If there is no **open** issue related to the bug, create a new issue. Include a **descriptive title and clear description** with as much relevant information as possible, and include **code samples** or **reproduction steps**. 5 | - Use the relevant bug report template when creating an issue. 6 | 7 | ## Patched a bug? 8 | - Open a new pull request including **only** the related changes. 9 | - Clearly describe the problem being fixed, and the solution. If the patch resolves any issues, mention them in the description. 10 | 11 | ## Want to share an improvement or add a new feature? 12 | - Create an issue discussing the change and wait for feedback. 13 | - If you've already worked on the change you can submit a **draft** pull request for feedback and review. 14 | - Not all features and changes are desired! Changes may be messy, poorly-planned, incomplete, or simply incompatible with our design philosophy. 15 | 16 | ## Is your change cosmetic (e.g. formatting)? 17 | - We will not accept pull requests that do not make substantial changes to the stability or functionality of the resource. 18 | -------------------------------------------------------------------------------- /data/animations.lua: -------------------------------------------------------------------------------- 1 | return { 2 | anim = { 3 | ['eating'] = { dict = 'mp_player_inteat@burger', clip = 'mp_player_int_eat_burger_fp' }, 4 | }, 5 | prop = { 6 | ['burger'] = { model = `prop_cs_burger_01`, pos = vec3(0.02, 0.02, -0.02), rot = vec3(0.0, 0.0, 0.0) }, 7 | } 8 | } -------------------------------------------------------------------------------- /data/crafting.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | items = { 4 | { 5 | name = 'lockpick', 6 | ingredients = { 7 | scrapmetal = 5, 8 | WEAPON_HAMMER = 0.05 9 | }, 10 | duration = 5000, 11 | count = 2, 12 | }, 13 | }, 14 | points = { 15 | vec3(-1147.083008, -2002.662109, 13.180260), 16 | vec3(-345.374969, -130.687088, 39.009613) 17 | }, 18 | zones = { 19 | { 20 | coords = vec3(-1146.2, -2002.05, 13.2), 21 | size = vec3(3.8, 1.05, 0.15), 22 | distance = 1.5, 23 | rotation = 315.0, 24 | }, 25 | { 26 | coords = vec3(-346.1, -130.45, 39.0), 27 | size = vec3(3.8, 1.05, 0.15), 28 | distance = 1.5, 29 | rotation = 70.0, 30 | }, 31 | }, 32 | blip = { id = 566, colour = 31, scale = 0.8 }, 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /data/evidence.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | coords = vec3(458.97, -982.79, 30.68), 4 | target = { -- qtarget support 5 | name = 'mrpd_evidence', -- name of zone must be uniuqe 6 | loc = vec3(459.07, -984.07, 30.69), 7 | length = 1.4, 8 | width = 3.2, 9 | heading = 0, 10 | minZ = 29.09, 11 | maxZ = 31.89 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /data/licenses.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { name = 'weapon', coords = vec3(12.42198, -1105.82, 29.7854), price = 5000 } 3 | } -------------------------------------------------------------------------------- /data/stashes.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | coords = vec3(452.3, -991.4, 30.7), 4 | target = { 5 | loc = vec3(451.25, -994.28, 30.69), 6 | length = 1.2, 7 | width = 5.6, 8 | heading = 0, 9 | minZ = 29.49, 10 | maxZ = 32.09, 11 | label = 'Open personal locker' 12 | }, 13 | name = 'policelocker', 14 | label = 'Personal locker', 15 | owner = true, 16 | slots = 70, 17 | weight = 70000, 18 | groups = shared.police 19 | }, 20 | 21 | { 22 | coords = vec3(301.3, -600.23, 43.28), 23 | target = { 24 | loc = vec3(301.82, -600.99, 43.29), 25 | length = 0.6, 26 | width = 1.8, 27 | heading = 340, 28 | minZ = 43.34, 29 | maxZ = 44.74, 30 | label = 'Open personal locker' 31 | }, 32 | name = 'emslocker', 33 | label = 'Personal Locker', 34 | owner = true, 35 | slots = 70, 36 | weight = 70000, 37 | groups = {['ambulance'] = 0} 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /data/vehicles.lua: -------------------------------------------------------------------------------- 1 | return { 2 | -- 0 vehicle has no storage 3 | -- 1 vehicle has no trunk storage 4 | -- 2 vehicle has no glovebox storage 5 | -- 3 vehicle has trunk in the hood 6 | Storage = { 7 | [`jester`] = 3, 8 | [`adder`] = 3, 9 | [`osiris`] = 1, 10 | [`pfister811`] = 1, 11 | [`penetrator`] = 1, 12 | [`autarch`] = 1, 13 | [`bullet`] = 1, 14 | [`cheetah`] = 1, 15 | [`cyclone`] = 1, 16 | [`voltic`] = 1, 17 | [`reaper`] = 3, 18 | [`entityxf`] = 1, 19 | [`t20`] = 1, 20 | [`taipan`] = 1, 21 | [`tezeract`] = 1, 22 | [`torero`] = 3, 23 | [`turismor`] = 1, 24 | [`fmj`] = 1, 25 | [`infernus`] = 1, 26 | [`italigtb`] = 3, 27 | [`italigtb2`] = 3, 28 | [`nero2`] = 1, 29 | [`vacca`] = 3, 30 | [`vagner`] = 1, 31 | [`visione`] = 1, 32 | [`prototipo`] = 1, 33 | [`zentorno`] = 1, 34 | [`trophytruck`] = 0, 35 | [`trophytruck2`] = 0, 36 | }, 37 | 38 | -- slots, maxWeight; default weight is 8000 per slot 39 | glovebox = { 40 | [0] = {11, 88000}, -- Compact 41 | [1] = {11, 88000}, -- Sedan 42 | [2] = {11, 88000}, -- SUV 43 | [3] = {11, 88000}, -- Coupe 44 | [4] = {11, 88000}, -- Muscle 45 | [5] = {11, 88000}, -- Sports Classic 46 | [6] = {11, 88000}, -- Sports 47 | [7] = {11, 88000}, -- Super 48 | [8] = {5, 40000}, -- Motorcycle 49 | [9] = {11, 88000}, -- Offroad 50 | [10] = {11, 88000}, -- Industrial 51 | [11] = {11, 88000}, -- Utility 52 | [12] = {11, 88000}, -- Van 53 | [14] = {31, 248000}, -- Boat 54 | [15] = {31, 248000}, -- Helicopter 55 | [16] = {51, 408000}, -- Plane 56 | [17] = {11, 88000}, -- Service 57 | [18] = {11, 88000}, -- Emergency 58 | [19] = {11, 88000}, -- Military 59 | [20] = {11, 88000}, -- Commercial (trucks) 60 | models = { 61 | [`xa21`] = {11, 88000} 62 | } 63 | }, 64 | 65 | trunk = { 66 | [0] = {21, 168000}, -- Compact 67 | [1] = {41, 328000}, -- Sedan 68 | [2] = {51, 408000}, -- SUV 69 | [3] = {31, 248000}, -- Coupe 70 | [4] = {41, 328000}, -- Muscle 71 | [5] = {31, 248000}, -- Sports Classic 72 | [6] = {31, 248000}, -- Sports 73 | [7] = {21, 168000}, -- Super 74 | [8] = {5, 40000}, -- Motorcycle 75 | [9] = {51, 408000}, -- Offroad 76 | [10] = {51, 408000}, -- Industrial 77 | [11] = {41, 328000}, -- Utility 78 | [12] = {61, 488000}, -- Van 79 | -- [14] -- Boat 80 | -- [15] -- Helicopter 81 | -- [16] -- Plane 82 | [17] = {41, 328000}, -- Service 83 | [18] = {41, 328000}, -- Emergency 84 | [19] = {41, 328000}, -- Military 85 | [20] = {61, 488000}, -- Commercial 86 | models = { 87 | [`xa21`] = {11, 10000} 88 | }, 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'cerulean' 2 | use_experimental_fxv2_oal 'yes' 3 | lua54 'yes' 4 | game 'gta5' 5 | name 'ox_inventory' 6 | author 'Overextended' 7 | version '2.38.1' 8 | repository 'https://github.com/overextended/ox_inventory' 9 | description 'Slot-based inventory with item metadata support' 10 | 11 | dependencies { 12 | '/server:6116', 13 | '/onesync', 14 | 'oxmysql', 15 | 'ox_lib', 16 | 'BC_Wounding' 17 | } 18 | 19 | shared_script '@ox_lib/init.lua' 20 | 21 | ox_libs { 22 | 'locale', 23 | 'table', 24 | 'math', 25 | } 26 | 27 | server_scripts { 28 | '@oxmysql/lib/MySQL.lua', 29 | 'init.lua' 30 | } 31 | 32 | client_script 'init.lua' 33 | 34 | ui_page 'web/build/index.html' 35 | 36 | files { 37 | 'client.lua', 38 | 'server.lua', 39 | 'locales/*.json', 40 | 'web/build/index.html', 41 | 'web/build/assets/*.js', 42 | 'web/build/assets/*.css', 43 | 'web/images/*.png', 44 | 'modules/**/shared.lua', 45 | 'modules/**/client.lua', 46 | 'modules/bridge/**/client.lua', 47 | 'data/*.lua', 48 | } 49 | -------------------------------------------------------------------------------- /locales/ko.json: -------------------------------------------------------------------------------- 1 | { 2 | "ui_use": "사용", 3 | "ui_give": "건네기", 4 | "ui_close": "닫기", 5 | "ui_drop": "떨구기", 6 | "ui_removeattachments": "부착물 제거", 7 | "ui_durability": "내구도", 8 | "ui_ammo": "탄약", 9 | "ui_serial": "시리얼 넘버", 10 | "ui_components": "컴포넌트", 11 | "ui_tint": "색조", 12 | "ui_usefulcontrols": "도움말", 13 | "ui_rmb": "아이템 컨메뉴 열기", 14 | "ui_ctrl_lmb": "다른 인벤토리로 빠르게 옮기기", 15 | "ui_shift_drag": "아이템 절반으로 나누기", 16 | "ui_ctrl_shift_lmb": "절반 아이템 빠르게 옮기기", 17 | "ui_alt_lmb": "퀵사용", 18 | "$": "$", 19 | "male": "남성", 20 | "female": "여성", 21 | "used": "사용된", 22 | "ui_removed": "사라짐", 23 | "ui_added": "추가됨", 24 | "ui_holstered": "Holstered", 25 | "ui_equipped": "장착됨", 26 | "using": "사용 %s", 27 | "inventory_setup": "인벤토리 사용이 준비되었습니다!", 28 | "inventory_player_access": "당신은 지금 인벤토리를 열 수 없어요.", 29 | "inventory_right_access": "당신은 이 인벤토리를 열 수 없어요.", 30 | "inventory_lost_access": "더 이상 이 인벤토리에 액세스할 수 없습니다.", 31 | "wrong_ammo": "%s 탄약을 %s 탄약으로 로드할 수 없습니다.", 32 | "weapon_license": "무기 라이센스", 33 | "already_have": "당신은 이미 무기 라이센스를 가지고 있습니다", 34 | "have_purchased": "무기 라이센스를 구매했습니다", 35 | "can_not_afford": "당신은 무기 라이센스를 감당할 수 없습니다", 36 | "purchase_license": "라이선스 구매", 37 | "interact_prompt": "Interact with [%s]", 38 | "weapon_unregistered": "%s은(는) 누구에게도 등록되지 않았습니다.", 39 | "weapon_registered": "%s(%s)이(가) %s에 등록되었습니다.", 40 | "weapon_broken": "이 무기는 고장났다", 41 | "vehicle_locked": "차량이 잠겨 있습니다", 42 | "nobody_nearby": "근처에 아무도 없다", 43 | "give_amount": "제공할 금액을 입력해야 합니다.", 44 | "buy_amount": "구매하려면 금액을 입력해야 합니다.", 45 | "component_has": "이 무기에는 이미 %s이(가) 있습니다.", 46 | "component_invalid": "이 무기는 %s과(와) 호환되지 않습니다.", 47 | "cannot_perform": "이 작업을 수행할 수 없습니다.", 48 | "cannot_carry": "당신은 그렇게 많이 가지고 갈 수 없습니다", 49 | "cannot_carry_other": "대상 인벤토리는 그렇게 많이 보유할 수 없습니다.", 50 | "cannot_carry_limit": "%s %s을(를) 초과할 수 없습니다.", 51 | "cannot_carry_limit_other": "대상은 %s %s을(를) 초과할 수 없습니다.", 52 | "items_confiscated": "귀하의 물품이 압수되었습니다.", 53 | "items_returned": "귀하의 항목이 반환되었습니다", 54 | "item_unauthorised": "이 항목을 구매할 권한이 없습니다.", 55 | "item_unlicensed": "이 항목을 구매할 수 있는 권한이 없습니다.", 56 | "item_not_enough": "%s이(가) 충분하지 않습니다.", 57 | "cannot_afford": "당신은 그것을 감당할 수 없습니다(%s 누락)", 58 | "stash_lowgrade": "이 항목을 가져갈 권한이 없습니다.", 59 | "cannot_use": "%s을(를) 사용할 수 없습니다.", 60 | "shop_nostock": "품목이 품절되었습니다", 61 | "identification": "성별:%s 생년월일: %s", 62 | "search_dumpster": "쓰레기 수거통 검색", 63 | "open_label": "열기 %s", 64 | "purchased_for": "%s %s을(를) %s%s에 대해 구매했습니다.", 65 | "unable_stack_items": "이 항목을 쌓을 수 없습니다", 66 | "police_evidence": "경찰 증거물", 67 | "open_police_evidence": "경찰 증거물 열기", 68 | "open_stash": "보관함 열기", 69 | "locker_number": "로커 번호", 70 | "locker_no_value": "사물함을 열려면 값이 있어야 합니다.", 71 | "locker_must_number": "사물함은 숫자여야 합니다.", 72 | "weapon_hand_required": "당신은 손에 무기가 있어야합니다", 73 | "weapon_hand_wrong": "손에 잘못된 무기", 74 | "open_player_inventory": "플레이어 인벤토리를 엽니다~", 75 | "open_secondary_inventory": "2차 인벤토리 열기~", 76 | "disable_hotbar": "인벤토리 핫바 표시~", 77 | "reload_weapon": "무기 재장전~", 78 | "use_hotbar": "핫바 항목 %s 사용~", 79 | "no_durability": "%s 내구도가 고갈되었습니다", 80 | "cannot_give": "대상에 %s %s을(를) 제공할 수 없습니다.", 81 | "evidence_cannot_take": "증거로 삼을 만큼 등급이 높지 않음", 82 | "dumpster": "쓰레기 수거통" 83 | } 84 | -------------------------------------------------------------------------------- /locales/zh-cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "ui_use": "使用", 3 | "ui_give": "给予", 4 | "ui_close": "关闭", 5 | "ui_drop": "丢掉", 6 | "ui_removeattachments": "删除附件", 7 | "ui_copy": "复制序列号", 8 | "ui_durability": "耐久性", 9 | "ui_ammo": "弹药", 10 | "ui_serial": "编号", 11 | "ui_components": "组件", 12 | "ui_tint": "色调", 13 | "ui_usefulcontrols": "实用控件", 14 | "ui_rmb": "打开物品菜单", 15 | "ui_ctrl_lmb": "快速将一堆物品移动到另一个物品栏中", 16 | "ui_shift_drag": "将项目数量分成两份", 17 | "ui_ctrl_shift_lmb": "快速将一半物品移动到另一个物品栏中", 18 | "ui_alt_lmb": "快速使用物品", 19 | "ui_ctrl_c": "当悬停在武器上时,复制其序列号", 20 | "ui_remove_ammo": "移除弹药", 21 | "ammo_type": "弹药类型", 22 | "$": "$", 23 | "male": "男性", 24 | "female": "女性", 25 | "used": "使用过", 26 | "ui_removed": "已移除", 27 | "ui_added": "添加", 28 | "ui_holstered": "已收回", 29 | "ui_equipped": "已装备", 30 | "using": "使用 %s", 31 | "inventory_setup": "物品栏已就绪", 32 | "inventory_player_access": "您现在无法打开物品栏", 33 | "inventory_right_access": "您无法打开此物品栏", 34 | "inventory_lost_access": "无法再访问此物品栏", 35 | "wrong_ammo": "您不能用 %s 弹药加载 %s", 36 | "license": "%s 许可证", 37 | "already_have": "您已经拥有 %s 许可证", 38 | "have_purchased": "您已购买 %s 许可证", 39 | "can_not_afford": "您买不起 %s 许可证", 40 | "purchase_license": "购买 %s 许可证", 41 | "interact_prompt": "[%s] 进行交互", 42 | "weapon_unregistered": "%s 未向任何人注册", 43 | "weapon_registered": "%s (%s) 注册到 %s", 44 | "weapon_broken": "这武器坏了", 45 | "vehicle_locked": "车辆已锁定", 46 | "nobody_nearby": "附近没有人", 47 | "give_amount": "您必须输入金额", 48 | "buy_amount": "您必须输入购买金额", 49 | "component_has": "这把武器已经有了 %s", 50 | "component_invalid": "此武器不兼容 %s", 51 | "component_slot_occupied": "该武器的 %s 插槽已被占用", 52 | "cannot_perform": "您无法执行此操作", 53 | "cannot_carry": "您不能带那么多", 54 | "cannot_carry_other": "目标物品栏不能容纳这些物品", 55 | "cannot_carry_limit": "您不能携带超过 %s %s", 56 | "cannot_carry_limit_other": "目标不能携带超过 %s %s", 57 | "items_confiscated": "您的物品已被没收", 58 | "items_returned": "您的物品已被退回", 59 | "item_unauthorised": "您无权购买此商品", 60 | "item_unlicensed": "您无权购买此商品", 61 | "item_not_enough": "您没有足够的 %s", 62 | "cannot_afford": "您买不起 (需要 %s)", 63 | "stash_lowgrade": "您无权携带此物品", 64 | "cannot_use": "无法使用 %s", 65 | "shop_nostock": "商品缺货", 66 | "identification": "性别: %s \n出生日期: %s", 67 | "search_dumpster": "搜索垃圾箱", 68 | "open_label": "打开 %s", 69 | "purchased_for": "已购买 %s %s %s%s", 70 | "unable_stack_items": "您无法堆叠这些物品", 71 | "police_evidence": "警方物证仓库", 72 | "open_police_evidence": "打开警方物证仓库", 73 | "open_stash": "打开藏匿处", 74 | "locker_number": "储物柜号码", 75 | "locker_no_value": "必须包含打开储物柜的号码", 76 | "locker_must_number": "储物柜号码必须是数字", 77 | "weapon_hand_required": "您手上必须有武器", 78 | "weapon_hand_wrong": "拿错了武器", 79 | "open_player_inventory": "打开玩家物品栏~", 80 | "open_secondary_inventory": "打开二级物品栏~", 81 | "disable_hotbar": "显示物品栏快捷栏~", 82 | "reload_weapon": "重装武器~", 83 | "use_hotbar": "使用快捷栏 %s~", 84 | "no_durability": "%s 耐久已耗尽", 85 | "cannot_give": "无法将 %s %s 交给目标", 86 | "evidence_cannot_take": "您无权撤回证据", 87 | "dumpster": "垃圾箱", 88 | "crafting_item": "制作 %s", 89 | "crafting_bench": "工作台", 90 | "open_crafting_bench": "打开工作台", 91 | "not_enough_durability": "%s 没有足够的耐久度", 92 | "storage": "储物柜" 93 | } -------------------------------------------------------------------------------- /locales/zh-tw.json: -------------------------------------------------------------------------------- 1 | { 2 | "ui_use": "使用", 3 | "ui_give": "給予", 4 | "ui_close": "關閉", 5 | "ui_drop": "丟下", 6 | "ui_removeattachments": "移除配件", 7 | "ui_copy": "複製序列號", 8 | "ui_durability": "耐久度", 9 | "ui_ammo": "彈藥", 10 | "ui_serial": "序列號", 11 | "ui_components": "附加組件", 12 | "ui_tint": "塗裝", 13 | "ui_usefulcontrols": "有效的操作", 14 | "ui_rmb": "打開快捷選單", 15 | "ui_ctrl_lmb": "快速移交物品", 16 | "ui_shift_drag": "將物品數量分成一半", 17 | "ui_ctrl_shift_lmb": "快捷移交一半的物品", 18 | "ui_alt_lmb": "物品快捷使用", 19 | "ui_ctrl_c": "將鼠標懸停在武器上時,複製其序列號", 20 | "ui_remove_ammo": "移除彈藥", 21 | "ammo_type": "彈藥類型", 22 | "$": "$", 23 | "male": "男", 24 | "female": "女", 25 | "used": "使用", 26 | "ui_removed": "移除了", 27 | "ui_added": "增加了", 28 | "ui_holstered": "收起武器", 29 | "ui_equipped": "裝備武器", 30 | "using": "使用 %s 中", 31 | "inventory_setup": "庫存已可以開啟", 32 | "inventory_player_access": "你現在無法開啟背包", 33 | "inventory_right_access": "你無法開啟這個物品庫", 34 | "inventory_lost_access": "無權力開啟這個物品庫", 35 | "wrong_ammo": "在 %s 上裝填 %s 時裝填失敗,彈藥類型錯誤", 36 | "license": "%s 許可證", 37 | "already_have": "你已擁有 %s 許可證", 38 | "have_purchased": "你購買了 %s 許可證", 39 | "can_not_afford": "你沒有足夠的金錢購買 %s 許可證", 40 | "purchase_license": "購買 %s 許可證", 41 | "interact_prompt": "[%s] 進行互動", 42 | "weapon_unregistered": "%s 沒有任何人註冊", 43 | "weapon_registered": "%s (%s) 註冊於 %s", 44 | "weapon_broken": "這把武器壞掉了", 45 | "vehicle_locked": "此載具是鎖上的", 46 | "nobody_nearby": "沒有任何人在附近", 47 | "give_amount": "你必須輸入要給予的數量", 48 | "buy_amount": "你必須輸入要購買的數量", 49 | "component_has": "這個武器已經有 %s", 50 | "component_invalid": "這個武器與 %s 不相容", 51 | "component_slot_occupied": "這個武器的 %s 位置已有其他同類型組件", 52 | "cannot_perform": "無法執行這個動作", 53 | "cannot_carry": "背包重量已達限制", 54 | "cannot_carry_other": "目標攜帶重量已達限制", 55 | "cannot_carry_limit": "你無法攜帶超過 %s %s", 56 | "cannot_carry_limit_other": "目標無法攜帶超過 %s %s", 57 | "items_confiscated": "物品已被沒收", 58 | "items_returned": "物品已被歸還", 59 | "item_unauthorised": "無權購買此商品", 60 | "item_unlicensed": "無購買此物品的許可", 61 | "item_not_enough": "你沒有足夠的 %s", 62 | "cannot_afford": "無法得到該物品 (缺少 %s)", 63 | "stash_lowgrade": "無權獲取此物品", 64 | "cannot_use": " %s 無法使用", 65 | "shop_nostock": "此商品缺貨中", 66 | "identification": "性別: %s \n生日: %s", 67 | "search_dumpster": "搜索垃圾桶", 68 | "open_label": "打開 %s", 69 | "purchased_for": "購買了 %s 個 %s 花了 %s%s", 70 | "unable_stack_items": "你無法堆疊此物品", 71 | "police_evidence": "警用證物櫃", 72 | "open_police_evidence": "打開警用證物櫃", 73 | "open_stash": "打開藏匿箱", 74 | "locker_number": "證物箱編號", 75 | "locker_no_value": "必須輸入編號來打開證物箱", 76 | "locker_must_number": "證物箱編號必須為數字", 77 | "weapon_hand_required": "你必須手持武器", 78 | "weapon_hand_wrong": "手持錯誤的武器", 79 | "open_player_inventory": "打開背包~", 80 | "open_secondary_inventory": "打開手套箱~", 81 | "disable_hotbar": "顯示物品快捷欄~", 82 | "reload_weapon": "武器裝填~", 83 | "use_hotbar": "使用快捷欄物品 %s~", 84 | "no_durability": "物品耐久度已耗盡", 85 | "cannot_give": "無法將 %s %s 給予目標 ", 86 | "evidence_cannot_take": "階級不夠,無法拿取證物", 87 | "dumpster": "垃圾桶", 88 | "crafting_item": "製作 %s", 89 | "crafting_bench": "工作台", 90 | "open_crafting_bench": "打開工作台", 91 | "not_enough_durability": "%s 沒有足夠的耐久度", 92 | "storage": "儲櫃" 93 | } 94 | -------------------------------------------------------------------------------- /modules/bridge/client.lua: -------------------------------------------------------------------------------- 1 | if not lib then return end 2 | 3 | ---@diagnostic disable-next-line: duplicate-set-field 4 | function client.setPlayerData(key, value) 5 | PlayerData[key] = value 6 | OnPlayerData(key, value) 7 | end 8 | 9 | function client.hasGroup(group) 10 | if not PlayerData.loaded then return end 11 | 12 | if type(group) == 'table' then 13 | for name, rank in pairs(group) do 14 | local groupRank = PlayerData.groups[name] 15 | if groupRank and groupRank >= (rank or 0) then 16 | return name, groupRank 17 | end 18 | end 19 | else 20 | local groupRank = PlayerData.groups[group] 21 | if groupRank then 22 | return group, groupRank 23 | end 24 | end 25 | end 26 | 27 | local Shops = require 'modules.shops.client' 28 | local Utils = require 'modules.utils.client' 29 | local Weapon = require 'modules.weapon.client' 30 | 31 | function client.onLogout() 32 | if not PlayerData.loaded then return end 33 | 34 | if client.parachute then 35 | Utils.DeleteEntity(client.parachute) 36 | client.parachute = false 37 | end 38 | 39 | for _, point in pairs(client.drops) do 40 | if point.entity then 41 | Utils.DeleteEntity(point.entity) 42 | end 43 | 44 | point:remove() 45 | end 46 | 47 | PlayerData.loaded = false 48 | client.drops = nil 49 | 50 | client.closeInventory() 51 | Shops.wipeShops() 52 | 53 | if client.interval then 54 | ClearInterval(client.interval) 55 | ClearInterval(client.tick) 56 | end 57 | 58 | Weapon.Disarm() 59 | end 60 | 61 | local success, result = pcall(lib.load, ('modules.bridge.%s.client'):format(shared.framework)) 62 | 63 | if not success then 64 | lib.print.error(result) 65 | lib = nil 66 | return 67 | end 68 | -------------------------------------------------------------------------------- /modules/bridge/esx/client.lua: -------------------------------------------------------------------------------- 1 | local ESX = setmetatable({}, { 2 | __index = function(self, index) 3 | local obj = exports.es_extended:getSharedObject() 4 | self.SetPlayerData = obj.SetPlayerData 5 | self.PlayerLoaded = obj.PlayerLoaded 6 | return self[index] 7 | end 8 | }) 9 | 10 | ---@diagnostic disable-next-line: duplicate-set-field 11 | function client.setPlayerData(key, value) 12 | PlayerData[key] = value 13 | ESX.SetPlayerData(key, value) 14 | end 15 | 16 | ---@diagnostic disable-next-line: duplicate-set-field 17 | function client.setPlayerStatus(values) 18 | for name, value in pairs(values) do 19 | if value > 0 then TriggerEvent('esx_status:add', name, value) else TriggerEvent('esx_status:remove', name, -value) end 20 | end 21 | end 22 | 23 | RegisterNetEvent('esx:onPlayerLogout', client.onLogout) 24 | 25 | AddEventHandler('esx:setPlayerData', function(key, value) 26 | if not PlayerData.loaded or GetInvokingResource() ~= 'es_extended' then return end 27 | 28 | if key == 'job' then 29 | key = 'groups' 30 | value = { [value.name] = value.grade } 31 | end 32 | 33 | PlayerData[key] = value 34 | OnPlayerData(key, value) 35 | end) 36 | 37 | local Weapon = require 'modules.weapon.client' 38 | 39 | RegisterNetEvent('esx_policejob:handcuff', function() 40 | PlayerData.cuffed = not PlayerData.cuffed 41 | LocalPlayer.state:set('invBusy', PlayerData.cuffed, false) 42 | 43 | if not PlayerData.cuffed then return end 44 | 45 | Weapon.Disarm() 46 | end) 47 | 48 | RegisterNetEvent('esx_policejob:unrestrain', function() 49 | PlayerData.cuffed = false 50 | LocalPlayer.state:set('invBusy', PlayerData.cuffed, false) 51 | end) 52 | -------------------------------------------------------------------------------- /modules/bridge/nd/client.lua: -------------------------------------------------------------------------------- 1 | if not lib.checkDependency('ND_Core', '2.0.0', true) then return end 2 | 3 | NDCore = {} 4 | 5 | lib.load('@ND_Core.init') 6 | 7 | RegisterNetEvent("ND:characterUnloaded", client.onLogout) 8 | 9 | local function reorderGroups(groups) 10 | groups = groups or {} 11 | for group, info in pairs(groups) do 12 | groups[group] = info.rank 13 | end 14 | return groups 15 | end 16 | 17 | SetTimeout(500, function() 18 | local player = NDCore.getPlayer() 19 | if not player then return end 20 | local groups = reorderGroups(player.groups) 21 | OnPlayerData("groups", groups) 22 | end) 23 | 24 | RegisterNetEvent("ND:characterLoaded", function(character) 25 | local groups = reorderGroups(character.groups) 26 | OnPlayerData("groups", groups) 27 | end) 28 | 29 | RegisterNetEvent("ND:updateCharacter", function(character) 30 | PlayerData.dead = character.metadata.dead 31 | OnPlayerData("dead", PlayerData.dead) 32 | end) 33 | 34 | ---@diagnostic disable-next-line: duplicate-set-field 35 | function client.setPlayerStatus(values) 36 | if GetResourceState("ND_Status") ~= "started" then return end 37 | 38 | local status = exports["ND_Status"] 39 | 40 | for name, value in pairs(values) do 41 | 42 | if value > 100 or value < -100 then 43 | value = value * 0.0001 44 | end 45 | 46 | status:changeStatus(name, value) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /modules/bridge/ox/client.lua: -------------------------------------------------------------------------------- 1 | CreateThread(function() lib.load('@ox_core.imports.client') end) 2 | 3 | RegisterNetEvent('ox:playerLogout', client.onLogout) 4 | 5 | RegisterNetEvent('ox:setGroup', function(name, grade) 6 | PlayerData.groups[name] = grade 7 | OnPlayerData('groups') 8 | end) 9 | 10 | ---@diagnostic disable-next-line: duplicate-set-field 11 | function client.setPlayerStatus(values) 12 | for name, value in pairs(values) do 13 | -- Thanks to having status values setup out of 1000000 (matching esx_status's standard) 14 | -- we need to awkwardly change the value 15 | if value > 100 or value < -100 then 16 | -- Hunger and thirst start at 0 and go up to 100 as you get hungry/thirsty (inverse of ESX) 17 | if (name == 'hunger' or name == 'thirst') then 18 | value = -value 19 | end 20 | 21 | value = value * 0.0001 22 | end 23 | 24 | ---@diagnostic disable-next-line: undefined-global 25 | player.addStatus(name, value) 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /modules/bridge/ox/server.lua: -------------------------------------------------------------------------------- 1 | CreateThread(function() lib.load('@ox_core.imports.server') end) 2 | 3 | local Inventory = require 'modules.inventory.server' 4 | 5 | AddEventHandler('ox:playerLogout', server.playerDropped) 6 | 7 | AddEventHandler('ox:setGroup', function(source, name, grade) 8 | local inventory = Inventory(source) 9 | if not inventory then return end 10 | inventory.player.groups[name] = grade 11 | end) 12 | 13 | ---@diagnostic disable-next-line: duplicate-set-field 14 | function server.hasLicense(inv, name) 15 | local player = Ox.GetPlayer(inv.id) 16 | return player.getLicense(name) 17 | end 18 | 19 | ---@diagnostic disable-next-line: duplicate-set-field 20 | function server.buyLicense(inv, license) 21 | local player = Ox.GetPlayer(inv.id) 22 | 23 | if player.getLicense(license.name) then 24 | return false, 'already_have' 25 | elseif Inventory.GetItem(inv, 'money', false, true) < license.price then 26 | return false, 'can_not_afford' 27 | end 28 | 29 | Inventory.RemoveItem(inv, 'money', license.price) 30 | player.addLicense(license.name) 31 | 32 | return true, 'have_purchased' 33 | end 34 | 35 | ---@diagnostic disable-next-line: duplicate-set-field 36 | function server.isPlayerBoss(playerId, group, grade) 37 | local groupData = GlobalState[('group.%s'):format(group)] 38 | 39 | return groupData and grade >= groupData.adminGrade 40 | end 41 | 42 | ---@param entityId number 43 | ---@return number | string 44 | function server.getOwnedVehicleId(entityId) 45 | return Ox.GetVehicle(entityId)?.id 46 | end 47 | -------------------------------------------------------------------------------- /modules/bridge/qb/client.lua: -------------------------------------------------------------------------------- 1 | local QBCore = exports['qb-core']:GetCoreObject() 2 | local Inventory = require 'modules.inventory.client' 3 | local Weapon = require 'modules.weapon.client' 4 | 5 | RegisterNetEvent('QBCore:Client:OnPlayerUnload', client.onLogout) 6 | 7 | RegisterNetEvent('QBCore:Player:SetPlayerData', function(data) 8 | if source == '' or not PlayerData.loaded then return end 9 | 10 | if (data.metadata.isdead or data.metadata.inlaststand) ~= PlayerData.dead then 11 | PlayerData.dead = data.metadata.isdead or data.metadata.inlaststand 12 | OnPlayerData('dead', PlayerData.dead) 13 | end 14 | 15 | local groups = PlayerData.groups 16 | 17 | if not groups[data.job.name] or not groups[data.gang.name] or groups[data.job.name] ~= data.job.grade.level or groups[data.gang.name] ~= data.gang.grade.level then 18 | PlayerData.groups = { 19 | [data.job.name] = data.job.grade.level, 20 | [data.gang.name] = data.gang.grade.level, 21 | } 22 | 23 | OnPlayerData('groups', PlayerData.groups) 24 | end 25 | end) 26 | 27 | RegisterNetEvent('police:client:GetCuffed', function() 28 | PlayerData.cuffed = not PlayerData.cuffed 29 | LocalPlayer.state:set('invBusy', PlayerData.cuffed, false) 30 | 31 | if not PlayerData.cuffed then return end 32 | 33 | Weapon.Disarm() 34 | end) 35 | 36 | ---@diagnostic disable-next-line: duplicate-set-field 37 | function client.setPlayerStatus(values) 38 | for name, value in pairs(values) do 39 | 40 | -- compatibility for ESX style values 41 | if value > 100 or value < -100 then 42 | value = value * 0.0001 43 | end 44 | 45 | if name == "hunger" then 46 | TriggerServerEvent('consumables:server:addHunger', QBCore.Functions.GetPlayerData().metadata.hunger + value) 47 | elseif name == "thirst" then 48 | TriggerServerEvent('consumables:server:addThirst', QBCore.Functions.GetPlayerData().metadata.thirst + value) 49 | elseif name == "stress" then 50 | if value > 0 then 51 | TriggerServerEvent('hud:server:GainStress', value) 52 | else 53 | value = math.abs(value) 54 | TriggerServerEvent('hud:server:RelieveStress', value) 55 | end 56 | end 57 | end 58 | end 59 | 60 | -- taken from qbox-core (https://github.com/Qbox-project/qb-core/blob/f4174f311aae8157181a48fa2e2bd30c8d13edb1/client/functions.lua#L25) 61 | local function hasItem(items, amount) 62 | amount = amount or 1 63 | 64 | local count = Inventory.Search('count', items) 65 | 66 | if type(items) == 'table' and type(count) == 'table' then 67 | for _, v in pairs(count) do 68 | if v < amount then 69 | return false 70 | end 71 | end 72 | 73 | return true 74 | end 75 | 76 | return count >= amount 77 | end 78 | 79 | AddStateBagChangeHandler('inv_busy', ('player:%s'):format(cache.serverId), function(_, _, value) 80 | LocalPlayer.state:set('invBusy', value, false) 81 | end) 82 | 83 | AddEventHandler(('__cfx_export_qb-inventory_HasItem'), function(setCB) 84 | setCB(hasItem) 85 | end) 86 | -------------------------------------------------------------------------------- /modules/bridge/server.lua: -------------------------------------------------------------------------------- 1 | ---@todo separate module into smaller submodules to handle each framework 2 | ---starting to get bulky 3 | 4 | function server.hasGroup(inv, group) 5 | if type(group) == 'table' then 6 | for name, rank in pairs(group) do 7 | local groupRank = inv.player.groups[name] 8 | if groupRank and groupRank >= (rank or 0) then 9 | return name, groupRank 10 | end 11 | end 12 | else 13 | local groupRank = inv.player.groups[group] 14 | if groupRank then 15 | return group, groupRank 16 | end 17 | end 18 | end 19 | 20 | ---@diagnostic disable-next-line: duplicate-set-field 21 | function server.setPlayerData(player) 22 | if not player.groups then 23 | warn(("server.setPlayerData did not receive any groups for '%s'"):format(player?.name or GetPlayerName(player))) 24 | end 25 | 26 | return { 27 | source = player.source, 28 | name = player.name, 29 | groups = player.groups or {}, 30 | sex = player.sex, 31 | dateofbirth = player.dateofbirth, 32 | } 33 | end 34 | 35 | ---@diagnostic disable-next-line: duplicate-set-field 36 | function server.buyLicense() 37 | warn('Licenses are not supported for the current framework.') 38 | end 39 | 40 | local Inventory = require 'modules.inventory.server' 41 | 42 | function server.playerDropped(source) 43 | local inv = Inventory(source) --[[@as OxInventory]] 44 | 45 | if inv?.player then 46 | inv:closeInventory() 47 | Inventory.Remove(inv) 48 | end 49 | end 50 | 51 | local success, result = pcall(lib.load, ('modules.bridge.%s.server'):format(shared.framework)) 52 | 53 | if not success then 54 | lib.print.error(result) 55 | lib = nil 56 | return 57 | end 58 | 59 | if server.convertInventory then exports('ConvertItems', server.convertInventory) end 60 | -------------------------------------------------------------------------------- /modules/crafting/client.lua: -------------------------------------------------------------------------------- 1 | if not lib then return end 2 | 3 | local CraftingBenches = {} 4 | local Items = require 'modules.items.client' 5 | local createBlip = require 'modules.utils.client'.CreateBlip 6 | 7 | ---@param id number 8 | ---@param data table 9 | local function createCraftingBench(id, data) 10 | CraftingBenches[id] = {} 11 | local recipes = data.items 12 | 13 | if recipes then 14 | data.slots = #recipes 15 | 16 | for i = 1, data.slots do 17 | local recipe = recipes[i] 18 | local item = Items[recipe.name] 19 | 20 | if item then 21 | recipe.weight = item.weight 22 | recipe.slot = i 23 | else 24 | warn(('failed to setup crafting recipe (bench: %s, slot: %s) - item "%s" does not exist'):format(id, i, recipe.name)) 25 | end 26 | end 27 | 28 | local blip = data.blip 29 | 30 | if blip then 31 | blip.name = blip.name or ('ox_crafting_%s'):format(data.label and id or 0) 32 | AddTextEntry(blip.name, data.label or locale('crafting_bench')) 33 | end 34 | 35 | if shared.target then 36 | data.points = nil 37 | if data.zones then 38 | for i = 1, #data.zones do 39 | local zone = data.zones[i] 40 | zone.name = ("craftingbench_%s:%s"):format(id, i) 41 | zone.id = id 42 | zone.index = i 43 | zone.options = { 44 | { 45 | label = zone.label or locale('open_crafting_bench'), 46 | canInteract = data.groups and function() 47 | return client.hasGroup(data.groups) 48 | end or nil, 49 | onSelect = function() 50 | client.openInventory('crafting', { id = id, index = i }) 51 | end, 52 | distance = zone.distance or 2.0, 53 | icon = zone.icon or 'fas fa-wrench', 54 | } 55 | } 56 | 57 | exports.ox_target:addBoxZone(zone) 58 | 59 | if blip then 60 | createBlip(blip, zone.coords) 61 | end 62 | end 63 | end 64 | elseif data.points then 65 | data.zones = nil 66 | 67 | ---@param point CPoint 68 | local function nearbyBench(point) 69 | ---@diagnostic disable-next-line: param-type-mismatch 70 | DrawMarker(2, point.coords.x, point.coords.y, point.coords.z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.2, 0.15, 150, 150, 30, 222, false, false, 0, true, false, false, false) 71 | 72 | if point.isClosest and point.currentDistance < 1.2 and IsControlJustReleased(0, 38) then 73 | client.openInventory('crafting', { id = point.benchid, index = point.index }) 74 | end 75 | end 76 | 77 | for i = 1, #data.points do 78 | local coords = data.points[i] 79 | 80 | lib.points.new({ 81 | coords = coords, 82 | distance = 16, 83 | benchid = id, 84 | index = i, 85 | inv = 'crafting', 86 | nearby = nearbyBench 87 | }) 88 | 89 | if blip then 90 | createBlip(blip, coords) 91 | end 92 | end 93 | end 94 | 95 | CraftingBenches[id] = data 96 | end 97 | end 98 | 99 | for id, data in pairs(lib.load('data.crafting')) do createCraftingBench(id, data) end 100 | 101 | return CraftingBenches 102 | -------------------------------------------------------------------------------- /modules/interface/client.lua: -------------------------------------------------------------------------------- 1 | if not lib then return end 2 | 3 | -- Module is deprecated and provided for compatibility 4 | -- All functions are now part of with ox_lib 5 | 6 | exports('Keyboard', lib.inputDialog) 7 | 8 | exports('Progress', function(options, completed) 9 | local success = lib.progressBar(options) 10 | 11 | if completed then 12 | completed(not success) 13 | end 14 | end) 15 | 16 | exports('CancelProgress', lib.cancelProgress) 17 | exports('ProgressActive', lib.progressActive) 18 | -------------------------------------------------------------------------------- /modules/items/containers.lua: -------------------------------------------------------------------------------- 1 | local containers = {} 2 | 3 | ---@class ItemContainerProperties 4 | ---@field slots number 5 | ---@field maxWeight number 6 | ---@field whitelist? table | string[] 7 | ---@field blacklist? table | string[] 8 | 9 | local function arrayToSet(tbl) 10 | local size = #tbl 11 | local set = table.create(0, size) 12 | 13 | for i = 1, size do 14 | set[tbl[i]] = true 15 | end 16 | 17 | return set 18 | end 19 | 20 | ---Registers items with itemName as containers (i.e. backpacks, wallets). 21 | ---@param itemName string 22 | ---@param properties ItemContainerProperties 23 | ---@todo Rework containers for flexibility, improved data structure; then export this method. 24 | local function setContainerProperties(itemName, properties) 25 | local blacklist, whitelist = properties.blacklist, properties.whitelist 26 | 27 | if blacklist then 28 | local tableType = table.type(blacklist) 29 | 30 | if tableType == 'array' then 31 | blacklist = arrayToSet(blacklist) 32 | elseif tableType ~= 'hash' then 33 | TypeError('blacklist', 'table', type(blacklist)) 34 | end 35 | end 36 | 37 | if whitelist then 38 | local tableType = table.type(whitelist) 39 | 40 | if tableType == 'array' then 41 | whitelist = arrayToSet(whitelist) 42 | elseif tableType ~= 'hash' then 43 | TypeError('whitelist', 'table', type(whitelist)) 44 | end 45 | end 46 | 47 | containers[itemName] = { 48 | size = { properties.slots, properties.maxWeight }, 49 | blacklist = blacklist, 50 | whitelist = whitelist, 51 | } 52 | end 53 | 54 | setContainerProperties('paperbag', { 55 | slots = 5, 56 | maxWeight = 1000, 57 | blacklist = { 'testburger' } 58 | }) 59 | 60 | setContainerProperties('pizzabox', { 61 | slots = 5, 62 | maxWeight = 1000, 63 | whitelist = { 'pizza' } 64 | }) 65 | 66 | return containers 67 | -------------------------------------------------------------------------------- /modules/items/shared.lua: -------------------------------------------------------------------------------- 1 | local function useExport(resource, export) 2 | return function(...) 3 | return exports[resource][export](nil, ...) 4 | end 5 | end 6 | 7 | local ItemList = {} 8 | local isServer = IsDuplicityVersion() 9 | 10 | ---@param data OxItem 11 | local function newItem(data) 12 | data.weight = data.weight or 0 13 | 14 | if data.close == nil then 15 | data.close = true 16 | end 17 | 18 | if data.stack == nil then 19 | data.stack = true 20 | end 21 | 22 | local clientData, serverData = data.client, data.server 23 | ---@cast clientData -nil 24 | ---@cast serverData -nil 25 | 26 | if not data.consume and (clientData and (clientData.status or clientData.usetime or clientData.export) or serverData?.export) then 27 | data.consume = 1 28 | end 29 | 30 | if isServer then 31 | ---@cast data OxServerItem 32 | serverData = data.server 33 | data.client = nil 34 | 35 | if not data.durability then 36 | if data.degrade or (data.consume and data.consume ~= 0 and data.consume < 1) then 37 | data.durability = true 38 | end 39 | end 40 | 41 | if not serverData then goto continue end 42 | 43 | if serverData.export then 44 | data.cb = useExport(string.strsplit('.', serverData.export)) 45 | end 46 | else 47 | ---@cast data OxClientItem 48 | clientData = data.client 49 | data.server = nil 50 | data.count = 0 51 | 52 | if not clientData then goto continue end 53 | 54 | if clientData.export then 55 | data.export = useExport(string.strsplit('.', clientData.export)) 56 | end 57 | 58 | if clientData.image then 59 | clientData.image = clientData.image:match('^[%w]+://') and clientData.image or ('%s/%s'):format(client.imagepath, clientData.image) 60 | end 61 | 62 | if clientData.propTwo then 63 | clientData.prop = clientData.prop and { clientData.prop, clientData.propTwo } or clientData.propTwo 64 | clientData.propTwo = nil 65 | end 66 | end 67 | 68 | ::continue:: 69 | ItemList[data.name] = data 70 | end 71 | 72 | for type, data in pairs(lib.load('data.weapons')) do 73 | for k, v in pairs(data) do 74 | v.name = k 75 | v.close = type == 'Ammo' and true or false 76 | v.weight = v.weight or 0 77 | 78 | if type == 'Weapons' then 79 | ---@cast v OxWeapon 80 | v.model = v.model or k -- actually weapon type or such? model for compatibility 81 | v.hash = joaat(v.model) 82 | v.stack = v.throwable and true or false 83 | v.durability = v.durability or 0.05 84 | v.weapon = true 85 | else 86 | v.stack = true 87 | end 88 | 89 | v[type == 'Ammo' and 'ammo' or type == 'Components' and 'component' or type == 'Tints' and 'tint' or 'weapon'] = true 90 | 91 | if isServer then v.client = nil else 92 | v.count = 0 93 | v.server = nil 94 | local clientData = v.client 95 | 96 | if clientData?.image then 97 | clientData.image = clientData.image:match('^[%w]+://') and ('url(%s)'):format(clientData.image) or ('url(%s/%s)'):format(client.imagepath, clientData.image) 98 | end 99 | end 100 | 101 | ItemList[k] = v 102 | end 103 | end 104 | 105 | for k, v in pairs(lib.load('data.items')) do 106 | v.name = k 107 | local success, response = pcall(newItem, v) 108 | 109 | if not success then 110 | warn(('An error occurred while creating item "%s" callback!\n^1SCRIPT ERROR: %s^0'):format(k, response)) 111 | end 112 | end 113 | 114 | ItemList.cash = ItemList.money 115 | 116 | return ItemList 117 | -------------------------------------------------------------------------------- /modules/pefcl/server.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Intended for use with https://github.com/project-error/pefcl 3 | config.useFrameworkIntegration.resource should be set as "ox_inventory" 4 | 5 | This isn't intended for use with frameworks with their own accounts, 6 | use the proper pefcl-framework resources and ensure item/account syncing 7 | works on your own. Note that qb uses "cash" but ox_inventory expects "money". 8 | 9 | This is mostly here for ox_core. 10 | ]] 11 | 12 | local Inventory = require 'modules.inventory.server' 13 | 14 | ---@param source number 15 | ---@param amount number 16 | exports('addCash', function(source, amount) 17 | Inventory.AddItem(source, 'money', amount) 18 | end) 19 | 20 | ---@param source number 21 | ---@param amount number 22 | exports('removeCash', function(source, amount) 23 | Inventory.RemoveItem(source, 'money', amount) 24 | end) 25 | 26 | ---@param source number 27 | ---@return number? 28 | exports('getCash', function(source) 29 | return Inventory.GetItem(source, 'money', false, true) or 0 --[[@as number]] 30 | end) 31 | 32 | ---@param source number 33 | ---@return table? 34 | exports('getCards', function(source) 35 | local items = Inventory(source)?.items 36 | 37 | if items then 38 | local retval, num = {}, 0 39 | 40 | for _, data in pairs(items) do 41 | if data.name == 'mastercard' then 42 | num += 1 43 | retval[num] = { 44 | id = data.metadata.id, 45 | holder = data.metadata.holder, 46 | number = data.metadata.number 47 | } 48 | end 49 | end 50 | 51 | return retval 52 | end 53 | end) 54 | 55 | ---@param source number 56 | ---@param card table 57 | exports('giveCard', function(source, card) 58 | Inventory.AddItem(source, 'mastercard', 1, { 59 | id = card.id, 60 | holder = card.holder, 61 | number = card.number, 62 | description = ('Card Number: %s'):format(card.number) 63 | }) 64 | end) 65 | 66 | ---no-op 67 | exports('getBank', function() end) 68 | 69 | -------------------------------------------------------------------------------- /modules/utils/server.lua: -------------------------------------------------------------------------------- 1 | if not lib then return end 2 | 3 | local Utils = {} 4 | 5 | local webHook = GetConvar('inventory:webhook', '') 6 | 7 | if webHook ~= '' then 8 | local validHosts = { 9 | ['i.imgur.com'] = true, 10 | } 11 | 12 | local validExtensions = { 13 | ['png'] = true, 14 | ['apng'] = true, 15 | ['webp'] = true, 16 | } 17 | 18 | local headers = { ['Content-Type'] = 'application/json' } 19 | 20 | function Utils.IsValidImageUrl(url) 21 | local host, extension = url:match('^https?://([^/]+).+%.([%l]+)') 22 | return host and extension and validHosts[host] and validExtensions[extension] 23 | end 24 | 25 | ---@param title string 26 | ---@param message string 27 | ---@param image string 28 | function Utils.DiscordEmbed(title, message, image, color) 29 | PerformHttpRequest(webHook, function() end, 'POST', json.encode({ 30 | username = 'ox_inventory', embeds = { 31 | { 32 | title = title, 33 | color = color, 34 | footer = { 35 | text = os.date('%c'), 36 | }, 37 | description = message, 38 | thumbnail = { 39 | url = image, 40 | width = 100, 41 | } 42 | } 43 | } 44 | }), headers) 45 | end 46 | end 47 | 48 | return Utils 49 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | .pnpm-debug.log 20 | -------------------------------------------------------------------------------- /web/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "useTabs": false, 5 | "tabWidth": 2, 6 | "semi": true, 7 | "bracketSpacing": true, 8 | "trailingComma": "es5" 9 | } 10 | -------------------------------------------------------------------------------- /web/LICENSE: -------------------------------------------------------------------------------- 1 | Ox Inventory 2 | Copyright © 2023 Overextended (https://github.com/overextended) 3 | Linden (https://github.com/thelindat) 4 | Luke (https://github.com/LukeWasTakenn) 5 | Dunak (https://github.com/dunak-debug) 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | -------------------------------------------------------------------------------- /web/build/assets/LLEG-5ff39a21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/LLEG-5ff39a21.png -------------------------------------------------------------------------------- /web/build/assets/RLEG-1dd40978.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/RLEG-1dd40978.png -------------------------------------------------------------------------------- /web/build/assets/head-52bdac31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/head-52bdac31.png -------------------------------------------------------------------------------- /web/build/assets/larm-9416bd78.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/larm-9416bd78.png -------------------------------------------------------------------------------- /web/build/assets/lfoot-6d7768f4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/lfoot-6d7768f4.png -------------------------------------------------------------------------------- /web/build/assets/lowerbody-4884bf92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/lowerbody-4884bf92.png -------------------------------------------------------------------------------- /web/build/assets/lpalm-cd95b6e0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/lpalm-cd95b6e0.png -------------------------------------------------------------------------------- /web/build/assets/neck-7fdfc0eb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/neck-7fdfc0eb.png -------------------------------------------------------------------------------- /web/build/assets/rarm-7c2e8852.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/rarm-7c2e8852.png -------------------------------------------------------------------------------- /web/build/assets/rfoot-df303828.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/rfoot-df303828.png -------------------------------------------------------------------------------- /web/build/assets/rpalm-fbec58a7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/rpalm-fbec58a7.png -------------------------------------------------------------------------------- /web/build/assets/upperbody-24b1890e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/build/assets/upperbody-24b1890e.png -------------------------------------------------------------------------------- /web/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | NUI React Boilerplate 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /web/images/CIGARETTE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/CIGARETTE.png -------------------------------------------------------------------------------- /web/images/LLEG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/LLEG.png -------------------------------------------------------------------------------- /web/images/RLEG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/RLEG.png -------------------------------------------------------------------------------- /web/images/WEAPON_ACIDPACKAGE.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_ACIDPACKAGE.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_ADVANCEDRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_ADVANCEDRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_APPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_APPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_ASSAULTRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_ASSAULTRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_ASSAULTRIFLE_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_ASSAULTRIFLE_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_ASSAULTSHOTGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_ASSAULTSHOTGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_ASSAULTSMG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_ASSAULTSMG.png -------------------------------------------------------------------------------- /web/images/WEAPON_AUTOSHOTGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_AUTOSHOTGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_BALL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BALL.png -------------------------------------------------------------------------------- /web/images/WEAPON_BAT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BAT.png -------------------------------------------------------------------------------- /web/images/WEAPON_BATTLEAXE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BATTLEAXE.png -------------------------------------------------------------------------------- /web/images/WEAPON_BOTTLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BOTTLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_BREAD.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BREAD.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_BRIEFCASE.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BRIEFCASE.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_BRIEFCASE_02.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BRIEFCASE_02.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_BULLPUPRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BULLPUPRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_BULLPUPRIFLE_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BULLPUPRIFLE_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_BULLPUPSHOTGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BULLPUPSHOTGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_BZGAS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_BZGAS.png -------------------------------------------------------------------------------- /web/images/WEAPON_CANDYCANE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_CANDYCANE.png -------------------------------------------------------------------------------- /web/images/WEAPON_CARBINERIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_CARBINERIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_CARBINERIFLE_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_CARBINERIFLE_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_CERAMICPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_CERAMICPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_COMBATMG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_COMBATMG.png -------------------------------------------------------------------------------- /web/images/WEAPON_COMBATMG_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_COMBATMG_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_COMBATPDW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_COMBATPDW.png -------------------------------------------------------------------------------- /web/images/WEAPON_COMBATPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_COMBATPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_COMBATSHOTGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_COMBATSHOTGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_COMPACTLAUNCHER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_COMPACTLAUNCHER.png -------------------------------------------------------------------------------- /web/images/WEAPON_COMPACTRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_COMPACTRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_CROWBAR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_CROWBAR.png -------------------------------------------------------------------------------- /web/images/WEAPON_DAGGER.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_DAGGER.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_DBSHOTGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_DBSHOTGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_DIGISCANNER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_DIGISCANNER.png -------------------------------------------------------------------------------- /web/images/WEAPON_DOUBLEACTION.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_DOUBLEACTION.png -------------------------------------------------------------------------------- /web/images/WEAPON_EMPLAUNCHER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_EMPLAUNCHER.png -------------------------------------------------------------------------------- /web/images/WEAPON_FERTILIZERCAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_FERTILIZERCAN.png -------------------------------------------------------------------------------- /web/images/WEAPON_FIREEXTINGUISHER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_FIREEXTINGUISHER.png -------------------------------------------------------------------------------- /web/images/WEAPON_FIREWORK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_FIREWORK.png -------------------------------------------------------------------------------- /web/images/WEAPON_FLARE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_FLARE.png -------------------------------------------------------------------------------- /web/images/WEAPON_FLAREGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_FLAREGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_FLASHLIGHT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_FLASHLIGHT.png -------------------------------------------------------------------------------- /web/images/WEAPON_GADGETPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_GADGETPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_GARBAGEBAG.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_GARBAGEBAG.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_GAS.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_GAS.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_GOLFCLUB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_GOLFCLUB.png -------------------------------------------------------------------------------- /web/images/WEAPON_GRENADE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_GRENADE.png -------------------------------------------------------------------------------- /web/images/WEAPON_GRENADELAUNCHER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_GRENADELAUNCHER.png -------------------------------------------------------------------------------- /web/images/WEAPON_GRENADELAUNCHER_SMOKE.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_GRENADELAUNCHER_SMOKE.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_GUSENBERG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_GUSENBERG.png -------------------------------------------------------------------------------- /web/images/WEAPON_HAMMER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HAMMER.png -------------------------------------------------------------------------------- /web/images/WEAPON_HANDCUFFS.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HANDCUFFS.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_HATCHET.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HATCHET.png -------------------------------------------------------------------------------- /web/images/WEAPON_HAZARDCAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HAZARDCAN.png -------------------------------------------------------------------------------- /web/images/WEAPON_HEAVYPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HEAVYPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_HEAVYRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HEAVYRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_HEAVYSHOTGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HEAVYSHOTGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_HEAVYSNIPER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HEAVYSNIPER.png -------------------------------------------------------------------------------- /web/images/WEAPON_HEAVYSNIPER_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HEAVYSNIPER_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_HOMINGLAUNCHER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_HOMINGLAUNCHER.png -------------------------------------------------------------------------------- /web/images/WEAPON_KNIFE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_KNIFE.png -------------------------------------------------------------------------------- /web/images/WEAPON_KNUCKLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_KNUCKLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_LICENSE.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_LICENSE.PNG -------------------------------------------------------------------------------- /web/images/WEAPON_MACHETE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MACHETE.png -------------------------------------------------------------------------------- /web/images/WEAPON_MACHINEPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MACHINEPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_MARKSMANPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MARKSMANPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_MARKSMANRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MARKSMANRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_MARKSMANRIFLE_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MARKSMANRIFLE_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_METALDETECTOR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_METALDETECTOR.png -------------------------------------------------------------------------------- /web/images/WEAPON_MG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MG.png -------------------------------------------------------------------------------- /web/images/WEAPON_MICROSMG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MICROSMG.png -------------------------------------------------------------------------------- /web/images/WEAPON_MILITARYRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MILITARYRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_MINIGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MINIGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_MINISMG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MINISMG.png -------------------------------------------------------------------------------- /web/images/WEAPON_MOLOTOV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MOLOTOV.png -------------------------------------------------------------------------------- /web/images/WEAPON_MUSKET.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_MUSKET.png -------------------------------------------------------------------------------- /web/images/WEAPON_NAVYREVOLVER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_NAVYREVOLVER.png -------------------------------------------------------------------------------- /web/images/WEAPON_NIGHTSTICK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_NIGHTSTICK.png -------------------------------------------------------------------------------- /web/images/WEAPON_PETROLCAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PETROLCAN.png -------------------------------------------------------------------------------- /web/images/WEAPON_PIPEBOMB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PIPEBOMB.png -------------------------------------------------------------------------------- /web/images/WEAPON_PISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_PISTOL50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PISTOL50.png -------------------------------------------------------------------------------- /web/images/WEAPON_PISTOLXM3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PISTOLXM3.png -------------------------------------------------------------------------------- /web/images/WEAPON_PISTOL_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PISTOL_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_POOLCUE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_POOLCUE.png -------------------------------------------------------------------------------- /web/images/WEAPON_PRECISIONRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PRECISIONRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_PROXMINE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PROXMINE.png -------------------------------------------------------------------------------- /web/images/WEAPON_PUMPSHOTGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PUMPSHOTGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_PUMPSHOTGUN_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_PUMPSHOTGUN_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_RAILGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_RAILGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_RAILGUNXM3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_RAILGUNXM3.png -------------------------------------------------------------------------------- /web/images/WEAPON_RAYCARBINE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_RAYCARBINE.png -------------------------------------------------------------------------------- /web/images/WEAPON_RAYMINIGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_RAYMINIGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_RAYPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_RAYPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_REVOLVER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_REVOLVER.png -------------------------------------------------------------------------------- /web/images/WEAPON_REVOLVER_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_REVOLVER_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_RPG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_RPG.png -------------------------------------------------------------------------------- /web/images/WEAPON_SAWNOFFSHOTGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SAWNOFFSHOTGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_SMG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SMG.png -------------------------------------------------------------------------------- /web/images/WEAPON_SMG_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SMG_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_SMOKEGRENADE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SMOKEGRENADE.png -------------------------------------------------------------------------------- /web/images/WEAPON_SNIPERRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SNIPERRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_SNOWBALL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SNOWBALL.png -------------------------------------------------------------------------------- /web/images/WEAPON_SNSPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SNSPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_SNSPISTOL_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SNSPISTOL_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_SPECIALCARBINE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SPECIALCARBINE.png -------------------------------------------------------------------------------- /web/images/WEAPON_SPECIALCARBINE_MK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SPECIALCARBINE_MK2.png -------------------------------------------------------------------------------- /web/images/WEAPON_STICKYBOMB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_STICKYBOMB.png -------------------------------------------------------------------------------- /web/images/WEAPON_STONE_HATCHET.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_STONE_HATCHET.png -------------------------------------------------------------------------------- /web/images/WEAPON_STUNGUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_STUNGUN.png -------------------------------------------------------------------------------- /web/images/WEAPON_SWITCHBLADE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_SWITCHBLADE.png -------------------------------------------------------------------------------- /web/images/WEAPON_TACTICALRIFLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_TACTICALRIFLE.png -------------------------------------------------------------------------------- /web/images/WEAPON_TECPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_TECPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_VINTAGEPISTOL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_VINTAGEPISTOL.png -------------------------------------------------------------------------------- /web/images/WEAPON_WRENCH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/WEAPON_WRENCH.png -------------------------------------------------------------------------------- /web/images/advancedkit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/advancedkit.png -------------------------------------------------------------------------------- /web/images/ammo-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-22.png -------------------------------------------------------------------------------- /web/images/ammo-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-38.png -------------------------------------------------------------------------------- /web/images/ammo-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-44.png -------------------------------------------------------------------------------- /web/images/ammo-45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-45.png -------------------------------------------------------------------------------- /web/images/ammo-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-50.png -------------------------------------------------------------------------------- /web/images/ammo-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-9.png -------------------------------------------------------------------------------- /web/images/ammo-beanbag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-beanbag.png -------------------------------------------------------------------------------- /web/images/ammo-emp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-emp.png -------------------------------------------------------------------------------- /web/images/ammo-firework.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-firework.PNG -------------------------------------------------------------------------------- /web/images/ammo-flare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-flare.png -------------------------------------------------------------------------------- /web/images/ammo-grenade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-grenade.png -------------------------------------------------------------------------------- /web/images/ammo-heavysniper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-heavysniper.png -------------------------------------------------------------------------------- /web/images/ammo-laser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-laser.png -------------------------------------------------------------------------------- /web/images/ammo-musket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-musket.png -------------------------------------------------------------------------------- /web/images/ammo-railgun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-railgun.png -------------------------------------------------------------------------------- /web/images/ammo-rifle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-rifle.png -------------------------------------------------------------------------------- /web/images/ammo-rifle2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-rifle2.png -------------------------------------------------------------------------------- /web/images/ammo-rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-rocket.png -------------------------------------------------------------------------------- /web/images/ammo-shotgun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-shotgun.png -------------------------------------------------------------------------------- /web/images/ammo-sniper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ammo-sniper.png -------------------------------------------------------------------------------- /web/images/armour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/armour.png -------------------------------------------------------------------------------- /web/images/at_barrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_barrel.png -------------------------------------------------------------------------------- /web/images/at_clip_drum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_clip_drum.png -------------------------------------------------------------------------------- /web/images/at_clip_extended.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_clip_extended.png -------------------------------------------------------------------------------- /web/images/at_clip_extended2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_clip_extended2.png -------------------------------------------------------------------------------- /web/images/at_flashlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_flashlight.png -------------------------------------------------------------------------------- /web/images/at_flashlight_rifle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_flashlight_rifle.png -------------------------------------------------------------------------------- /web/images/at_grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_grip.png -------------------------------------------------------------------------------- /web/images/at_muzzle_bell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_muzzle_bell.png -------------------------------------------------------------------------------- /web/images/at_muzzle_fat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_muzzle_fat.png -------------------------------------------------------------------------------- /web/images/at_muzzle_flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_muzzle_flat.png -------------------------------------------------------------------------------- /web/images/at_muzzle_heavy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_muzzle_heavy.png -------------------------------------------------------------------------------- /web/images/at_muzzle_precision'.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_muzzle_precision'.png -------------------------------------------------------------------------------- /web/images/at_muzzle_slanted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_muzzle_slanted.png -------------------------------------------------------------------------------- /web/images/at_muzzle_split.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_muzzle_split.png -------------------------------------------------------------------------------- /web/images/at_muzzle_squared.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_muzzle_squared.png -------------------------------------------------------------------------------- /web/images/at_muzzle_tactical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_muzzle_tactical.png -------------------------------------------------------------------------------- /web/images/at_scope_advanced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_scope_advanced.png -------------------------------------------------------------------------------- /web/images/at_scope_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_scope_holo.png -------------------------------------------------------------------------------- /web/images/at_scope_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_scope_large.png -------------------------------------------------------------------------------- /web/images/at_scope_medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_scope_medium.png -------------------------------------------------------------------------------- /web/images/at_scope_nv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_scope_nv.png -------------------------------------------------------------------------------- /web/images/at_scope_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_scope_small.png -------------------------------------------------------------------------------- /web/images/at_scope_thermal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_scope_thermal.png -------------------------------------------------------------------------------- /web/images/at_suppressor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/at_suppressor.png -------------------------------------------------------------------------------- /web/images/bandage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/bandage.png -------------------------------------------------------------------------------- /web/images/beer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/beer.png -------------------------------------------------------------------------------- /web/images/black_money.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/black_money.png -------------------------------------------------------------------------------- /web/images/bsfries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/bsfries.png -------------------------------------------------------------------------------- /web/images/burger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/burger.png -------------------------------------------------------------------------------- /web/images/burger_chicken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/burger_chicken.png -------------------------------------------------------------------------------- /web/images/candy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/candy.png -------------------------------------------------------------------------------- /web/images/card_bank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/card_bank.png -------------------------------------------------------------------------------- /web/images/card_id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/card_id.png -------------------------------------------------------------------------------- /web/images/carkey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/carkey.png -------------------------------------------------------------------------------- /web/images/carokit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/carokit.png -------------------------------------------------------------------------------- /web/images/chipscheese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/chipscheese.png -------------------------------------------------------------------------------- /web/images/chipshabanero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/chipshabanero.png -------------------------------------------------------------------------------- /web/images/chipsribs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/chipsribs.png -------------------------------------------------------------------------------- /web/images/chipssalt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/chipssalt.png -------------------------------------------------------------------------------- /web/images/cigarettes_redwood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/cigarettes_redwood.png -------------------------------------------------------------------------------- /web/images/cocaine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/cocaine.png -------------------------------------------------------------------------------- /web/images/cola.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/cola.png -------------------------------------------------------------------------------- /web/images/copper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/copper.png -------------------------------------------------------------------------------- /web/images/diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/diamond.png -------------------------------------------------------------------------------- /web/images/donut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/donut.png -------------------------------------------------------------------------------- /web/images/drug_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/drug_blue.png -------------------------------------------------------------------------------- /web/images/drug_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/drug_red.png -------------------------------------------------------------------------------- /web/images/drug_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/drug_white.png -------------------------------------------------------------------------------- /web/images/evidence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/evidence.png -------------------------------------------------------------------------------- /web/images/fertilizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/fertilizer.png -------------------------------------------------------------------------------- /web/images/fixkit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/fixkit.png -------------------------------------------------------------------------------- /web/images/fries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/fries.png -------------------------------------------------------------------------------- /web/images/garbage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/garbage.png -------------------------------------------------------------------------------- /web/images/gold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/gold.png -------------------------------------------------------------------------------- /web/images/head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/head.png -------------------------------------------------------------------------------- /web/images/hotdog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/hotdog.png -------------------------------------------------------------------------------- /web/images/iron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/iron.png -------------------------------------------------------------------------------- /web/images/joint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/joint.png -------------------------------------------------------------------------------- /web/images/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/key.png -------------------------------------------------------------------------------- /web/images/keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/keys.png -------------------------------------------------------------------------------- /web/images/larm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/larm.png -------------------------------------------------------------------------------- /web/images/lfoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/lfoot.png -------------------------------------------------------------------------------- /web/images/lockpick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/lockpick.png -------------------------------------------------------------------------------- /web/images/lowerbody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/lowerbody.png -------------------------------------------------------------------------------- /web/images/lpalm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/lpalm.png -------------------------------------------------------------------------------- /web/images/medikit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/medikit.png -------------------------------------------------------------------------------- /web/images/meth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/meth.png -------------------------------------------------------------------------------- /web/images/money.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/money.png -------------------------------------------------------------------------------- /web/images/mustard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/mustard.png -------------------------------------------------------------------------------- /web/images/neck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/neck.png -------------------------------------------------------------------------------- /web/images/necklace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/necklace.png -------------------------------------------------------------------------------- /web/images/oldkey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/oldkey.png -------------------------------------------------------------------------------- /web/images/panties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/panties.png -------------------------------------------------------------------------------- /web/images/paperbag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/paperbag.png -------------------------------------------------------------------------------- /web/images/parachute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/parachute.png -------------------------------------------------------------------------------- /web/images/pepperoni.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/pepperoni.png -------------------------------------------------------------------------------- /web/images/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/phone.png -------------------------------------------------------------------------------- /web/images/pizza_ham.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/pizza_ham.png -------------------------------------------------------------------------------- /web/images/pizza_ham_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/pizza_ham_box.png -------------------------------------------------------------------------------- /web/images/pizza_ham_slice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/pizza_ham_slice.png -------------------------------------------------------------------------------- /web/images/radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/radio.png -------------------------------------------------------------------------------- /web/images/ramen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ramen.png -------------------------------------------------------------------------------- /web/images/rarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/rarm.png -------------------------------------------------------------------------------- /web/images/readme.md: -------------------------------------------------------------------------------- 1 | ## The following images were provided by [yaroph](https://forum.cfx.re/u/yaroph/) for free-use by ox_inventory. 2 | - All files prefixed with _ammo-_, _at\__, and _WEAPON\__. 3 | - advancedkit 4 | - armour 5 | - bandage 6 | - black_money 7 | - burger 8 | - burger_chicken 9 | - card_id 10 | - carkey 11 | - cigarette 12 | - cigarettes_redwood 13 | - cocaine 14 | - donut 15 | - fries 16 | - garbage 17 | - key 18 | - lockpick 19 | - medikit 20 | - meth 21 | - money 22 | - mustard 23 | - oldkey 24 | - panties 25 | - paperbag 26 | - parachute 27 | - phone 28 | - pizza_ham 29 | - pizza_ham_box 30 | - pizza_ham_slice 31 | - radio 32 | - scrapmetal 33 | - sprunk 34 | - trash 35 | - trash_bread 36 | - trash_burger 37 | - trash_can 38 | - trash_chips 39 | - usb_black 40 | - water 41 | - weed 42 | - ziptie 43 | 44 | For more images, see [this thread](https://forum.cfx.re/t/inventory-icons-pack-for-rp-server-hq-draw-24k-cloth-l-1400-objects/5203350) and get a **10%** discount when using creator code `ox10`. 45 | -------------------------------------------------------------------------------- /web/images/rfoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/rfoot.png -------------------------------------------------------------------------------- /web/images/rolex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/rolex.png -------------------------------------------------------------------------------- /web/images/rpalm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/rpalm.png -------------------------------------------------------------------------------- /web/images/scrapmetal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/scrapmetal.png -------------------------------------------------------------------------------- /web/images/silver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/silver.png -------------------------------------------------------------------------------- /web/images/small_armour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/small_armour.png -------------------------------------------------------------------------------- /web/images/sprunk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/sprunk.png -------------------------------------------------------------------------------- /web/images/taco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/taco.png -------------------------------------------------------------------------------- /web/images/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash.png -------------------------------------------------------------------------------- /web/images/trash_bread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash_bread.png -------------------------------------------------------------------------------- /web/images/trash_burger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash_burger.png -------------------------------------------------------------------------------- /web/images/trash_burgershot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash_burgershot.png -------------------------------------------------------------------------------- /web/images/trash_can.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash_can.png -------------------------------------------------------------------------------- /web/images/trash_chips.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash_chips.png -------------------------------------------------------------------------------- /web/images/trash_coffee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash_coffee.png -------------------------------------------------------------------------------- /web/images/trash_fags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash_fags.png -------------------------------------------------------------------------------- /web/images/trash_newspaper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash_newspaper.png -------------------------------------------------------------------------------- /web/images/trash_paper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/trash_paper.png -------------------------------------------------------------------------------- /web/images/turkey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/turkey.png -------------------------------------------------------------------------------- /web/images/upperbody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/upperbody.png -------------------------------------------------------------------------------- /web/images/usb_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/usb_black.png -------------------------------------------------------------------------------- /web/images/water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/water.png -------------------------------------------------------------------------------- /web/images/weed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/weed.png -------------------------------------------------------------------------------- /web/images/ziptie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/images/ziptie.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | NUI React Boilerplate 15 | 16 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ox_inventory", 3 | "version": "1.0.0", 4 | "homepage": "web/build", 5 | "private": true, 6 | "dependencies": { 7 | "@floating-ui/react": "^0.25.4", 8 | "@types/lodash": "^4.14.191", 9 | "@types/node": "^18.11.12", 10 | "@types/react": "^18.0.26", 11 | "@types/react-dom": "^18.0.9", 12 | "@types/react-transition-group": "^4.4.5", 13 | "@vitejs/plugin-react": "^3.0.0", 14 | "lodash": "^4.17.21", 15 | "react": "^18.2.0", 16 | "react-circular-progressbar": "^2.1.0", 17 | "react-dnd": "^16.0.1", 18 | "react-dnd-touch-backend": "^16.0.1", 19 | "react-dom": "^18.2.0", 20 | "react-markdown": "^8.0.4", 21 | "react-redux": "^8.0.5", 22 | "react-tooltip": "^5.25.2", 23 | "react-transition-group": "^4.4.5", 24 | "redux": "^4.2.0", 25 | "sass": "^1.56.2" 26 | }, 27 | "scripts": { 28 | "dev": "vite", 29 | "game": "vite build --watch", 30 | "build": "tsc && vite build", 31 | "preview": "vite preview", 32 | "format": "prettier --write \"./src/**/*.{ts,tsx,css}\"" 33 | }, 34 | "eslintConfig": { 35 | "extends": [ 36 | "react-app" 37 | ] 38 | }, 39 | "browserslist": { 40 | "production": [ 41 | ">0.2%", 42 | "not dead", 43 | "not op_mini all" 44 | ], 45 | "development": [ 46 | "last 1 chrome version", 47 | "last 1 firefox version", 48 | "last 1 safari version" 49 | ] 50 | }, 51 | "devDependencies": { 52 | "@babel/core": "^7.20.5", 53 | "@redux-devtools/core": "^3.13.1", 54 | "@redux-devtools/instrument": "^2.1.0", 55 | "@reduxjs/toolkit": "^1.9.1", 56 | "@types/react-redux": "^7.1.24", 57 | "cross-env": "^7.0.3", 58 | "csstype": "^2.6.21", 59 | "prettier": "^2.8.1", 60 | "typescript": "^4.9.4", 61 | "vite": "^4.0.0" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /web/src/SVG/Earings.tsx: -------------------------------------------------------------------------------- 1 | export default function Earings({styles, onClick}:{styles?:React.CSSProperties, onClick?:()=>void}) { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ) 19 | } -------------------------------------------------------------------------------- /web/src/SVG/Glasses.tsx: -------------------------------------------------------------------------------- 1 | export default function Glasses({styles, onClick}:{styles?:React.CSSProperties, onClick?:()=>void}) { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ) 11 | } -------------------------------------------------------------------------------- /web/src/SVG/Hand.tsx: -------------------------------------------------------------------------------- 1 | export default function Hand({styles, onClick}:{styles?:React.CSSProperties, onClick?:()=>void}) { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ) 17 | } -------------------------------------------------------------------------------- /web/src/SVG/Shirt.tsx: -------------------------------------------------------------------------------- 1 | export default function Shirt({styles, onClick}:{styles?:React.CSSProperties, onClick?:()=>void}) { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ) 16 | } -------------------------------------------------------------------------------- /web/src/SVG/Shoes.tsx: -------------------------------------------------------------------------------- 1 | export default function Shoes({styles, onClick}:{styles?:React.CSSProperties, onClick?:()=>void}) { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ) 26 | } -------------------------------------------------------------------------------- /web/src/SVG/Tie.tsx: -------------------------------------------------------------------------------- 1 | export default function Tie({styles, onClick}:{styles?:React.CSSProperties, onClick?:()=>void}) { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ) 19 | } -------------------------------------------------------------------------------- /web/src/SVG/Vest.tsx: -------------------------------------------------------------------------------- 1 | export default function Vest({styles, onClick}:{styles?:React.CSSProperties, onClick?:()=>void}) { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ) 16 | } -------------------------------------------------------------------------------- /web/src/SVG/durablity.tsx: -------------------------------------------------------------------------------- 1 | export default function DamagePercent({percent, styles, label}: {percent: number, styles?: React.CSSProperties, label?: string}) { 2 | return ( 3 |
4 |
5 | {label} 6 |
7 |
8 |
17 |
18 |
19 |
20 | ) 21 | } -------------------------------------------------------------------------------- /web/src/SVG/head.tsx: -------------------------------------------------------------------------------- 1 | export default function Head({styles, onClick}:{styles?:React.CSSProperties, onClick?:()=>void}) { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ) 21 | } -------------------------------------------------------------------------------- /web/src/components/inventory/BodyDamge.tsx: -------------------------------------------------------------------------------- 1 | import Body from "../../utils/Body"; 2 | import { useAppSelector } from "../../store"; 3 | import { useState, useEffect } from "react"; 4 | 5 | export default function BodyDamage() { 6 | const damagevar = useAppSelector((state) => state.damage.data) 7 | return ( 8 |
12 | 15 |
16 | ) 17 | } -------------------------------------------------------------------------------- /web/src/components/inventory/InventoryControl.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { useDrop } from 'react-dnd'; 3 | import { useAppDispatch, useAppSelector } from '../../store'; 4 | import { selectItemAmount, setItemAmount } from '../../store/inventory'; 5 | import { DragSource } from '../../typings'; 6 | import { onUse } from '../../dnd/onUse'; 7 | import { onGive } from '../../dnd/onGive'; 8 | import { fetchNui } from '../../utils/fetchNui'; 9 | import { Locale } from '../../store/locale'; 10 | import UsefulControls from './UsefulControls'; 11 | 12 | const InventoryControl: React.FC = () => { 13 | const itemAmount = useAppSelector(selectItemAmount); 14 | const dispatch = useAppDispatch(); 15 | 16 | const [infoVisible, setInfoVisible] = useState(false); 17 | 18 | const [, use] = useDrop(() => ({ 19 | accept: 'SLOT', 20 | drop: (source) => { 21 | source.inventory === 'player' && onUse(source.item); 22 | }, 23 | })); 24 | 25 | const [, give] = useDrop(() => ({ 26 | accept: 'SLOT', 27 | drop: (source) => { 28 | source.inventory === 'player' && onGive(source.item); 29 | }, 30 | })); 31 | 32 | const inputHandler = (event: React.ChangeEvent) => { 33 | event.target.valueAsNumber = 34 | isNaN(event.target.valueAsNumber) || event.target.valueAsNumber < 0 ? 0 : Math.floor(event.target.valueAsNumber); 35 | dispatch(setItemAmount(event.target.valueAsNumber)); 36 | }; 37 | 38 | return ( 39 | <> 40 | 41 |
42 |
43 | 50 |
51 |
52 | 53 | ); 54 | }; 55 | 56 | export default InventoryControl; 57 | -------------------------------------------------------------------------------- /web/src/components/inventory/InventoryHotbar.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { getItemUrl, isSlotWithItem } from '../../helpers'; 3 | import useNuiEvent from '../../hooks/useNuiEvent'; 4 | import { Items } from '../../store/items'; 5 | import WeightBar from '../utils/WeightBar'; 6 | import { useAppSelector } from '../../store'; 7 | import { selectLeftInventory } from '../../store/inventory'; 8 | import { SlotWithItem } from '../../typings'; 9 | import SlideUp from '../utils/transitions/SlideUp'; 10 | 11 | const InventoryHotbar: React.FC = () => { 12 | const [hotbarVisible, setHotbarVisible] = useState(false); 13 | const items = useAppSelector(selectLeftInventory).items.slice(0, 5); 14 | 15 | //stupid fix for timeout 16 | const [handle, setHandle] = useState(); 17 | useNuiEvent('toggleHotbar', () => { 18 | if (hotbarVisible) { 19 | setHotbarVisible(false); 20 | } else { 21 | if (handle) clearTimeout(handle); 22 | setHotbarVisible(true); 23 | setHandle(setTimeout(() => setHotbarVisible(false), 3000)); 24 | } 25 | }); 26 | 27 | return ( 28 | // 29 | 30 |
31 | {items.map((item) => ( 32 |
39 | {isSlotWithItem(item) && ( 40 |
43 |
44 |
{item.slot}
45 |
46 | {item?.durability !== undefined && } 47 |
48 |
49 |
50 | 51 |
52 |
53 | {item.metadata?.label ? item.metadata.label : Items[item.name]?.label || item.name} 54 |
{typeof item.count === 'undefined' ? '0x' : item.count + 'x'}
55 |
56 |
57 |
58 |
59 | )} 60 |
61 | ))} 62 |
63 |
64 | ); 65 | }; 66 | 67 | export default InventoryHotbar; 68 | -------------------------------------------------------------------------------- /web/src/components/inventory/LeftInventory.tsx: -------------------------------------------------------------------------------- 1 | import InventoryGrid from './InventoryGrid'; 2 | import { useAppSelector } from '../../store'; 3 | import { selectLeftInventory } from '../../store/inventory'; 4 | 5 | const LeftInventory: React.FC = () => { 6 | const leftInventory = useAppSelector(selectLeftInventory); 7 | 8 | return ; 9 | }; 10 | 11 | export default LeftInventory; 12 | -------------------------------------------------------------------------------- /web/src/components/inventory/RightInventory.tsx: -------------------------------------------------------------------------------- 1 | import InventoryGrid from './InventoryGrid'; 2 | import { useAppSelector } from '../../store'; 3 | import { selectRightInventory } from '../../store/inventory'; 4 | 5 | const RightInventory: React.FC = () => { 6 | const rightInventory = useAppSelector(selectRightInventory); 7 | 8 | return ; 9 | }; 10 | 11 | export default RightInventory; 12 | -------------------------------------------------------------------------------- /web/src/components/inventory/UsefulControls.tsx: -------------------------------------------------------------------------------- 1 | import { Locale } from '../../store/locale'; 2 | import React from 'react'; 3 | import { 4 | FloatingFocusManager, 5 | FloatingOverlay, 6 | FloatingPortal, 7 | useDismiss, 8 | useFloating, 9 | useInteractions, 10 | useTransitionStyles, 11 | } from '@floating-ui/react'; 12 | 13 | interface Props { 14 | infoVisible: boolean; 15 | setInfoVisible: React.Dispatch>; 16 | } 17 | 18 | const UsefulControls: React.FC = ({ infoVisible, setInfoVisible }) => { 19 | const { refs, context } = useFloating({ 20 | open: infoVisible, 21 | onOpenChange: setInfoVisible, 22 | }); 23 | 24 | const dismiss = useDismiss(context, { 25 | outsidePressEvent: 'mousedown', 26 | }); 27 | 28 | const { isMounted, styles } = useTransitionStyles(context); 29 | 30 | const { getFloatingProps } = useInteractions([dismiss]); 31 | 32 | return ( 33 | <> 34 | {isMounted && ( 35 | 36 | 37 | 38 |
39 |
40 |

{Locale.ui_usefulcontrols || 'Useful controls'}

41 |
setInfoVisible(false)}> 42 | 43 | 44 | 45 |
46 |
47 |
48 |

49 | RMB 50 |
51 | {Locale.ui_rmb} 52 |

53 |

54 | ALT + LMB 55 |
56 | {Locale.ui_alt_lmb} 57 |

58 |

59 | CTRL + LMB 60 |
61 | {Locale.ui_ctrl_lmb} 62 |

63 |

64 | SHIFT + Drag 65 |
66 | {Locale.ui_shift_drag} 67 |

68 |

69 | CTRL + SHIFT + LMB 70 |
71 | {Locale.ui_ctrl_shift_lmb} 72 |

73 |
🐂
74 |
75 |
76 |
77 |
78 |
79 | )} 80 | 81 | ); 82 | }; 83 | 84 | export default UsefulControls; 85 | -------------------------------------------------------------------------------- /web/src/components/inventory/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import useNuiEvent from '../../hooks/useNuiEvent'; 3 | import InventoryControl from './InventoryControl'; 4 | import InventoryHotbar from './InventoryHotbar'; 5 | import { useAppDispatch } from '../../store'; 6 | import { refreshSlots, setAdditionalMetadata, setupInventory } from '../../store/inventory'; 7 | import { useExitListener } from '../../hooks/useExitListener'; 8 | import type { Inventory as InventoryProps } from '../../typings'; 9 | import RightInventory from './RightInventory'; 10 | import LeftInventory from './LeftInventory'; 11 | import Tooltip from '../utils/Tooltip'; 12 | import { closeTooltip } from '../../store/tooltip'; 13 | import InventoryContext from './InventoryContext'; 14 | import { closeContextMenu } from '../../store/contextMenu'; 15 | import Fade from '../utils/transitions/Fade'; 16 | import BodyDamege from './BodyDamge'; 17 | 18 | const Inventory: React.FC = () => { 19 | const [inventoryVisible, setInventoryVisible] = React.useState(false); 20 | const dispatch = useAppDispatch(); 21 | 22 | useNuiEvent('setInventoryVisible', setInventoryVisible); 23 | useNuiEvent('closeInventory', () => { 24 | setInventoryVisible(false); 25 | dispatch(closeContextMenu()); 26 | dispatch(closeTooltip()); 27 | }); 28 | useExitListener(setInventoryVisible); 29 | 30 | useNuiEvent<{ 31 | leftInventory?: InventoryProps; 32 | rightInventory?: InventoryProps; 33 | }>('setupInventory', (data) => { 34 | dispatch(setupInventory(data)); 35 | !inventoryVisible && setInventoryVisible(true); 36 | }); 37 | 38 | useNuiEvent('refreshSlots', (data) => dispatch(refreshSlots(data))); 39 | 40 | useNuiEvent('displayMetadata', (data: Array<{ metadata: string; value: string }>) => { 41 | dispatch(setAdditionalMetadata(data)); 42 | }); 43 | 44 | return ( 45 | <> 46 | 47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 |
56 | 57 | 58 | 59 | ); 60 | }; 61 | 62 | export default Inventory; 63 | -------------------------------------------------------------------------------- /web/src/components/utils/Divider.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Divider: React.FC = () => { 4 | return
; 5 | }; 6 | 7 | export default Divider; 8 | -------------------------------------------------------------------------------- /web/src/components/utils/DragPreview.tsx: -------------------------------------------------------------------------------- 1 | import React, { RefObject, useRef } from 'react'; 2 | import { DragLayerMonitor, useDragLayer, XYCoord } from 'react-dnd'; 3 | import { DragSource } from '../../typings'; 4 | 5 | interface DragLayerProps { 6 | data: DragSource; 7 | currentOffset: XYCoord | null; 8 | isDragging: boolean; 9 | } 10 | 11 | const subtract = (a: XYCoord, b: XYCoord): XYCoord => { 12 | return { 13 | x: a.x - b.x, 14 | y: a.y - b.y, 15 | }; 16 | }; 17 | 18 | const calculateParentOffset = (monitor: DragLayerMonitor): XYCoord => { 19 | const client = monitor.getInitialClientOffset(); 20 | const source = monitor.getInitialSourceClientOffset(); 21 | if (client === null || source === null || client.x === undefined || client.y === undefined) { 22 | return { x: 0, y: 0 }; 23 | } 24 | return subtract(client, source); 25 | }; 26 | 27 | export const calculatePointerPosition = (monitor: DragLayerMonitor, childRef: RefObject): XYCoord | null => { 28 | const offset = monitor.getClientOffset(); 29 | if (offset === null) { 30 | return null; 31 | } 32 | 33 | if (!childRef.current || !childRef.current.getBoundingClientRect) { 34 | return subtract(offset, calculateParentOffset(monitor)); 35 | } 36 | 37 | const bb = childRef.current.getBoundingClientRect(); 38 | const middle = { x: bb.width / 2, y: bb.height / 2 }; 39 | return subtract(offset, middle); 40 | }; 41 | 42 | const DragPreview: React.FC = () => { 43 | const element = useRef(null); 44 | 45 | const { data, isDragging, currentOffset } = useDragLayer((monitor) => ({ 46 | data: monitor.getItem(), 47 | currentOffset: calculatePointerPosition(monitor, element), 48 | isDragging: monitor.isDragging(), 49 | })); 50 | 51 | return ( 52 | <> 53 | {isDragging && currentOffset && data.item && ( 54 |
62 | )} 63 | 64 | ); 65 | }; 66 | 67 | export default DragPreview; 68 | -------------------------------------------------------------------------------- /web/src/components/utils/ItemNotifications.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createPortal } from 'react-dom'; 3 | import { TransitionGroup } from 'react-transition-group'; 4 | import useNuiEvent from '../../hooks/useNuiEvent'; 5 | import useQueue from '../../hooks/useQueue'; 6 | import { Locale } from '../../store/locale'; 7 | import { getItemUrl } from '../../helpers'; 8 | import { SlotWithItem } from '../../typings'; 9 | import { Items } from '../../store/items'; 10 | import Fade from './transitions/Fade'; 11 | 12 | interface ItemNotificationProps { 13 | item: SlotWithItem; 14 | text: string; 15 | } 16 | 17 | export const ItemNotificationsContext = React.createContext<{ 18 | add: (item: ItemNotificationProps) => void; 19 | } | null>(null); 20 | 21 | export const useItemNotifications = () => { 22 | const itemNotificationsContext = React.useContext(ItemNotificationsContext); 23 | if (!itemNotificationsContext) throw new Error(`ItemNotificationsContext undefined`); 24 | return itemNotificationsContext; 25 | }; 26 | 27 | const ItemNotification = React.forwardRef( 28 | (props: { item: ItemNotificationProps; style?: React.CSSProperties }, ref: React.ForwardedRef) => { 29 | const slotItem = props.item.item; 30 | 31 | return ( 32 |
40 |
41 |
42 |

{props.item.text}

43 |
44 |
45 |
{slotItem.metadata?.label || Items[slotItem.name]?.label}
46 |
47 |
48 |
49 | ); 50 | } 51 | ); 52 | 53 | export const ItemNotificationsProvider = ({ children }: { children: React.ReactNode }) => { 54 | const queue = useQueue<{ 55 | id: number; 56 | item: ItemNotificationProps; 57 | ref: React.RefObject; 58 | }>(); 59 | 60 | const add = (item: ItemNotificationProps) => { 61 | const ref = React.createRef(); 62 | const notification = { id: Date.now(), item, ref: ref }; 63 | 64 | queue.add(notification); 65 | 66 | const timeout = setTimeout(() => { 67 | queue.remove(); 68 | clearTimeout(timeout); 69 | }, 2500); 70 | }; 71 | 72 | useNuiEvent<[item: SlotWithItem, text: string, count?: number]>('itemNotify', ([item, text, count]) => { 73 | add({ item: item, text: count ? `${Locale[text]} ${count}x` : `${Locale[text]}` }); 74 | }); 75 | 76 | return ( 77 | 78 | {children} 79 | {createPortal( 80 | 81 | {queue.values.map((notification, index) => ( 82 | 83 | 84 | 85 | ))} 86 | , 87 | document.body 88 | )} 89 | 90 | ); 91 | }; 92 | -------------------------------------------------------------------------------- /web/src/components/utils/KeyPress.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { setShiftPressed } from '../../store/inventory'; 3 | import useKeyPress from '../../hooks/useKeyPress'; 4 | import { useAppDispatch } from '../../store'; 5 | 6 | const KeyPress: React.FC = () => { 7 | const dispatch = useAppDispatch(); 8 | const shiftPressed = useKeyPress('Shift'); 9 | 10 | useEffect(() => { 11 | dispatch(setShiftPressed(shiftPressed)); 12 | }, [shiftPressed, dispatch]); 13 | 14 | return <>; 15 | }; 16 | 17 | export default KeyPress; 18 | -------------------------------------------------------------------------------- /web/src/components/utils/Tooltip.tsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react'; 2 | import { flip, FloatingPortal, offset, shift, useFloating, useTransitionStyles } from '@floating-ui/react'; 3 | import { useAppSelector } from '../../store'; 4 | import SlotTooltip from '../inventory/SlotTooltip'; 5 | import { useDebounce } from '../../hooks/useDebounce'; 6 | 7 | const Tooltip: React.FC = () => { 8 | const hoverData = useAppSelector((state) => state.tooltip); 9 | const debounce = useDebounce(hoverData.open, 500); 10 | const [open, setOpen] = React.useState(false); 11 | const openTimer = useRef(null); 12 | const canOpen = useRef(false); 13 | 14 | const { refs, context, floatingStyles } = useFloating({ 15 | middleware: [flip(), shift(), offset({ mainAxis: 10, crossAxis: 10 })], 16 | open: hoverData.open, 17 | placement: 'right-start', 18 | }); 19 | 20 | const { isMounted, styles } = useTransitionStyles(context, { 21 | duration: 200, 22 | }); 23 | 24 | const handleMouseMove = ({ clientX, clientY }: MouseEvent | React.MouseEvent) => { 25 | refs.setPositionReference({ 26 | getBoundingClientRect() { 27 | return { 28 | width: 0, 29 | height: 0, 30 | x: clientX, 31 | y: clientY, 32 | left: clientX, 33 | top: clientY, 34 | right: clientX, 35 | bottom: clientY, 36 | }; 37 | }, 38 | }); 39 | }; 40 | 41 | React.useEffect(() => { 42 | window.addEventListener('mousemove', handleMouseMove); 43 | 44 | return () => { 45 | window.removeEventListener('mousemove', handleMouseMove); 46 | }; 47 | }, []); 48 | 49 | return ( 50 | <> 51 | {isMounted && hoverData.item && hoverData.inventoryType && ( 52 | 53 | 59 | 60 | )} 61 | 62 | ); 63 | }; 64 | 65 | export default Tooltip; 66 | -------------------------------------------------------------------------------- /web/src/components/utils/WeightBar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { CircularProgressbarWithChildren, buildStyles } from 'react-circular-progressbar'; 3 | import 'react-circular-progressbar/dist/styles.css'; 4 | 5 | const colorChannelMixer = (colorChannelA: number, colorChannelB: number, amountToMix: number) => { 6 | let channelA = colorChannelA * amountToMix; 7 | let channelB = colorChannelB * (1 - amountToMix); 8 | return channelA + channelB; 9 | }; 10 | 11 | const colorMixer = (rgbA: number[], rgbB: number[], amountToMix: number) => { 12 | let r = colorChannelMixer(rgbA[0], rgbB[0], amountToMix); 13 | let g = colorChannelMixer(rgbA[1], rgbB[1], amountToMix); 14 | let b = colorChannelMixer(rgbA[2], rgbB[2], amountToMix); 15 | return `rgb(${r}, ${g}, ${b})`; 16 | }; 17 | 18 | const COLORS = { 19 | // Colors used - https://materialui.co/flatuicolors 20 | primaryColor: [255, 255, 255], // Red (Pomegranate) 21 | secondColor: [255, 255, 255], // Green (Nephritis) 22 | accentColor: [255, 0, 0], // Orange (Oragne) 23 | }; 24 | const COLORSS = { 25 | // Colors used - https://materialui.co/flatuicolors 26 | primaryColor: [38, 255, 0], // Red (Pomegranate) 27 | secondColor: [247, 227, 0], // Green (Nephritis) 28 | accentColor: [255, 0, 0], // Orange (Oragne) 29 | }; 30 | const WeightBar: React.FC<{ percent: number; durability?: boolean, strokesize: number }> = ({ percent, durability, strokesize }) => { 31 | const color = React.useMemo( 32 | () => 33 | percent >= 50 34 | ? colorMixer(COLORS.accentColor, COLORS.secondColor, percent / 100) 35 | : colorMixer(COLORS.accentColor, COLORS.secondColor, percent / 100), 36 | [durability, percent] 37 | ); 38 | const colorr = React.useMemo( 39 | () => 40 | percent < 50 41 | ? colorMixer(COLORSS.secondColor, COLORSS.accentColor, percent / 100) 42 | : colorMixer(COLORSS.primaryColor, COLORSS.accentColor, percent / 100), 43 | [durability, percent] 44 | ); 45 | return ( 46 | 60 | 70 ? durability ? '' : 'fa-light fa-scale-balanced fa-beat-fade' : durability ? '' : 'fa-regular fa-scale-balanced' 63 | } 64 | style={ 65 | durability 66 | ? { 67 | 68 | } 69 | : { 70 | fontSize: '0.7vw', 71 | marginLeft: '0.25vw', 72 | marginTop: '0.4vw', 73 | animationDuration: '3s', 74 | } 75 | } 76 | /> 77 | 78 | ); 79 | }; 80 | export default WeightBar; 81 | -------------------------------------------------------------------------------- /web/src/components/utils/icons/ClockIcon.tsx: -------------------------------------------------------------------------------- 1 | export const ClockIcon: React.FC = () => { 2 | return ( 3 | 14 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default ClockIcon; 22 | -------------------------------------------------------------------------------- /web/src/components/utils/transitions/Fade.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { CSSTransition } from 'react-transition-group'; 3 | 4 | interface Props { 5 | in?: boolean; 6 | children: React.ReactNode; 7 | } 8 | 9 | const Fade: React.FC = (props) => { 10 | const nodeRef = React.useRef(null); 11 | 12 | return ( 13 | 14 | {props.children} 15 | 16 | ); 17 | }; 18 | 19 | export default Fade; 20 | -------------------------------------------------------------------------------- /web/src/components/utils/transitions/SlideUp.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { CSSTransition } from 'react-transition-group'; 3 | 4 | interface Props { 5 | in?: boolean; 6 | children: React.ReactElement>; 7 | } 8 | 9 | const SlideUp: React.FC = (props) => { 10 | const nodeRef = React.useRef(null); 11 | 12 | return ( 13 | 14 | {React.cloneElement(props.children, { ref: nodeRef })} 15 | 16 | ); 17 | }; 18 | 19 | export default SlideUp; 20 | -------------------------------------------------------------------------------- /web/src/dnd/onBuy.ts: -------------------------------------------------------------------------------- 1 | import { isSlotWithItem } from '../helpers'; 2 | import { store } from '../store'; 3 | import { DragSource, DropTarget } from '../typings'; 4 | import { Items } from '../store/items'; 5 | import { buyItem } from '../thunks/buyItem'; 6 | 7 | export const onBuy = (source: DragSource, target: DropTarget) => { 8 | const { inventory: state } = store.getState(); 9 | 10 | const sourceInventory = state.rightInventory; 11 | const targetInventory = state.leftInventory; 12 | 13 | const sourceSlot = sourceInventory.items[source.item.slot - 1]; 14 | 15 | if (!isSlotWithItem(sourceSlot)) throw new Error(`Item ${sourceSlot.slot} name === undefined`); 16 | 17 | if (sourceSlot.count === 0) return; 18 | 19 | const sourceData = Items[sourceSlot.name]; 20 | 21 | if (sourceData === undefined) return console.error(`Item ${sourceSlot.name} data undefined!`); 22 | 23 | const targetSlot = targetInventory.items[target.item.slot - 1]; 24 | 25 | if (targetSlot === undefined) return console.error(`Target slot undefined`); 26 | 27 | const count = 28 | state.itemAmount !== 0 29 | ? sourceSlot.count 30 | ? state.itemAmount > sourceSlot.count 31 | ? sourceSlot.count 32 | : state.itemAmount 33 | : state.itemAmount 34 | : 1; 35 | 36 | const data = { 37 | fromSlot: sourceSlot, 38 | toSlot: targetSlot, 39 | fromType: sourceInventory.type, 40 | toType: targetInventory.type, 41 | count: count, 42 | }; 43 | 44 | store.dispatch( 45 | buyItem({ 46 | ...data, 47 | fromSlot: sourceSlot.slot, 48 | toSlot: targetSlot.slot, 49 | }) 50 | ); 51 | }; 52 | -------------------------------------------------------------------------------- /web/src/dnd/onCraft.ts: -------------------------------------------------------------------------------- 1 | import { store } from '../store'; 2 | import { DragSource, DropTarget } from '../typings'; 3 | import { isSlotWithItem } from '../helpers'; 4 | import { Items } from '../store/items'; 5 | import { craftItem } from '../thunks/craftItem'; 6 | 7 | export const onCraft = (source: DragSource, target: DropTarget) => { 8 | const { inventory: state } = store.getState(); 9 | 10 | const sourceInventory = state.rightInventory; 11 | const targetInventory = state.leftInventory; 12 | 13 | const sourceSlot = sourceInventory.items[source.item.slot - 1]; 14 | 15 | if (!isSlotWithItem(sourceSlot)) throw new Error(`Item ${sourceSlot.slot} name === undefined`); 16 | 17 | if (sourceSlot.count === 0) return; 18 | 19 | const sourceData = Items[sourceSlot.name]; 20 | 21 | if (sourceData === undefined) return console.error(`Item ${sourceSlot.name} data undefined!`); 22 | 23 | const targetSlot = targetInventory.items[target.item.slot - 1]; 24 | 25 | if (targetSlot === undefined) return console.error(`Target slot undefined`); 26 | 27 | const count = state.itemAmount === 0 ? 1 : state.itemAmount; 28 | 29 | const data = { 30 | fromSlot: sourceSlot, 31 | toSlot: targetSlot, 32 | fromType: sourceInventory.type, 33 | toType: targetInventory.type, 34 | count, 35 | }; 36 | 37 | store.dispatch( 38 | craftItem({ 39 | ...data, 40 | fromSlot: sourceSlot.slot, 41 | toSlot: targetSlot.slot, 42 | }) 43 | ); 44 | }; 45 | -------------------------------------------------------------------------------- /web/src/dnd/onDrop.ts: -------------------------------------------------------------------------------- 1 | import { canStack, findAvailableSlot, getTargetInventory, isSlotWithItem } from '../helpers'; 2 | import { validateMove } from '../thunks/validateItems'; 3 | import { store } from '../store'; 4 | import { DragSource, DropTarget, InventoryType, SlotWithItem } from '../typings'; 5 | import { moveSlots, stackSlots, swapSlots } from '../store/inventory'; 6 | import { Items } from '../store/items'; 7 | 8 | export const onDrop = (source: DragSource, target?: DropTarget) => { 9 | const { inventory: state } = store.getState(); 10 | 11 | const { sourceInventory, targetInventory } = getTargetInventory(state, source.inventory, target?.inventory); 12 | 13 | const sourceSlot = sourceInventory.items[source.item.slot - 1] as SlotWithItem; 14 | 15 | const sourceData = Items[sourceSlot.name]; 16 | 17 | if (sourceData === undefined) return console.error(`${sourceSlot.name} item data undefined!`); 18 | 19 | // If dragging from container slot 20 | if (sourceSlot.metadata?.container !== undefined) { 21 | // Prevent storing container in container 22 | if (targetInventory.type === InventoryType.CONTAINER) 23 | return console.log(`Cannot store container ${sourceSlot.name} inside another container`); 24 | 25 | // Prevent dragging of container slot when opened 26 | if (state.rightInventory.id === sourceSlot.metadata.container) 27 | return console.log(`Cannot move container ${sourceSlot.name} when opened`); 28 | } 29 | 30 | const targetSlot = target 31 | ? targetInventory.items[target.item.slot - 1] 32 | : findAvailableSlot(sourceSlot, sourceData, targetInventory.items); 33 | 34 | if (targetSlot === undefined) return console.error('Target slot undefined!'); 35 | 36 | // If dropping on container slot when opened 37 | if (targetSlot.metadata?.container !== undefined && state.rightInventory.id === targetSlot.metadata.container) 38 | return console.log(`Cannot swap item ${sourceSlot.name} with container ${targetSlot.name} when opened`); 39 | 40 | const count = 41 | state.shiftPressed && sourceSlot.count > 1 && sourceInventory.type !== 'shop' 42 | ? Math.floor(sourceSlot.count / 2) 43 | : state.itemAmount === 0 || state.itemAmount > sourceSlot.count 44 | ? sourceSlot.count 45 | : state.itemAmount; 46 | 47 | const data = { 48 | fromSlot: sourceSlot, 49 | toSlot: targetSlot, 50 | fromType: sourceInventory.type, 51 | toType: targetInventory.type, 52 | count: count, 53 | }; 54 | 55 | store.dispatch( 56 | validateMove({ 57 | ...data, 58 | fromSlot: sourceSlot.slot, 59 | toSlot: targetSlot.slot, 60 | }) 61 | ); 62 | 63 | isSlotWithItem(targetSlot, true) 64 | ? sourceData.stack && canStack(sourceSlot, targetSlot) 65 | ? store.dispatch( 66 | stackSlots({ 67 | ...data, 68 | toSlot: targetSlot, 69 | }) 70 | ) 71 | : store.dispatch( 72 | swapSlots({ 73 | ...data, 74 | toSlot: targetSlot, 75 | }) 76 | ) 77 | : store.dispatch(moveSlots(data)); 78 | }; 79 | -------------------------------------------------------------------------------- /web/src/dnd/onGive.ts: -------------------------------------------------------------------------------- 1 | import { store } from '../store'; 2 | import { Slot } from '../typings'; 3 | import { fetchNui } from '../utils/fetchNui'; 4 | 5 | export const onGive = (item: Slot) => { 6 | const { 7 | inventory: { itemAmount }, 8 | } = store.getState(); 9 | fetchNui('giveItem', { slot: item.slot, count: itemAmount }); 10 | }; 11 | -------------------------------------------------------------------------------- /web/src/dnd/onUse.ts: -------------------------------------------------------------------------------- 1 | //import toast from "react-hot-toast"; 2 | import { fetchNui } from '../utils/fetchNui'; 3 | import { Slot } from '../typings'; 4 | 5 | export const onUse = (item: Slot) => { 6 | //toast.success(`Use ${item.name}`); 7 | fetchNui('useItem', item.slot); 8 | }; 9 | -------------------------------------------------------------------------------- /web/src/hooks/useDebounce.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | export function useDebounce(value: T, delay?: number): T { 4 | const [debouncedValue, setDebouncedValue] = useState(value); 5 | 6 | useEffect(() => { 7 | const timer = setTimeout(() => setDebouncedValue(value), delay || 500); 8 | 9 | return () => { 10 | clearTimeout(timer); 11 | }; 12 | }, [value, delay]); 13 | 14 | return debouncedValue; 15 | } 16 | -------------------------------------------------------------------------------- /web/src/hooks/useExitListener.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | import { noop } from '../utils/misc'; 3 | import { fetchNui } from '../utils/fetchNui'; 4 | import { closeTooltip } from '../store/tooltip'; 5 | import { useAppDispatch } from '../store'; 6 | import { closeContextMenu } from '../store/contextMenu'; 7 | 8 | type FrameVisibleSetter = (bool: boolean) => void; 9 | 10 | const LISTENED_KEYS = ['Escape']; 11 | 12 | // Basic hook to listen for key presses in NUI in order to exit 13 | export const useExitListener = (visibleSetter: FrameVisibleSetter) => { 14 | const setterRef = useRef(noop); 15 | const dispatch = useAppDispatch(); 16 | 17 | useEffect(() => { 18 | setterRef.current = visibleSetter; 19 | }, [visibleSetter]); 20 | 21 | useEffect(() => { 22 | const keyHandler = (e: KeyboardEvent) => { 23 | if (LISTENED_KEYS.includes(e.code)) { 24 | setterRef.current(false); 25 | dispatch(closeTooltip()); 26 | dispatch(closeContextMenu()); 27 | fetchNui('exit'); 28 | } 29 | }; 30 | 31 | window.addEventListener('keyup', keyHandler); 32 | 33 | return () => window.removeEventListener('keyup', keyHandler); 34 | }, []); 35 | }; 36 | -------------------------------------------------------------------------------- /web/src/hooks/useIntersection.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/mantinedev/mantine/blob/master/src/mantine-hooks/src/use-intersection/use-intersection.ts 2 | 3 | import { useCallback, useRef, useState } from 'react'; 4 | 5 | export function useIntersection( 6 | options?: ConstructorParameters[1] 7 | ) { 8 | const [entry, setEntry] = useState(null); 9 | 10 | const observer = useRef(null); 11 | 12 | const ref = useCallback( 13 | (element: T | null) => { 14 | if (observer.current) { 15 | observer.current.disconnect(); 16 | observer.current = null; 17 | } 18 | 19 | if (element === null) { 20 | setEntry(null); 21 | return; 22 | } 23 | 24 | observer.current = new IntersectionObserver(([_entry]) => { 25 | setEntry(_entry); 26 | }, options); 27 | 28 | observer.current.observe(element); 29 | }, 30 | [options?.rootMargin, options?.root, options?.threshold] 31 | ); 32 | 33 | return { ref, entry }; 34 | } 35 | -------------------------------------------------------------------------------- /web/src/hooks/useKeyPress.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const useKeyPress = (targetKey: KeyboardEvent['key']) => { 4 | const [keyPressed, setKeyPressed] = React.useState(false); 5 | 6 | const downHandler = React.useCallback( 7 | ({ key }: KeyboardEvent) => { 8 | if (key === targetKey) { 9 | setKeyPressed(true); 10 | } 11 | }, 12 | [targetKey] 13 | ); 14 | 15 | const upHandler = React.useCallback( 16 | ({ key }: KeyboardEvent) => { 17 | if (key === targetKey) { 18 | setKeyPressed(false); 19 | } 20 | }, 21 | [targetKey] 22 | ); 23 | 24 | React.useEffect(() => { 25 | window.addEventListener('keydown', downHandler); 26 | window.addEventListener('keyup', upHandler); 27 | 28 | return () => { 29 | window.removeEventListener('keydown', downHandler); 30 | window.removeEventListener('keyup', upHandler); 31 | }; 32 | }, [downHandler, upHandler]); 33 | 34 | return keyPressed; 35 | }; 36 | 37 | export default useKeyPress; 38 | -------------------------------------------------------------------------------- /web/src/hooks/useNuiEvent.ts: -------------------------------------------------------------------------------- 1 | import { MutableRefObject, useEffect, useRef } from 'react'; 2 | import { noop } from '../utils/misc'; 3 | 4 | interface NuiMessageData { 5 | action: string; 6 | data: T; 7 | } 8 | 9 | type NuiHandlerSignature = (data: T) => void; 10 | 11 | /** 12 | * A hook that manage events listeners for receiving data from the client scripts 13 | * @param action The specific `action` that should be listened for. 14 | * @param handler The callback function that will handle data relayed by this hook 15 | * 16 | * @example 17 | * useNuiEvent<{visibility: true, wasVisible: 'something'}>('setVisible', (data) => { 18 | * // whatever logic you want 19 | * }) 20 | * 21 | **/ 22 | 23 | export const useNuiEvent = (action: string, handler: (data: T) => void) => { 24 | const savedHandler: MutableRefObject> = useRef(noop); 25 | 26 | // When handler value changes set mutable ref to handler val 27 | useEffect(() => { 28 | savedHandler.current = handler; 29 | }, [handler]); 30 | 31 | useEffect(() => { 32 | const eventListener = (event: MessageEvent>) => { 33 | const { action: eventAction, data } = event.data; 34 | 35 | if (savedHandler.current) { 36 | if (eventAction === action) { 37 | savedHandler.current(data); 38 | } 39 | } 40 | }; 41 | 42 | window.addEventListener('message', eventListener); 43 | // Remove Event Listener on component cleanup 44 | return () => window.removeEventListener('message', eventListener); 45 | }, [action]); 46 | }; 47 | 48 | export default useNuiEvent; 49 | -------------------------------------------------------------------------------- /web/src/hooks/useQueue.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | export interface QueueMethods { 4 | add: (item: T) => void; 5 | remove: () => void; 6 | first: T; 7 | last: T; 8 | values: T[]; 9 | size: number; 10 | } 11 | 12 | const useQueue = (initialValue: T[] = []): QueueMethods => { 13 | const [state, set] = useState(initialValue); 14 | return { 15 | add: (value) => { 16 | set((queue) => [...queue, value]); 17 | }, 18 | remove: () => { 19 | let result; 20 | set(([first, ...rest]) => { 21 | result = first; 22 | return rest; 23 | }); 24 | return result; 25 | }, 26 | get values() { 27 | return state; 28 | }, 29 | get first() { 30 | return state[0]; 31 | }, 32 | get last() { 33 | return state[state.length - 1]; 34 | }, 35 | get size() { 36 | return state.length; 37 | }, 38 | }; 39 | }; 40 | 41 | export default useQueue; 42 | -------------------------------------------------------------------------------- /web/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import { Provider } from 'react-redux'; 4 | import { DndProvider } from 'react-dnd'; 5 | import { TouchBackend } from 'react-dnd-touch-backend'; 6 | import { store } from './store'; 7 | import App from './App'; 8 | import './index.scss'; 9 | import { ItemNotificationsProvider } from './components/utils/ItemNotifications'; 10 | import { isEnvBrowser } from './utils/misc'; 11 | 12 | const root = document.getElementById('root'); 13 | 14 | if (isEnvBrowser()) { 15 | // https://i.imgur.com/iPTAdYV.png - Night time img 16 | root!.style.backgroundImage = 'url("https://i.imgur.com/3pzRj9n.png")'; 17 | root!.style.backgroundSize = 'cover'; 18 | root!.style.backgroundRepeat = 'no-repeat'; 19 | root!.style.backgroundPosition = 'center'; 20 | } 21 | 22 | createRoot(root!).render( 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ); 33 | -------------------------------------------------------------------------------- /web/src/reducers/index.ts: -------------------------------------------------------------------------------- 1 | export { setupInventoryReducer } from './setupInventory'; 2 | export { refreshSlotsReducer } from './refreshSlots'; 3 | 4 | export { swapSlotsReducer } from './swapSlots'; 5 | export { stackSlotsReducer } from './stackSlots'; 6 | export { moveSlotsReducer } from './moveSlots'; 7 | -------------------------------------------------------------------------------- /web/src/reducers/moveSlots.ts: -------------------------------------------------------------------------------- 1 | import { CaseReducer, PayloadAction } from '@reduxjs/toolkit'; 2 | import { getTargetInventory, itemDurability } from '../helpers'; 3 | import { Inventory, InventoryType, Slot, SlotWithItem, State } from '../typings'; 4 | 5 | export const moveSlotsReducer: CaseReducer< 6 | State, 7 | PayloadAction<{ 8 | fromSlot: SlotWithItem; 9 | fromType: Inventory['type']; 10 | toSlot: Slot; 11 | toType: Inventory['type']; 12 | count: number; 13 | }> 14 | > = (state, action) => { 15 | const { fromSlot, fromType, toSlot, toType, count } = action.payload; 16 | const { sourceInventory, targetInventory } = getTargetInventory(state, fromType, toType); 17 | const pieceWeight = fromSlot.weight / fromSlot.count; 18 | const curTime = Math.floor(Date.now() / 1000); 19 | const fromItem = sourceInventory.items[fromSlot.slot - 1]; 20 | 21 | targetInventory.items[toSlot.slot - 1] = { 22 | ...fromItem, 23 | count: count, 24 | weight: pieceWeight * count, 25 | slot: toSlot.slot, 26 | durability: itemDurability(fromItem.metadata, curTime), 27 | }; 28 | 29 | if (fromType === InventoryType.SHOP || fromType === InventoryType.CRAFTING) return; 30 | 31 | sourceInventory.items[fromSlot.slot - 1] = 32 | fromSlot.count - count > 0 33 | ? { 34 | ...sourceInventory.items[fromSlot.slot - 1], 35 | count: fromSlot.count - count, 36 | weight: pieceWeight * (fromSlot.count - count), 37 | } 38 | : { 39 | slot: fromSlot.slot, 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /web/src/reducers/refreshSlots.ts: -------------------------------------------------------------------------------- 1 | import { CaseReducer, PayloadAction } from '@reduxjs/toolkit'; 2 | import { itemDurability } from '../helpers'; 3 | import { Items } from '../store/items'; 4 | import { InventoryType, Slot, State } from '../typings'; 5 | import { inventorySlice } from '../store/inventory'; 6 | import RightInventory from '../components/inventory/RightInventory'; 7 | 8 | export type ItemsPayload = { item: Slot; inventory?: InventoryType }; 9 | 10 | interface Payload { 11 | items?: ItemsPayload | ItemsPayload[]; 12 | itemCount?: Record; 13 | weightData?: { inventoryId: string; maxWeight: number }; 14 | slotsData?: { inventoryId: string; slots: number }; 15 | } 16 | 17 | export const refreshSlotsReducer: CaseReducer> = (state, action) => { 18 | if (action.payload.items) { 19 | if (!Array.isArray(action.payload.items)) action.payload.items = [action.payload.items]; 20 | const curTime = Math.floor(Date.now() / 1000); 21 | 22 | Object.values(action.payload.items) 23 | .filter((data) => !!data) 24 | .forEach((data) => { 25 | const targetInventory = data.inventory 26 | ? data.inventory !== InventoryType.PLAYER 27 | ? state.rightInventory 28 | : state.leftInventory 29 | : state.leftInventory; 30 | 31 | data.item.durability = itemDurability(data.item.metadata, curTime); 32 | targetInventory.items[data.item.slot - 1] = data.item; 33 | }); 34 | 35 | // Janky workaround to force a state rerender for crafting inventory to 36 | // run canCraftItem checks 37 | if (state.rightInventory.type === InventoryType.CRAFTING) { 38 | state.rightInventory = { ...state.rightInventory }; 39 | } 40 | } 41 | 42 | if (action.payload.itemCount) { 43 | const items = Object.entries(action.payload.itemCount); 44 | 45 | for (let i = 0; i < items.length; i++) { 46 | const item = items[i][0]; 47 | const count = items[i][1]; 48 | 49 | if (Items[item]!) { 50 | Items[item]!.count += count; 51 | } else console.log(`Item data for ${item} is undefined`); 52 | } 53 | } 54 | 55 | // Refresh maxWeight when SetMaxWeight is ran while an inventory is open 56 | if (action.payload.weightData) { 57 | const inventoryId = action.payload.weightData.inventoryId; 58 | const inventoryMaxWeight = action.payload.weightData.maxWeight; 59 | const inv = 60 | inventoryId === state.leftInventory.id 61 | ? 'leftInventory' 62 | : inventoryId === state.rightInventory.id 63 | ? 'rightInventory' 64 | : null; 65 | 66 | if (!inv) return; 67 | 68 | state[inv].maxWeight = inventoryMaxWeight; 69 | } 70 | 71 | if (action.payload.slotsData) { 72 | const { inventoryId } = action.payload.slotsData; 73 | const { slots } = action.payload.slotsData; 74 | 75 | const inv = 76 | inventoryId === state.leftInventory.id 77 | ? 'leftInventory' 78 | : inventoryId === state.rightInventory.id 79 | ? 'rightInventory' 80 | : null; 81 | 82 | if (!inv) return; 83 | 84 | state[inv].slots = slots; 85 | inventorySlice.caseReducers.setupInventory(state, { 86 | type: 'setupInventory', 87 | payload: { 88 | leftInventory: inv === 'leftInventory' ? state[inv] : undefined, 89 | rightInventory: inv === 'rightInventory' ? state[inv] : undefined, 90 | }, 91 | }); 92 | } 93 | }; 94 | -------------------------------------------------------------------------------- /web/src/reducers/setupInventory.ts: -------------------------------------------------------------------------------- 1 | import { CaseReducer, PayloadAction } from '@reduxjs/toolkit'; 2 | import { getItemData, itemDurability } from '../helpers'; 3 | import { Items } from '../store/items'; 4 | import { Inventory, State } from '../typings'; 5 | 6 | export const setupInventoryReducer: CaseReducer< 7 | State, 8 | PayloadAction<{ 9 | leftInventory?: Inventory; 10 | rightInventory?: Inventory; 11 | }> 12 | > = (state, action) => { 13 | const { leftInventory, rightInventory } = action.payload; 14 | const curTime = Math.floor(Date.now() / 1000); 15 | 16 | if (leftInventory) 17 | state.leftInventory = { 18 | ...leftInventory, 19 | items: Array.from(Array(leftInventory.slots), (_, index) => { 20 | const item = Object.values(leftInventory.items).find((item) => item?.slot === index + 1) || { 21 | slot: index + 1, 22 | }; 23 | 24 | if (!item.name) return item; 25 | 26 | if (typeof Items[item.name] === 'undefined') { 27 | getItemData(item.name); 28 | } 29 | 30 | item.durability = itemDurability(item.metadata, curTime); 31 | return item; 32 | }), 33 | }; 34 | 35 | if (rightInventory) 36 | state.rightInventory = { 37 | ...rightInventory, 38 | items: Array.from(Array(rightInventory.slots), (_, index) => { 39 | const item = Object.values(rightInventory.items).find((item) => item?.slot === index + 1) || { 40 | slot: index + 1, 41 | }; 42 | 43 | if (!item.name) return item; 44 | 45 | if (typeof Items[item.name] === 'undefined') { 46 | getItemData(item.name); 47 | } 48 | 49 | item.durability = itemDurability(item.metadata, curTime); 50 | return item; 51 | }), 52 | }; 53 | 54 | state.isBusy = false; 55 | }; 56 | -------------------------------------------------------------------------------- /web/src/reducers/stackSlots.ts: -------------------------------------------------------------------------------- 1 | import { CaseReducer, PayloadAction } from '@reduxjs/toolkit'; 2 | import { getTargetInventory } from '../helpers'; 3 | import { Inventory, InventoryType, SlotWithItem, State } from '../typings'; 4 | 5 | export const stackSlotsReducer: CaseReducer< 6 | State, 7 | PayloadAction<{ 8 | fromSlot: SlotWithItem; 9 | fromType: Inventory['type']; 10 | toSlot: SlotWithItem; 11 | toType: Inventory['type']; 12 | count: number; 13 | }> 14 | > = (state, action) => { 15 | const { fromSlot, fromType, toSlot, toType, count } = action.payload; 16 | 17 | const { sourceInventory, targetInventory } = getTargetInventory(state, fromType, toType); 18 | 19 | const pieceWeight = fromSlot.weight / fromSlot.count; 20 | 21 | targetInventory.items[toSlot.slot - 1] = { 22 | ...targetInventory.items[toSlot.slot - 1], 23 | count: toSlot.count + count, 24 | weight: pieceWeight * (toSlot.count + count), 25 | }; 26 | 27 | if (fromType === InventoryType.SHOP || fromType === InventoryType.CRAFTING) return; 28 | 29 | sourceInventory.items[fromSlot.slot - 1] = 30 | fromSlot.count - count > 0 31 | ? { 32 | ...sourceInventory.items[fromSlot.slot - 1], 33 | count: fromSlot.count - count, 34 | weight: pieceWeight * (fromSlot.count - count), 35 | } 36 | : { 37 | slot: fromSlot.slot, 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /web/src/reducers/swapSlots.ts: -------------------------------------------------------------------------------- 1 | import { CaseReducer, PayloadAction } from '@reduxjs/toolkit'; 2 | import { getTargetInventory, itemDurability } from '../helpers'; 3 | import { Inventory, SlotWithItem, State } from '../typings'; 4 | 5 | export const swapSlotsReducer: CaseReducer< 6 | State, 7 | PayloadAction<{ 8 | fromSlot: SlotWithItem; 9 | fromType: Inventory['type']; 10 | toSlot: SlotWithItem; 11 | toType: Inventory['type']; 12 | }> 13 | > = (state, action) => { 14 | const { fromSlot, fromType, toSlot, toType } = action.payload; 15 | const { sourceInventory, targetInventory } = getTargetInventory(state, fromType, toType); 16 | const curTime = Math.floor(Date.now() / 1000); 17 | 18 | [sourceInventory.items[fromSlot.slot - 1], targetInventory.items[toSlot.slot - 1]] = [ 19 | { 20 | ...targetInventory.items[toSlot.slot - 1], 21 | slot: fromSlot.slot, 22 | durability: itemDurability(toSlot.metadata, curTime), 23 | }, 24 | { 25 | ...sourceInventory.items[fromSlot.slot - 1], 26 | slot: toSlot.slot, 27 | durability: itemDurability(fromSlot.metadata, curTime), 28 | }, 29 | ]; 30 | }; 31 | -------------------------------------------------------------------------------- /web/src/store/contextMenu.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from '@reduxjs/toolkit'; 2 | import { SlotWithItem } from '../typings'; 3 | 4 | interface ContextMenuState { 5 | coords: { 6 | x: number; 7 | y: number; 8 | } | null; 9 | item: SlotWithItem | null; 10 | } 11 | 12 | const initialState: ContextMenuState = { 13 | coords: null, 14 | item: null, 15 | }; 16 | 17 | export const contextMenuSlice = createSlice({ 18 | name: 'contextMenu', 19 | initialState, 20 | reducers: { 21 | openContextMenu(state, action: PayloadAction<{ item: SlotWithItem; coords: { x: number; y: number } }>) { 22 | state.coords = action.payload.coords; 23 | state.item = action.payload.item; 24 | }, 25 | closeContextMenu(state) { 26 | state.coords = null; 27 | }, 28 | }, 29 | }); 30 | 31 | export const { openContextMenu, closeContextMenu } = contextMenuSlice.actions; 32 | 33 | export default contextMenuSlice.reducer; 34 | -------------------------------------------------------------------------------- /web/src/store/damage.ts: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const initialState = { 4 | data : {} 5 | } 6 | 7 | const damageSlice = createSlice({ 8 | name: 'damage', 9 | initialState, 10 | reducers: { 11 | setDamage: (state:any, action:any) => { 12 | state.data = action.payload; 13 | }, 14 | } 15 | }) 16 | 17 | export const { setDamage } = damageSlice.actions; 18 | export default damageSlice.reducer; -------------------------------------------------------------------------------- /web/src/store/imagepath.ts: -------------------------------------------------------------------------------- 1 | export let imagepath = 'images'; 2 | 3 | export function setImagePath(path: string) { 4 | if (path && path !== '') imagepath = path; 5 | } 6 | -------------------------------------------------------------------------------- /web/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { Action, configureStore, ThunkAction } from '@reduxjs/toolkit'; 2 | import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; 3 | import inventoryReducer from './inventory'; 4 | import tooltipReducer from './tooltip'; 5 | import contextMenuReducer from './contextMenu'; 6 | import damageReducer from './damage'; 7 | 8 | export const store = configureStore({ 9 | reducer: { 10 | inventory: inventoryReducer, 11 | tooltip: tooltipReducer, 12 | contextMenu: contextMenuReducer, 13 | damage: damageReducer, 14 | }, 15 | }); 16 | 17 | export type AppDispatch = typeof store.dispatch; 18 | export type RootState = ReturnType; 19 | export type AppThunk = ThunkAction>; 20 | 21 | export const useAppDispatch = () => useDispatch(); 22 | export const useAppSelector: TypedUseSelectorHook = useSelector; 23 | -------------------------------------------------------------------------------- /web/src/store/inventory.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, current, isFulfilled, isPending, isRejected, PayloadAction } from '@reduxjs/toolkit'; 2 | import type { RootState } from '.'; 3 | import { Slot, State } from '../typings'; 4 | import { 5 | moveSlotsReducer, 6 | refreshSlotsReducer, 7 | setupInventoryReducer, 8 | stackSlotsReducer, 9 | swapSlotsReducer, 10 | } from '../reducers'; 11 | 12 | const initialState: State = { 13 | leftInventory: { 14 | id: '', 15 | type: '', 16 | slots: 0, 17 | maxWeight: 0, 18 | items: [], 19 | }, 20 | rightInventory: { 21 | id: '', 22 | type: '', 23 | slots: 0, 24 | maxWeight: 0, 25 | items: [], 26 | }, 27 | additionalMetadata: new Array(), 28 | itemAmount: 0, 29 | shiftPressed: false, 30 | isBusy: false, 31 | }; 32 | 33 | export const inventorySlice = createSlice({ 34 | name: 'inventory', 35 | initialState, 36 | reducers: { 37 | stackSlots: stackSlotsReducer, 38 | swapSlots: swapSlotsReducer, 39 | setupInventory: setupInventoryReducer, 40 | moveSlots: moveSlotsReducer, 41 | refreshSlots: refreshSlotsReducer, 42 | setAdditionalMetadata: (state, action: PayloadAction>) => { 43 | const metadata = []; 44 | 45 | for (let i = 0; i < action.payload.length; i++) { 46 | const entry = action.payload[i]; 47 | if (!state.additionalMetadata.find((el) => el.value === entry.value)) metadata.push(entry); 48 | } 49 | 50 | state.additionalMetadata = [...state.additionalMetadata, ...metadata]; 51 | }, 52 | setItemAmount: (state, action: PayloadAction) => { 53 | state.itemAmount = action.payload; 54 | }, 55 | setShiftPressed: (state, action: PayloadAction) => { 56 | state.shiftPressed = action.payload; 57 | }, 58 | setContainerWeight: (state, action: PayloadAction) => { 59 | const container = state.leftInventory.items.find((item) => item.metadata?.container === state.rightInventory.id); 60 | 61 | if (!container) return; 62 | 63 | container.weight = action.payload; 64 | }, 65 | }, 66 | extraReducers: (builder) => { 67 | builder.addMatcher(isPending, (state) => { 68 | state.isBusy = true; 69 | 70 | state.history = { 71 | leftInventory: current(state.leftInventory), 72 | rightInventory: current(state.rightInventory), 73 | }; 74 | }); 75 | builder.addMatcher(isFulfilled, (state) => { 76 | state.isBusy = false; 77 | }); 78 | builder.addMatcher(isRejected, (state) => { 79 | if (state.history && state.history.leftInventory && state.history.rightInventory) { 80 | state.leftInventory = state.history.leftInventory; 81 | state.rightInventory = state.history.rightInventory; 82 | } 83 | state.isBusy = false; 84 | }); 85 | }, 86 | }); 87 | 88 | export const { 89 | setAdditionalMetadata, 90 | setItemAmount, 91 | setShiftPressed, 92 | setupInventory, 93 | swapSlots, 94 | moveSlots, 95 | stackSlots, 96 | refreshSlots, 97 | setContainerWeight, 98 | } = inventorySlice.actions; 99 | export const selectLeftInventory = (state: RootState) => state.inventory.leftInventory; 100 | export const selectRightInventory = (state: RootState) => state.inventory.rightInventory; 101 | export const selectItemAmount = (state: RootState) => state.inventory.itemAmount; 102 | export const selectIsBusy = (state: RootState) => state.inventory.isBusy; 103 | 104 | export default inventorySlice.reducer; 105 | -------------------------------------------------------------------------------- /web/src/store/items.ts: -------------------------------------------------------------------------------- 1 | import { ItemData } from '../typings/item'; 2 | 3 | export const Items: { 4 | [key: string]: ItemData | undefined; 5 | } = { 6 | water: { 7 | name: 'water', 8 | close: false, 9 | label: 'VODA', 10 | stack: true, 11 | usable: true, 12 | count: 0, 13 | }, 14 | burger: { 15 | name: 'burger', 16 | close: false, 17 | label: 'BURGR', 18 | stack: false, 19 | usable: false, 20 | count: 0, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /web/src/store/locale.ts: -------------------------------------------------------------------------------- 1 | export const Locale: { 2 | [key: string]: string; 3 | } = {}; 4 | -------------------------------------------------------------------------------- /web/src/store/tooltip.ts: -------------------------------------------------------------------------------- 1 | import { createSlice, PayloadAction } from '@reduxjs/toolkit'; 2 | import { Inventory, SlotWithItem } from '../typings'; 3 | 4 | interface TooltipState { 5 | open: boolean; 6 | item: SlotWithItem | null; 7 | inventoryType: Inventory['type'] | null; 8 | } 9 | 10 | const initialState: TooltipState = { 11 | open: false, 12 | item: null, 13 | inventoryType: null, 14 | }; 15 | 16 | export const tooltipSlice = createSlice({ 17 | name: 'tooltip', 18 | initialState, 19 | reducers: { 20 | openTooltip(state, action: PayloadAction<{ item: SlotWithItem; inventoryType: Inventory['type'] }>) { 21 | state.open = true; 22 | state.item = action.payload.item; 23 | state.inventoryType = action.payload.inventoryType; 24 | }, 25 | closeTooltip(state) { 26 | state.open = false; 27 | }, 28 | }, 29 | }); 30 | 31 | export const { openTooltip, closeTooltip } = tooltipSlice.actions; 32 | 33 | export default tooltipSlice.reducer; 34 | -------------------------------------------------------------------------------- /web/src/thunks/buyItem.ts: -------------------------------------------------------------------------------- 1 | import { createAsyncThunk } from '@reduxjs/toolkit'; 2 | import { fetchNui } from '../utils/fetchNui'; 3 | 4 | export const buyItem = createAsyncThunk( 5 | 'inventory/buyItem', 6 | async ( 7 | data: { 8 | fromSlot: number; 9 | fromType: string; 10 | toSlot: number; 11 | toType: string; 12 | count: number; 13 | }, 14 | { rejectWithValue } 15 | ) => { 16 | try { 17 | const response = await fetchNui('buyItem', data); 18 | 19 | if (response === false) { 20 | return rejectWithValue(response); 21 | } 22 | } catch (error) { 23 | return rejectWithValue(false); 24 | } 25 | } 26 | ); 27 | -------------------------------------------------------------------------------- /web/src/thunks/craftItem.ts: -------------------------------------------------------------------------------- 1 | import { createAsyncThunk } from '@reduxjs/toolkit'; 2 | import { fetchNui } from '../utils/fetchNui'; 3 | 4 | export const craftItem = createAsyncThunk( 5 | 'inventory/craftItem', 6 | async ( 7 | data: { fromSlot: number; fromType: string; toSlot: number; toType: string; count: number }, 8 | { rejectWithValue } 9 | ) => { 10 | try { 11 | const response = await fetchNui('craftItem', data); 12 | 13 | if (response === false) { 14 | return rejectWithValue(response); 15 | } 16 | } catch (error) { 17 | return rejectWithValue(false); 18 | } 19 | } 20 | ); 21 | -------------------------------------------------------------------------------- /web/src/thunks/validateItems.ts: -------------------------------------------------------------------------------- 1 | import { createAsyncThunk } from '@reduxjs/toolkit'; 2 | import { setContainerWeight } from '../store/inventory'; 3 | import { fetchNui } from '../utils/fetchNui'; 4 | 5 | export const validateMove = createAsyncThunk( 6 | 'inventory/validateMove', 7 | async ( 8 | data: { 9 | fromSlot: number; 10 | fromType: string; 11 | toSlot: number; 12 | toType: string; 13 | count: number; 14 | }, 15 | { rejectWithValue, dispatch } 16 | ) => { 17 | try { 18 | const response = await fetchNui('swapItems', data); 19 | 20 | if (response === false) return rejectWithValue(response); 21 | 22 | if (typeof response === 'number') dispatch(setContainerWeight(response)); 23 | } catch (error) { 24 | return rejectWithValue(false); 25 | } 26 | } 27 | ); 28 | -------------------------------------------------------------------------------- /web/src/typings/dnd.ts: -------------------------------------------------------------------------------- 1 | import { Inventory } from './inventory'; 2 | import { Slot, SlotWithItem } from './slot'; 3 | 4 | export type DragSource = { 5 | item: Pick; 6 | inventory: Inventory['type']; 7 | image?: string; 8 | }; 9 | 10 | export type DropTarget = { 11 | item: Pick; 12 | inventory: Inventory['type']; 13 | }; 14 | -------------------------------------------------------------------------------- /web/src/typings/index.ts: -------------------------------------------------------------------------------- 1 | export * from './state'; 2 | export * from './inventory'; 3 | export * from './item'; 4 | export * from './slot'; 5 | export * from './dnd'; 6 | -------------------------------------------------------------------------------- /web/src/typings/inventory.ts: -------------------------------------------------------------------------------- 1 | import { Slot } from './slot'; 2 | 3 | export enum InventoryType { 4 | PLAYER = 'player', 5 | SHOP = 'shop', 6 | CONTAINER = 'container', 7 | CRAFTING = 'crafting', 8 | } 9 | 10 | export type Inventory = { 11 | id: string; 12 | type: string; 13 | slots: number; 14 | items: Slot[]; 15 | maxWeight?: number; 16 | label?: string; 17 | groups?: Record; 18 | }; 19 | -------------------------------------------------------------------------------- /web/src/typings/item.ts: -------------------------------------------------------------------------------- 1 | export type ItemData = { 2 | name: string; 3 | label: string; 4 | stack: boolean; 5 | usable: boolean; 6 | close: boolean; 7 | count: number; 8 | description?: string; 9 | buttons?: string[]; 10 | ammoName?: string; 11 | image?: string; 12 | }; 13 | -------------------------------------------------------------------------------- /web/src/typings/slot.ts: -------------------------------------------------------------------------------- 1 | export type Slot = { 2 | slot: number; 3 | name?: string; 4 | count?: number; 5 | weight?: number; 6 | metadata?: { 7 | [key: string]: any; 8 | }; 9 | durability?: number; 10 | }; 11 | 12 | export type SlotWithItem = Slot & { 13 | name: string; 14 | count: number; 15 | weight: number; 16 | durability?: number; 17 | price?: number; 18 | currency?: string; 19 | ingredients?: { [key: string]: number }; 20 | duration?: number; 21 | image?: string; 22 | grade?: number | number[]; 23 | }; 24 | -------------------------------------------------------------------------------- /web/src/typings/state.ts: -------------------------------------------------------------------------------- 1 | import { Inventory } from './inventory'; 2 | import { Slot } from './slot'; 3 | 4 | export type State = { 5 | leftInventory: Inventory; 6 | rightInventory: Inventory; 7 | itemAmount: number; 8 | shiftPressed: boolean; 9 | isBusy: boolean; 10 | additionalMetadata: Array<{ metadata: string; value: string }>; 11 | history?: { 12 | leftInventory: Inventory; 13 | rightInventory: Inventory; 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /web/src/utils/debugData.ts: -------------------------------------------------------------------------------- 1 | import { isEnvBrowser } from './misc'; 2 | 3 | interface DebugEvent { 4 | action: string; 5 | data: T; 6 | } 7 | 8 | /** 9 | * Emulates dispatching an event using SendNUIMessage in the lua scripts. 10 | * This is used when developing in browser 11 | * 12 | * @param events - The event you want to cover 13 | * @param timer - How long until it should trigger (ms) 14 | */ 15 | export const debugData =

(events: DebugEvent

[], timer = 1000): void => { 16 | if (import.meta.env.DEV && isEnvBrowser()) { 17 | for (const event of events) { 18 | setTimeout(() => { 19 | window.dispatchEvent( 20 | new MessageEvent('message', { 21 | data: { 22 | action: event.action, 23 | data: event.data, 24 | }, 25 | }) 26 | ); 27 | }, timer); 28 | } 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /web/src/utils/fetchNui.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple wrapper around fetch API tailored for CEF/NUI use. This abstraction 3 | * can be extended to include AbortController if needed or if the response isn't 4 | * JSON. Tailor it to your needs. 5 | * 6 | * @param eventName - The endpoint eventname to target 7 | * @param data - Data you wish to send in the NUI Callback 8 | * 9 | * @return returnData - A promise for the data sent back by the NuiCallbacks CB argument 10 | */ 11 | 12 | import { isEnvBrowser } from './misc'; 13 | 14 | const resourceName = (window as any).GetParentResourceName ? (window as any).GetParentResourceName() : 'ox_inventory'; 15 | 16 | export async function fetchNui(eventName: string, data?: unknown): Promise { 17 | if (isEnvBrowser()) return undefined as any; // HACK FOR BORING ERRORS IN DEV 18 | 19 | try { 20 | const resp = await fetch(`https://${resourceName}/${eventName}`, { 21 | method: 'post', 22 | headers: { 23 | 'Content-Type': 'application/json; charset=UTF-8', 24 | }, 25 | body: JSON.stringify(data), 26 | }); 27 | 28 | const respFormatted = await resp.json(); 29 | 30 | return respFormatted; 31 | } catch (error) { 32 | throw Error(`Failed to fetch NUI callback ${eventName}! (${error})`); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /web/src/utils/img/LLEG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/LLEG.png -------------------------------------------------------------------------------- /web/src/utils/img/RLEG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/RLEG.png -------------------------------------------------------------------------------- /web/src/utils/img/head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/head.png -------------------------------------------------------------------------------- /web/src/utils/img/larm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/larm.png -------------------------------------------------------------------------------- /web/src/utils/img/lfoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/lfoot.png -------------------------------------------------------------------------------- /web/src/utils/img/lowerbody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/lowerbody.png -------------------------------------------------------------------------------- /web/src/utils/img/lpalm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/lpalm.png -------------------------------------------------------------------------------- /web/src/utils/img/neck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/neck.png -------------------------------------------------------------------------------- /web/src/utils/img/rarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/rarm.png -------------------------------------------------------------------------------- /web/src/utils/img/rfoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/rfoot.png -------------------------------------------------------------------------------- /web/src/utils/img/rpalm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/rpalm.png -------------------------------------------------------------------------------- /web/src/utils/img/upperbody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeamBroCode/ox_inventory-brocode/74ea966178201b8f314a34015336c3f2e5f2b2e7/web/src/utils/img/upperbody.png -------------------------------------------------------------------------------- /web/src/utils/misc.ts: -------------------------------------------------------------------------------- 1 | // Will return whether the current environment is in a regular browser 2 | // and not CEF 3 | export const isEnvBrowser = (): boolean => !(window as any).invokeNative; 4 | 5 | // Basic no operation function 6 | export const noop = () => {}; 7 | -------------------------------------------------------------------------------- /web/src/utils/setClipboard.ts: -------------------------------------------------------------------------------- 1 | // yoinked from https://github.com/project-error/npwd/blob/d8dc5b7f47faf5fc581ffee30f31ff61d184cfe7/phone/src/os/phone/hooks/useClipboard.ts#L1 2 | export const setClipboard = (value: string) => { 3 | const clipElem = document.createElement('input'); 4 | clipElem.value = value; 5 | document.body.appendChild(clipElem); 6 | clipElem.select(); 7 | document.execCommand('copy'); 8 | document.body.removeChild(clipElem); 9 | }; 10 | -------------------------------------------------------------------------------- /web/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "allowUnreachableCode": false, 19 | }, 20 | "include": ["src"], 21 | "references": [{ "path": "./tsconfig.node.json" }] 22 | } 23 | -------------------------------------------------------------------------------- /web/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /web/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | base: './', 8 | publicDir: false, 9 | build: { 10 | outDir: 'build', 11 | target: 'esnext', 12 | }, 13 | define: { 14 | 'process.env': {}, 15 | }, 16 | esbuild: { 17 | logOverride: { 'this-is-undefined-in-esm': 'silent' }, 18 | }, 19 | }); 20 | --------------------------------------------------------------------------------