commit 4c20cfc716a18686dbf95a7c24db7fe9d033c236 Author: IfCasper Date: Tue Jul 7 21:08:52 2026 +0200 0.0.1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9dd2cc5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,248 @@ +### Node +# Dependencies +node_modules/ + +# Logs +*.log + +# Runtime data +*.pid +*.pid.lock + +# Coverage +coverage/ +*.lcov +.nyc_output + +# Build output +dist/ +build/Release + +# TypeScript cache +*.tsbuildinfo + +# Framework build output and caches +.cache +.parcel-cache +.next +out/ +.nuxt + +# dotenv environment variable files +.env +.env.local +.env.*.local + +# npm cache directory +.npm +*.tgz + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/install-state.gz +.pnp.* + +### Windows +# Windows thumbnail cache files +Thumbs.db + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows shortcuts +*.lnk + +### VS Code +# VSCode settings (keep shared configuration) +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +# ========================================================= +# FiveM / FXServer / ESX Git Ignore +# Sauber für Server-Repos - Cache/DB/Runtime wird ignoriert +# ========================================================= + + +# --------------------------------------------------------- +# FiveM / FXServer Runtime Cache +# --------------------------------------------------------- +cache/ +.cache/ +server-cache/ +server-cache-priv/ + +# Generated cache files +*.rpf.db +*.sf1.db +*.sst +*.ldb +*.log +LOCK +CURRENT +IDENTITY +MANIFEST-* + + +# --------------------------------------------------------- +# FiveM Runtime Database / RocksDB / Local DB +# --------------------------------------------------------- +db/ +database/ +*.sqlite +*.sqlite3 +*.db +*.db-shm +*.db-wal + + +# --------------------------------------------------------- +# txAdmin Runtime Data +# --------------------------------------------------------- +txData/ +txAdmin/ +monitor/ +logs/ +crashes/ + + +# --------------------------------------------------------- +# Sensitive Configs / Secrets +# WICHTIG: server.cfg enthält oft sv_licenseKey und DB-Passwort +# --------------------------------------------------------- +server.cfg +server_private.cfg +secrets.cfg +permissions.cfg +.env +.env.* +!.env.example + +# Common secret/key files +*.pem +*.key +*.crt +*.pfx +*.p12 + + +# --------------------------------------------------------- +# Backups / Dumps +# --------------------------------------------------------- +backup/ +backups/ +dumps/ +dump/ +*.bak +*.backup +*.dump + +# SQL Dumps ignorieren, aber Install-SQL behalten +*.sql.gz +*.sql.zip +*_backup.sql +*_dump.sql +backup_*.sql +dump_*.sql + + +# --------------------------------------------------------- +# Logs +# --------------------------------------------------------- +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# --------------------------------------------------------- +# Node / NPM / Yarn / PNPM +# --------------------------------------------------------- +node_modules/ +package-lock.json +yarn.lock +pnpm-lock.yaml + + +# --------------------------------------------------------- +# Build Output +# --------------------------------------------------------- +dist/ +build/ +out/ +release/ +tmp/ +temp/ + + +# --------------------------------------------------------- +# Lua / Resource Temp Files +# --------------------------------------------------------- +*.luac +*.tmp +*.temp + + +# --------------------------------------------------------- +# Windows Trash +# --------------------------------------------------------- +Thumbs.db +desktop.ini +$RECYCLE.BIN/ + + +# --------------------------------------------------------- +# macOS Trash +# --------------------------------------------------------- +.DS_Store +.AppleDouble +.LSOverride + + +# --------------------------------------------------------- +# Linux Trash +# --------------------------------------------------------- +*~ +.directory +.Trash-* + + +# --------------------------------------------------------- +# IDE / Editor +# --------------------------------------------------------- +.vscode/ +.idea/ +*.suo +*.user +*.userosscache +*.sln.docstates + + +# --------------------------------------------------------- +# Git / Tooling Garbage +# --------------------------------------------------------- +*.orig +*.rej +*.swp +*.swo + + +# --------------------------------------------------------- +# Optional: Local-only folders +# --------------------------------------------------------- +local/ +private/ +_private/ \ No newline at end of file diff --git a/.replxx_history b/.replxx_history new file mode 100644 index 0000000..e69de29 diff --git a/esxLogo.png b/esxLogo.png new file mode 100644 index 0000000..72ddacb Binary files /dev/null and b/esxLogo.png differ diff --git a/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-hipster/fxmanifest.lua b/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-hipster/fxmanifest.lua new file mode 100644 index 0000000..aec55b6 --- /dev/null +++ b/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-hipster/fxmanifest.lua @@ -0,0 +1,14 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'Example spawn points for FiveM with a "hipster" model.' +repository 'https://github.com/citizenfx/cfx-server-data' + +resource_type 'map' { gameTypes = { ['basic-gamemode'] = true } } + +map 'map.lua' + +fx_version 'adamant' +game 'gta5' diff --git a/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-hipster/map.lua b/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-hipster/map.lua new file mode 100644 index 0000000..be81831 --- /dev/null +++ b/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-hipster/map.lua @@ -0,0 +1,63 @@ +vehicle_generator "airtug" { -54.26639938354492, -1679.548828125, 28.4414, heading = 228.2736053466797 } + +spawnpoint 'a_m_y_hipster_01' { x = -802.311, y = 175.056, z = 72.8446 } +spawnpoint 'a_m_y_hipster_02' { x = -9.96562, y = -1438.54, z = 31.1015 } +spawnpoint 'a_m_y_hipster_01' { x = 0.916756, y = 528.485, z = 174.628 } +spawnpoint 'a_m_y_hipster_01' { x = -181.615, y = 852.8, z = 232.701 } +spawnpoint 'a_m_y_hipster_02' { x = 657.723, y = 457.342, z = 144.641 } +spawnpoint 'a_m_y_hipster_01' { x = 134.387, y = 1150.31, z = 231.594 } +spawnpoint 'a_m_y_hipster_02' { x = 726.14, y = 1196.91, z = 326.262 } +spawnpoint 'a_m_y_hipster_01' { x = 740.792, y = 1283.62, z = 360.297 } +spawnpoint 'a_m_y_hipster_02' { x = -437.009, y = 1059.59, z = 327.331 } +spawnpoint 'a_m_y_hipster_01' { x = -428.771, y = 1596.8, z = 356.338 } +spawnpoint 'a_m_y_hipster_02' { x = -1348.78, y = 723.87, z = 186.45 } +spawnpoint 'a_m_y_hipster_01' { x = -1543.24, y = 830.069, z = 182.132 } +spawnpoint 'a_m_y_hipster_02' { x = -2150.48, y = 222.019, z = 184.602 } +spawnpoint 'a_m_y_hipster_01' { x = -3032.13, y = 22.2157, z = 10.1184 } +spawnpoint 'a_m_y_hipster_02' { x = 3063.97, y = 5608.88, z = 209.245 } +spawnpoint 'a_m_y_hipster_01' { x = -2614.35, y = 1872.49, z = 167.32 } +spawnpoint 'a_m_y_hipster_02' { x = -1873.94, y = 2088.73, z = 140.994 } +spawnpoint 'a_m_y_hipster_01' { x = -597.177, y = 2092.16, z = 131.413 } +spawnpoint 'a_m_y_hipster_02' { x = 967.126, y = 2226.99, z = 54.0588 } +spawnpoint 'a_m_y_hipster_01' { x = -338.043, y = 2829, z = 56.0871 } +spawnpoint 'a_m_y_hipster_02' { x = 1082.25, y = -696.921, z = 58.0099 } +spawnpoint 'a_m_y_hipster_01' { x = 1658.31, y = -13.9234, z = 169.992 } +spawnpoint 'a_m_y_hipster_02' { x = 2522.98, y = -384.436, z = 92.9928 } +spawnpoint 'a_m_y_hipster_01' { x = 2826.27, y = -656.489, z = 1.87841 } +spawnpoint 'a_m_y_hipster_02' { x = 2851.12, y = 1467.5, z = 24.5554 } +spawnpoint 'a_m_y_hipster_01' { x = 2336.33, y = 2535.39, z = 46.5177 } +spawnpoint 'a_m_y_hipster_02' { x = 2410.46, y = 3077.88, z = 48.1529 } +spawnpoint 'a_m_y_hipster_01' { x = 2451.15, y = 3768.37, z = 41.3477 } +spawnpoint 'a_m_y_hipster_02' { x = 3337.78, y = 5174.8, z = 18.2108 } +spawnpoint 'a_m_y_hipster_01' { x = -1119.33, y = 4978.52, z = 186.26 } +spawnpoint 'a_m_y_hipster_02' { x = 2877.3, y = 5911.57, z = 369.618 } +spawnpoint 'a_m_y_hipster_01' { x = 2942.1, y = 5306.73, z = 101.52 } +spawnpoint 'a_m_y_hipster_02' { x = 2211.29, y = 5577.94, z = 53.872 } +spawnpoint 'a_m_y_hipster_01' { x = 1602.39, y = 6623.02, z = 15.8417 } +spawnpoint 'a_m_y_hipster_02' { x = 66.0113, y = 7203.58, z = 3.16 } +spawnpoint 'a_m_y_hipster_01' { x = -219.201, y = 6562.82, z = 10.9706 } +spawnpoint 'a_m_y_hipster_02' { x = -45.1562, y = 6301.64, z = 31.6114 } +spawnpoint 'a_m_y_hipster_01' { x = -1004.77, y = 4854.32, z = 274.606 } +spawnpoint 'a_m_y_hipster_02' { x = -1580.01, y = 5173.3, z = 19.5813 } +spawnpoint 'a_m_y_hipster_01' { x = -1467.95, y = 5416.2, z = 23.5959 } +spawnpoint 'a_m_y_hipster_02' { x = -2359.31, y = 3243.83, z = 92.9037 } +spawnpoint 'a_m_y_hipster_01' { x = -2612.96, y = 3555.03, z = 4.85649 } +spawnpoint 'a_m_y_hipster_02' { x = -2083.27, y = 2616.94, z = 3.08396 } +spawnpoint 'a_m_y_hipster_01' { x = -524.471, y = 4195, z = 193.731 } +spawnpoint 'a_m_y_hipster_02' { x = -840.713, y = 4183.18, z = 215.29 } +spawnpoint 'a_m_y_hipster_01' { x = -1576.24, y = 2103.87, z = 67.576 } +spawnpoint 'a_m_y_hipster_02' { x = -1634.37, y = 209.816, z = 60.6413 } +spawnpoint 'a_m_y_hipster_01' { x = -1495.07, y = 142.697, z = 55.6527 } +spawnpoint 'a_m_y_hipster_02' { x = -1715.41, y = -197.722, z = 57.698 } +spawnpoint 'a_m_y_hipster_01' { x = -1181.07, y = -505.544, z = 35.5661 } +spawnpoint 'a_m_y_hipster_02' { x = -1712.37, y = -1082.91, z = 13.0801 } +spawnpoint 'a_m_y_hipster_01' { x = -1352.43, y = -1542.75, z = 4.42268 } +spawnpoint 'a_m_y_hipster_02' { x = -1756.89, y = 427.531, z = 127.685 } +spawnpoint 'a_m_y_hipster_01' { x = 3060.2, y = 2113.2, z = 1.6613 } +spawnpoint 'a_m_y_hipster_02' { x = 501.646, y = 5604.53, z = 797.91 } +spawnpoint 'a_m_y_hipster_01' { x = 714.109, y = 4151.15, z = 35.7792 } +spawnpoint 'a_m_y_hipster_02' { x = -103.651, y = -967.93, z = 296.52 } +spawnpoint 'a_m_y_hipster_01' { x = -265.333, y = -2419.35, z = 122.366 } +spawnpoint 'a_m_y_hipster_02' { x = 1788.25, y = 3890.34, z = 34.3849 } + +-- diff --git a/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-skater/fxmanifest.lua b/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-skater/fxmanifest.lua new file mode 100644 index 0000000..5075a0c --- /dev/null +++ b/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-skater/fxmanifest.lua @@ -0,0 +1,14 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'Example spawn points for FiveM with a "skater" model.' +repository 'https://github.com/citizenfx/cfx-server-data' + +resource_type 'map' { gameTypes = { ['basic-gamemode'] = true } } + +map 'map.lua' + +fx_version 'adamant' +game 'gta5' diff --git a/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-skater/map.lua b/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-skater/map.lua new file mode 100644 index 0000000..93a9069 --- /dev/null +++ b/resources/[cfx-default]/[gamemodes]/[maps]/fivem-map-skater/map.lua @@ -0,0 +1,62 @@ +spawnpoint 'a_m_y_skater_01' { x = -802.311, y = 175.056, z = 72.8446 } +spawnpoint 'a_m_y_skater_02' { x = -9.96562, y = -1438.54, z = 31.1015 } +spawnpoint 'a_m_y_skater_01' { x = 0.916756, y = 528.485, z = 174.628 } +spawnpoint 'a_m_y_skater_02' { x = 1975.86, y = 3821.03, z = 33.4501 } +spawnpoint 'a_m_y_skater_01' { x = -181.615, y = 852.8, z = 232.701 } +spawnpoint 'a_m_y_skater_02' { x = 657.723, y = 457.342, z = 144.641 } +spawnpoint 'a_m_y_skater_01' { x = 134.387, y = 1150.31, z = 231.594 } +spawnpoint 'a_m_y_skater_02' { x = 726.14, y = 1196.91, z = 326.262 } +spawnpoint 'a_m_y_skater_01' { x = 740.792, y = 1283.62, z = 360.297 } +spawnpoint 'a_m_y_skater_02' { x = -437.009, y = 1059.59, z = 327.331 } +spawnpoint 'a_m_y_skater_01' { x = -428.771, y = 1596.8, z = 356.338 } +spawnpoint 'a_m_y_skater_02' { x = -1348.78, y = 723.87, z = 186.45 } +spawnpoint 'a_m_y_skater_01' { x = -1543.24, y = 830.069, z = 182.132 } +spawnpoint 'a_m_y_skater_02' { x = -2150.48, y = 222.019, z = 184.602 } +spawnpoint 'a_m_y_skater_01' { x = -3032.13, y = 22.2157, z = 10.1184 } +spawnpoint 'a_m_y_skater_02' { x = 3063.97, y = 5608.88, z = 209.245 } +spawnpoint 'a_m_y_skater_01' { x = -2614.35, y = 1872.49, z = 167.32 } +spawnpoint 'a_m_y_skater_02' { x = -1873.94, y = 2088.73, z = 140.994 } +spawnpoint 'a_m_y_skater_01' { x = -597.177, y = 2092.16, z = 131.413 } +spawnpoint 'a_m_y_skater_02' { x = 967.126, y = 2226.99, z = 54.0588 } +spawnpoint 'a_m_y_skater_01' { x = -338.043, y = 2829, z = 56.0871 } +spawnpoint 'a_m_y_skater_02' { x = 1082.25, y = -696.921, z = 58.0099 } +spawnpoint 'a_m_y_skater_01' { x = 1658.31, y = -13.9234, z = 169.992 } +spawnpoint 'a_m_y_skater_02' { x = 2522.98, y = -384.436, z = 92.9928 } +spawnpoint 'a_m_y_skater_01' { x = 2826.27, y = -656.489, z = 1.87841 } +spawnpoint 'a_m_y_skater_02' { x = 2851.12, y = 1467.5, z = 24.5554 } +spawnpoint 'a_m_y_skater_01' { x = 2336.33, y = 2535.39, z = 46.5177 } +spawnpoint 'a_m_y_skater_02' { x = 2410.46, y = 3077.88, z = 48.1529 } +spawnpoint 'a_m_y_skater_01' { x = 2451.15, y = 3768.37, z = 41.3477 } +spawnpoint 'a_m_y_skater_02' { x = 3337.78, y = 5174.8, z = 18.2108 } +spawnpoint 'a_m_y_skater_01' { x = -1119.33, y = 4978.52, z = 186.26 } +spawnpoint 'a_m_y_skater_02' { x = 2877.3, y = 5911.57, z = 369.618 } +spawnpoint 'a_m_y_skater_01' { x = 2942.1, y = 5306.73, z = 101.52 } +spawnpoint 'a_m_y_skater_02' { x = 2211.29, y = 5577.94, z = 53.872 } +spawnpoint 'a_m_y_skater_01' { x = 1602.39, y = 6623.02, z = 15.8417 } +spawnpoint 'a_m_y_skater_02' { x = 66.0113, y = 7203.58, z = 3.16 } +spawnpoint 'a_m_y_skater_01' { x = -219.201, y = 6562.82, z = 10.9706 } +spawnpoint 'a_m_y_skater_02' { x = -45.1562, y = 6301.64, z = 31.6114 } +spawnpoint 'a_m_y_skater_01' { x = -1004.77, y = 4854.32, z = 274.606 } +spawnpoint 'a_m_y_skater_02' { x = -1580.01, y = 5173.3, z = 19.5813 } +spawnpoint 'a_m_y_skater_01' { x = -1467.95, y = 5416.2, z = 23.5959 } +spawnpoint 'a_m_y_skater_02' { x = -2359.31, y = 3243.83, z = 92.9037 } +spawnpoint 'a_m_y_skater_01' { x = -2612.96, y = 3555.03, z = 4.85649 } +spawnpoint 'a_m_y_skater_02' { x = -2083.27, y = 2616.94, z = 3.08396 } +spawnpoint 'a_m_y_skater_01' { x = -524.471, y = 4195, z = 193.731 } +spawnpoint 'a_m_y_skater_02' { x = -840.713, y = 4183.18, z = 215.29 } +spawnpoint 'a_m_y_skater_01' { x = -1576.24, y = 2103.87, z = 67.576 } +spawnpoint 'a_m_y_skater_02' { x = -1634.37, y = 209.816, z = 60.6413 } +spawnpoint 'a_m_y_skater_01' { x = -1495.07, y = 142.697, z = 55.6527 } +spawnpoint 'a_m_y_skater_02' { x = -1715.41, y = -197.722, z = 57.698 } +spawnpoint 'a_m_y_skater_01' { x = -1181.07, y = -505.544, z = 35.5661 } +spawnpoint 'a_m_y_skater_02' { x = -1712.37, y = -1082.91, z = 13.0801 } +spawnpoint 'a_m_y_skater_01' { x = -1352.43, y = -1542.75, z = 4.42268 } +spawnpoint 'a_m_y_skater_02' { x = -1756.89, y = 427.531, z = 127.685 } +spawnpoint 'a_m_y_skater_01' { x = 3060.2, y = 2113.2, z = 1.6613 } +spawnpoint 'a_m_y_skater_02' { x = 501.646, y = 5604.53, z = 797.91 } +spawnpoint 'a_m_y_skater_01' { x = 714.109, y = 4151.15, z = 35.7792 } +spawnpoint 'a_m_y_skater_02' { x = -103.651, y = -967.93, z = 296.52 } +spawnpoint 'a_m_y_skater_01' { x = -265.333, y = -2419.35, z = 122.366 } +spawnpoint 'a_m_y_skater_02' { x = 1788.25, y = 3890.34, z = 34.3849 } + +-- \ No newline at end of file diff --git a/resources/[cfx-default]/[gamemodes]/[maps]/redm-map-one/fxmanifest.lua b/resources/[cfx-default]/[gamemodes]/[maps]/redm-map-one/fxmanifest.lua new file mode 100644 index 0000000..a5b1f49 --- /dev/null +++ b/resources/[cfx-default]/[gamemodes]/[maps]/redm-map-one/fxmanifest.lua @@ -0,0 +1,16 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'Example spawn points for RedM.' +repository 'https://github.com/citizenfx/cfx-server-data' + +resource_type 'map' { gameTypes = { ['basic-gamemode'] = true } } + +map 'map.lua' + +fx_version 'adamant' +game 'rdr3' + +rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.' diff --git a/resources/[cfx-default]/[gamemodes]/[maps]/redm-map-one/map.lua b/resources/[cfx-default]/[gamemodes]/[maps]/redm-map-one/map.lua new file mode 100644 index 0000000..d010aed --- /dev/null +++ b/resources/[cfx-default]/[gamemodes]/[maps]/redm-map-one/map.lua @@ -0,0 +1,2 @@ +spawnpoint 'player_three' { x = -262.849, y = 793.404, z = 118.087 } +spawnpoint 'player_zero' { x = -262.849, y = 793.404, z = 118.087 } diff --git a/resources/[cfx-default]/[gamemodes]/basic-gamemode/basic_client.lua b/resources/[cfx-default]/[gamemodes]/basic-gamemode/basic_client.lua new file mode 100644 index 0000000..5631d48 --- /dev/null +++ b/resources/[cfx-default]/[gamemodes]/basic-gamemode/basic_client.lua @@ -0,0 +1,4 @@ +AddEventHandler('onClientMapStart', function() + exports.spawnmanager:setAutoSpawn(true) + exports.spawnmanager:forceRespawn() +end) diff --git a/resources/[cfx-default]/[gamemodes]/basic-gamemode/fxmanifest.lua b/resources/[cfx-default]/[gamemodes]/basic-gamemode/fxmanifest.lua new file mode 100644 index 0000000..74911e9 --- /dev/null +++ b/resources/[cfx-default]/[gamemodes]/basic-gamemode/fxmanifest.lua @@ -0,0 +1,14 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'A basic freeroam gametype that uses the default spawn logic from spawnmanager.' +repository 'https://github.com/citizenfx/cfx-server-data' + +resource_type 'gametype' { name = 'Freeroam' } + +client_script 'basic_client.lua' + +game 'common' +fx_version 'adamant' diff --git a/resources/[cfx-default]/[gameplay]/[examples]/money-fountain-example-map/fxmanifest.lua b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain-example-map/fxmanifest.lua new file mode 100644 index 0000000..a1365ca --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain-example-map/fxmanifest.lua @@ -0,0 +1,14 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +description 'An example money system fountain spawn point.' +repository 'https://github.com/citizenfx/cfx-server-data' +author 'Cfx.re ' + +fx_version 'cerulean' +game 'gta5' + +map 'map.lua' + +dependency 'money-fountain' diff --git a/resources/[cfx-default]/[gameplay]/[examples]/money-fountain-example-map/map.lua b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain-example-map/map.lua new file mode 100644 index 0000000..e7e1626 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain-example-map/map.lua @@ -0,0 +1,4 @@ +money_fountain 'test_fountain' { + vector3(97.334, -973.621, 29.36), + amount = 75 +} \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/client.lua b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/client.lua new file mode 100644 index 0000000..1cdc1f1 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/client.lua @@ -0,0 +1,101 @@ +-- add text entries for all the help types we have +AddTextEntry('FOUNTAIN_HELP', 'This fountain currently contains $~1~.~n~Press ~INPUT_PICKUP~ to obtain $~1~.~n~Press ~INPUT_DETONATE~ to place $~1~.') +AddTextEntry('FOUNTAIN_HELP_DRAINED', 'This fountain currently contains $~1~.~n~Press ~INPUT_DETONATE~ to place $~1~.') +AddTextEntry('FOUNTAIN_HELP_BROKE', 'This fountain currently contains $~1~.~n~Press ~INPUT_PICKUP~ to obtain $~1~.') +AddTextEntry('FOUNTAIN_HELP_BROKE_N_DRAINED', 'This fountain currently contains $~1~.') +AddTextEntry('FOUNTAIN_HELP_INUSE', 'This fountain currently contains $~1~.~n~You can use it again in ~a~.') + +-- upvalue aliases so that we will be fast if far away +local Wait = Wait +local GetEntityCoords = GetEntityCoords +local PlayerPedId = PlayerPedId + +-- timer, don't tick as frequently if we're far from any money fountain +local relevanceTimer = 500 + +CreateThread(function() + local pressing = false + + while true do + Wait(relevanceTimer) + + local coords = GetEntityCoords(PlayerPedId()) + + for _, data in pairs(moneyFountains) do + -- if we're near this fountain + local dist = #(coords - data.coords) + + -- near enough to draw + if dist < 40 then + -- ensure per-frame tick + relevanceTimer = 0 + + DrawMarker(29, data.coords.x, data.coords.y, data.coords.z, 0, 0, 0, 0.0, 0, 0, 1.0, 1.0, 1.0, 0, 150, 0, 120, false, true, 2, false, nil, nil, false) + else + -- put the relevance timer back to the way it was + relevanceTimer = 500 + end + + -- near enough to use + if dist < 1 then + -- are we able to use it? if not, display appropriate help + local player = LocalPlayer + local nextUse = player.state['fountain_nextUse'] + + -- GetNetworkTime is synced for everyone + if nextUse and nextUse >= GetNetworkTime() then + BeginTextCommandDisplayHelp('FOUNTAIN_HELP_INUSE') + AddTextComponentInteger(GlobalState['fountain_' .. data.id]) + AddTextComponentSubstringTime(math.tointeger(nextUse - GetNetworkTime()), 2 | 4) -- seconds (2), minutes (4) + EndTextCommandDisplayHelp(0, false, false, 1000) + else + -- handle inputs for pickup/place + if not pressing then + if IsControlPressed(0, 38 --[[ INPUT_PICKUP ]]) then + TriggerServerEvent('money_fountain:tryPickup', data.id) + pressing = true + elseif IsControlPressed(0, 47 --[[ INPUT_DETONATE ]]) then + TriggerServerEvent('money_fountain:tryPlace', data.id) + pressing = true + end + else + if not IsControlPressed(0, 38 --[[ INPUT_PICKUP ]]) and + not IsControlPressed(0, 47 --[[ INPUT_DETONATE ]]) then + pressing = false + end + end + + -- decide the appropriate help message + local youCanSpend = (player.state['money_cash'] or 0) >= data.amount + local fountainCanSpend = GlobalState['fountain_' .. data.id] >= data.amount + + local helpName + + if youCanSpend and fountainCanSpend then + helpName = 'FOUNTAIN_HELP' + elseif youCanSpend and not fountainCanSpend then + helpName = 'FOUNTAIN_HELP_DRAINED' + elseif not youCanSpend and fountainCanSpend then + helpName = 'FOUNTAIN_HELP_BROKE' + else + helpName = 'FOUNTAIN_HELP_BROKE_N_DRAINED' + end + + -- and print it + BeginTextCommandDisplayHelp(helpName) + AddTextComponentInteger(GlobalState['fountain_' .. data.id]) + + if fountainCanSpend then + AddTextComponentInteger(data.amount) + end + + if youCanSpend then + AddTextComponentInteger(data.amount) + end + + EndTextCommandDisplayHelp(0, false, false, 1000) + end + end + end + end +end) \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/fxmanifest.lua b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/fxmanifest.lua new file mode 100644 index 0000000..0218c4d --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/fxmanifest.lua @@ -0,0 +1,22 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +description 'An example money system client containing a money fountain.' +repository 'https://github.com/citizenfx/cfx-server-data' +author 'Cfx.re ' + +fx_version 'bodacious' +game 'gta5' + +client_script 'client.lua' +server_script 'server.lua' + +shared_script 'mapdata.lua' + +dependencies { + 'mapmanager', + 'money' +} + +lua54 'yes' diff --git a/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/mapdata.lua b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/mapdata.lua new file mode 100644 index 0000000..4eecad8 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/mapdata.lua @@ -0,0 +1,28 @@ +-- define the money fountain list (SHARED SCRIPT) +moneyFountains = {} + +-- index to know what to remove +local fountainIdx = 1 + +AddEventHandler('getMapDirectives', function(add) + -- add a 'money_fountain' map directive + add('money_fountain', function(state, name) + return function(data) + local coords = data[1] + local amount = data.amount or 100 + + local idx = fountainIdx + fountainIdx += 1 + + moneyFountains[idx] = { + id = name, + coords = coords, + amount = amount + } + + state.add('idx', idx) + end + end, function(state) + moneyFountains[state.idx] = nil + end) +end) \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/server.lua b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/server.lua new file mode 100644 index 0000000..9b1e238 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/money-fountain/server.lua @@ -0,0 +1,107 @@ +-- track down what we've added to global state +local sentState = {} + +-- money system +local ms = exports['money'] + +-- get the fountain content from storage +local function getMoneyForId(fountainId) + return GetResourceKvpInt(('money:%s'):format(fountainId)) / 100.0 +end + +-- set the fountain content in storage + state +local function setMoneyForId(fountainId, money) + GlobalState['fountain_' .. fountainId] = math.tointeger(money) + + return SetResourceKvpInt(('money:%s'):format(fountainId), math.tointeger(money * 100.0)) +end + +-- get the nearest fountain to the player + ID +local function getMoneyFountain(id, source) + local coords = GetEntityCoords(GetPlayerPed(source)) + + for _, v in pairs(moneyFountains) do + if v.id == id then + if #(v.coords - coords) < 2.5 then + return v + end + end + end + + return nil +end + +-- generic function for events +local function handleFountainStuff(source, id, pickup) + -- if near the fountain we specify + local fountain = getMoneyFountain(id, source) + + if fountain then + -- and we can actually use the fountain already + local player = Player(source) + + local nextUse = player.state['fountain_nextUse'] + if not nextUse then + nextUse = 0 + end + + -- GetGameTimer ~ GetNetworkTime on client + if nextUse <= GetGameTimer() then + -- not rate limited + local success = false + local money = getMoneyForId(fountain.id) + + -- decide the op + if pickup then + -- if the fountain is rich enough to get the per-use amount + if money >= fountain.amount then + -- give the player money + if ms:addMoney(source, 'cash', fountain.amount) then + money -= fountain.amount + success = true + end + end + else + -- if the player is rich enough + if ms:removeMoney(source, 'cash', fountain.amount) then + -- add to the fountain + money += fountain.amount + success = true + end + end + + -- save it and set the player's cooldown + if success then + setMoneyForId(fountain.id, money) + player.state['fountain_nextUse'] = GetGameTimer() + GetConvarInt('moneyFountain_cooldown', 5000) + end + end + end +end + +-- event for picking up fountain->player +RegisterNetEvent('money_fountain:tryPickup') +AddEventHandler('money_fountain:tryPickup', function(id) + handleFountainStuff(source, id, true) +end) + +-- event for donating player->fountain +RegisterNetEvent('money_fountain:tryPlace') +AddEventHandler('money_fountain:tryPlace', function(id) + handleFountainStuff(source, id, false) +end) + +-- listener: if a new fountain is added, set its current money in state +CreateThread(function() + while true do + Wait(500) + + for _, fountain in pairs(moneyFountains) do + if not sentState[fountain.id] then + GlobalState['fountain_' .. fountain.id] = math.tointeger(getMoneyForId(fountain.id)) + + sentState[fountain.id] = true + end + end + end +end) \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/[examples]/money/client.lua b/resources/[cfx-default]/[gameplay]/[examples]/money/client.lua new file mode 100644 index 0000000..e094dd1 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/money/client.lua @@ -0,0 +1,30 @@ +local moneyTypes = { + cash = `MP0_WALLET_BALANCE`, + bank = `BANK_BALANCE`, +} + +RegisterNetEvent('money:displayUpdate') + +AddEventHandler('money:displayUpdate', function(type, money) + local stat = moneyTypes[type] + if not stat then return end + StatSetInt(stat, math.floor(money)) +end) + +TriggerServerEvent('money:requestDisplay') + +CreateThread(function() + while true do + Wait(0) + + if IsControlJustPressed(0, 20) then + SetMultiplayerBankCash() + SetMultiplayerWalletCash() + + Wait(4350) + + RemoveMultiplayerBankCash() + RemoveMultiplayerWalletCash() + end + end +end) \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/[examples]/money/fxmanifest.lua b/resources/[cfx-default]/[gameplay]/[examples]/money/fxmanifest.lua new file mode 100644 index 0000000..7abd12c --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/money/fxmanifest.lua @@ -0,0 +1,16 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +description 'An example money system using KVS.' +repository 'https://github.com/citizenfx/cfx-server-data' +author 'Cfx.re ' + +fx_version 'bodacious' +game 'gta5' + +client_script 'client.lua' +server_script 'server.lua' + +--dependency 'cfx.re/playerData.v1alpha1' +lua54 'yes' diff --git a/resources/[cfx-default]/[gameplay]/[examples]/money/server.lua b/resources/[cfx-default]/[gameplay]/[examples]/money/server.lua new file mode 100644 index 0000000..2b2ce96 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/money/server.lua @@ -0,0 +1,119 @@ +local playerData = exports['cfx.re/playerData.v1alpha1'] + +local validMoneyTypes = { + bank = true, + cash = true, +} + +local function getMoneyForId(playerId, moneyType) + return GetResourceKvpInt(('money:%s:%s'):format(playerId, moneyType)) / 100.0 +end + +local function setMoneyForId(playerId, moneyType, money) + local s = playerData:getPlayerById(playerId) + + TriggerEvent('money:updated', { + dbId = playerId, + source = s, + moneyType = moneyType, + money = money + }) + + return SetResourceKvpInt(('money:%s:%s'):format(playerId, moneyType), math.tointeger(money * 100.0)) +end + +local function addMoneyForId(playerId, moneyType, amount) + local curMoney = getMoneyForId(playerId, moneyType) + curMoney += amount + + if curMoney >= 0 then + setMoneyForId(playerId, moneyType, curMoney) + return true, curMoney + end + + return false, 0 +end + +exports('addMoney', function(playerIdx, moneyType, amount) + amount = tonumber(amount) + + if amount <= 0 or amount > (1 << 30) then + return false + end + + if not validMoneyTypes[moneyType] then + return false + end + + local playerId = playerData:getPlayerId(playerIdx) + local success, money = addMoneyForId(playerId, moneyType, amount) + + if success then + Player(playerIdx).state['money_' .. moneyType] = money + end + + return true +end) + +exports('removeMoney', function(playerIdx, moneyType, amount) + amount = tonumber(amount) + + if amount <= 0 or amount > (1 << 30) then + return false + end + + if not validMoneyTypes[moneyType] then + return false + end + + local playerId = playerData:getPlayerId(playerIdx) + local success, money = addMoneyForId(playerId, moneyType, -amount) + + if success then + Player(playerIdx).state['money_' .. moneyType] = money + end + + return success +end) + +exports('getMoney', function(playerIdx, moneyType) + local playerId = playerData:getPlayerId(playerIdx) + return getMoneyForId(playerId, moneyType) +end) + +-- player display bits +AddEventHandler('money:updated', function(data) + if data.source then + TriggerClientEvent('money:displayUpdate', data.source, data.moneyType, data.money) + end +end) + +RegisterNetEvent('money:requestDisplay') + +AddEventHandler('money:requestDisplay', function() + local source = source + local playerId = playerData:getPlayerId(source) + + for type, _ in pairs(validMoneyTypes) do + local amount = getMoneyForId(playerId, type) + TriggerClientEvent('money:displayUpdate', source, type, amount) + + Player(source).state['money_' .. type] = amount + end +end) + +RegisterCommand('earn', function(source, args) + local type = args[1] + local amount = tonumber(args[2]) + + exports['money']:addMoney(source, type, amount) +end, true) + +RegisterCommand('spend', function(source, args) + local type = args[1] + local amount = tonumber(args[2]) + + if not exports['money']:removeMoney(source, type, amount) then + print('you are broke??') + end +end, true) \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/[examples]/ped-money-drops/client.lua b/resources/[cfx-default]/[gameplay]/[examples]/ped-money-drops/client.lua new file mode 100644 index 0000000..d6d000c --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/ped-money-drops/client.lua @@ -0,0 +1,41 @@ +AddEventHandler('gameEventTriggered', function(eventName, args) + if eventName == 'CEventNetworkEntityDamage' then + local victim = args[1] + local culprit = args[2] + local isDead = args[4] == 1 + + if isDead then + local origCoords = GetEntityCoords(victim) + local pickup = CreatePickupRotate(`PICKUP_MONEY_VARIABLE`, origCoords.x, origCoords.y, origCoords.z - 0.7, 0.0, 0.0, 0.0, 512, 0, false, 0) + local netId = PedToNet(victim) + + local undoStuff = { false } + + CreateThread(function() + local self = PlayerPedId() + + while not undoStuff[1] do + Wait(50) + + if #(GetEntityCoords(self) - origCoords) < 2.5 and HasPickupBeenCollected(pickup) then + TriggerServerEvent('money:tryPickup', netId) + + RemovePickup(pickup) + break + end + end + + undoStuff[1] = true + end) + + SetTimeout(15000, function() + if not undoStuff[1] then + RemovePickup(pickup) + undoStuff[1] = true + end + end) + + TriggerServerEvent('money:allowPickupNear', netId) + end + end +end) \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/[examples]/ped-money-drops/fxmanifest.lua b/resources/[cfx-default]/[gameplay]/[examples]/ped-money-drops/fxmanifest.lua new file mode 100644 index 0000000..1e6b7b2 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/ped-money-drops/fxmanifest.lua @@ -0,0 +1,15 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +description 'An example money system client.' +author 'Cfx.re ' +repository 'https://github.com/citizenfx/cfx-server-data' + +fx_version 'bodacious' +game 'gta5' + +client_script 'client.lua' +server_script 'server.lua' + +lua54 'yes' diff --git a/resources/[cfx-default]/[gameplay]/[examples]/ped-money-drops/server.lua b/resources/[cfx-default]/[gameplay]/[examples]/ped-money-drops/server.lua new file mode 100644 index 0000000..6876952 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/[examples]/ped-money-drops/server.lua @@ -0,0 +1,42 @@ +local safePositions = {} + +RegisterNetEvent('money:allowPickupNear') + +AddEventHandler('money:allowPickupNear', function(pedId) + local entity = NetworkGetEntityFromNetworkId(pedId) + + Wait(250) + + if not DoesEntityExist(entity) then + return + end + + if GetEntityHealth(entity) > 100 then + return + end + + local coords = GetEntityCoords(entity) + safePositions[pedId] = coords +end) + +RegisterNetEvent('money:tryPickup') + +AddEventHandler('money:tryPickup', function(entity) + if not safePositions[entity] then + return + end + + local source = source + local playerPed = GetPlayerPed(source) + local coords = GetEntityCoords(playerPed) + + if #(safePositions[entity] - coords) < 2.5 then + exports['money']:addMoney(source, 'cash', 40) + end + + safePositions[entity] = nil +end) + +AddEventHandler('entityRemoved', function(entity) + safePositions[entity] = nil +end) \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/chat-theme-gtao/fxmanifest.lua b/resources/[cfx-default]/[gameplay]/chat-theme-gtao/fxmanifest.lua new file mode 100644 index 0000000..08bdf27 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/chat-theme-gtao/fxmanifest.lua @@ -0,0 +1,21 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'A GTA Online-styled theme for the chat resource.' +repository 'https://github.com/citizenfx/cfx-server-data' + +file 'style.css' +file 'shadow.js' + +chat_theme 'gtao' { + styleSheet = 'style.css', + script = 'shadow.js', + msgTemplates = { + default = '{0}{1}' + } +} + +game 'common' +fx_version 'adamant' diff --git a/resources/[cfx-default]/[gameplay]/chat-theme-gtao/shadow.js b/resources/[cfx-default]/[gameplay]/chat-theme-gtao/shadow.js new file mode 100644 index 0000000..55d3176 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/chat-theme-gtao/shadow.js @@ -0,0 +1,74 @@ +(function() { +var Filters = {} + +var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); +svg.setAttribute("style", "display:block;width:0px;height:0px"); +var defs = document.createElementNS("http://www.w3.org/2000/svg", "defs"); + +var blurFilter = document.createElementNS("http://www.w3.org/2000/svg", "filter"); +blurFilter.setAttribute("id", "svgBlurFilter"); +var feGaussianFilter = document.createElementNS("http://www.w3.org/2000/svg", "feGaussianBlur"); +feGaussianFilter.setAttribute("stdDeviation", "0 0"); +blurFilter.appendChild(feGaussianFilter); +defs.appendChild(blurFilter); +Filters._svgBlurFilter = feGaussianFilter; + +// Drop Shadow Filter +var dropShadowFilter = document.createElementNS("http://www.w3.org/2000/svg", "filter"); +dropShadowFilter.setAttribute("id", "svgDropShadowFilter"); +var feGaussianFilter = document.createElementNS("http://www.w3.org/2000/svg", "feGaussianBlur"); +feGaussianFilter.setAttribute("in", "SourceAlpha"); +feGaussianFilter.setAttribute("stdDeviation", "3"); +dropShadowFilter.appendChild(feGaussianFilter); +Filters._svgDropshadowFilterBlur = feGaussianFilter; + +var feOffset = document.createElementNS("http://www.w3.org/2000/svg", "feOffset"); +feOffset.setAttribute("dx", "0"); +feOffset.setAttribute("dy", "0"); +feOffset.setAttribute("result", "offsetblur"); +dropShadowFilter.appendChild(feOffset); +Filters._svgDropshadowFilterOffset = feOffset; + +var feFlood = document.createElementNS("http://www.w3.org/2000/svg", "feFlood"); +feFlood.setAttribute("flood-color", "rgba(0,0,0,1)"); +dropShadowFilter.appendChild(feFlood); +Filters._svgDropshadowFilterFlood = feFlood; + +var feComposite = document.createElementNS("http://www.w3.org/2000/svg", "feComposite"); +feComposite.setAttribute("in2", "offsetblur"); +feComposite.setAttribute("operator", "in"); +dropShadowFilter.appendChild(feComposite); +var feComposite = document.createElementNS("http://www.w3.org/2000/svg", "feComposite"); +feComposite.setAttribute("in2", "SourceAlpha"); +feComposite.setAttribute("operator", "out"); +feComposite.setAttribute("result", "outer"); +dropShadowFilter.appendChild(feComposite); + +var feMerge = document.createElementNS("http://www.w3.org/2000/svg", "feMerge"); +var feMergeNode = document.createElementNS("http://www.w3.org/2000/svg", "feMergeNode"); +feMerge.appendChild(feMergeNode); +var feMergeNode = document.createElementNS("http://www.w3.org/2000/svg", "feMergeNode"); +feMerge.appendChild(feMergeNode); +Filters._svgDropshadowMergeNode = feMergeNode; +dropShadowFilter.appendChild(feMerge); +defs.appendChild(dropShadowFilter); +svg.appendChild(defs); +document.documentElement.appendChild(svg); + +const blurScale = 1; +const scale = (document.body.clientWidth / 1280); + +Filters._svgDropshadowFilterBlur.setAttribute("stdDeviation", + 1 * blurScale + " " + + 1 * blurScale +); +Filters._svgDropshadowFilterOffset.setAttribute("dx", + String(Math.cos(45 * Math.PI / 180) * 1 * scale)); +Filters._svgDropshadowFilterOffset.setAttribute("dy", + String(Math.sin(45 * Math.PI / 180) * 1 * scale)); +Filters._svgDropshadowFilterFlood.setAttribute("flood-color", + 'rgba(0, 0, 0, 1)'); +Filters._svgDropshadowMergeNode.setAttribute("in", + "SourceGraphic"); + +})(); \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/chat-theme-gtao/style.css b/resources/[cfx-default]/[gameplay]/chat-theme-gtao/style.css new file mode 100644 index 0000000..5e28f97 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/chat-theme-gtao/style.css @@ -0,0 +1,141 @@ +* { + font-family: inherit; +} + +.chat-window { + --size: calc(((2.7vh * 1.2)) * 6); + + position: absolute; + right: calc(2.77vh); + top: calc(50% - (var(--size) / 2)); + height: var(--size) !important; + + background: inherit !important; + + text-align: right; + + left: auto; + + user-select: none; +} + +@font-face { + font-family: 'Font2'; + src: url(https://runtime.fivem.net/temp/ChaletLondonNineteenSixty.otf?a); +} + +@font-face { + font-family: 'Font2_cond'; + src: url(https://runtime.fivem.net/temp/chaletcomprime-colognesixty-webfont.ttf?a); +} + +.msg { + font-family: Font2, sans-serif; + color: #fff; + + font-size: calc(1.8vh); /* 13px in 720p, calc'd by width */ + filter: url(#svgDropShadowFilter); + + line-height: calc(2.7vh * 1.2); + + margin-bottom: 0; +} + +.chat-messages { + margin: 0; + height: 100%; +} + +.msg > span > span > b { + font-family: Font2_cond, sans-serif; + font-weight: normal; + + vertical-align: baseline; + padding-right: 11px; + + line-height: 1; + + font-size: calc(2.7vh); +} + +.msg > span > span > span { + vertical-align: baseline; +} + +.msg i:first-of-type { + font-style: normal; + color: #c0c0c0; +} + +.chat-input { + position: absolute; + right: calc(2.77vh); + bottom: calc(2.77vh); + + background: inherit !important; + + text-align: right; + + top: auto; + left: auto; + + height: auto; + + font-family: Font2, sans-serif; +} + +.chat-input > div { + background-color: rgba(0, 0, 0, .6) !important; + border: calc(0.28vh / 2) solid rgba(180, 180, 180, .6); + outline: calc(0.28vh / 2) solid rgba(0, 0, 0, .8); /* to replace margin-background */ + padding: calc(0.28vh / 2); +} + +.chat-input .prefix { + margin: 0; + margin-left: 0.7%; + margin-top: -0.1%; + line-height: 2.8vh; +} + +.chat-input .prefix.any { + opacity: 0.8; +} + +.chat-input .prefix.any:before { + content: '['; +} + +.chat-input .prefix.any:after { + content: ']'; +} + +.chat-input > div + div { + position: absolute; + bottom: calc(1.65vh + 0.28vh + 0.28vh + 0.28vh + (0.28vh / 2)); + width: 99.6%; + + text-align: left; +} + +.suggestions { + border: calc(0.28vh / 2) solid rgba(180, 180, 180, .6); + background: transparent; +} + +textarea { + background: transparent; + padding: 0.5vh; +} + +@media screen and (min-aspect-ratio: 21/9) { + .chat-window, .chat-input { + right: calc(12.8vw); + } +} + +@media screen and (min-aspect-ratio: 32/9) { + .chat-window, .chat-input { + right: calc(25vw); + } +} diff --git a/resources/[cfx-default]/[gameplay]/player-data/fxmanifest.lua b/resources/[cfx-default]/[gameplay]/player-data/fxmanifest.lua new file mode 100644 index 0000000..1188255 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/player-data/fxmanifest.lua @@ -0,0 +1,16 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +description 'A basic resource for storing player identifiers.' +author 'Cfx.re ' +repository 'https://github.com/citizenfx/cfx-server-data' + +fx_version 'bodacious' +game 'common' + +server_script 'server.lua' + +provides { + 'cfx.re/playerData.v1alpha1' +} diff --git a/resources/[cfx-default]/[gameplay]/player-data/server.lua b/resources/[cfx-default]/[gameplay]/player-data/server.lua new file mode 100644 index 0000000..a262281 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/player-data/server.lua @@ -0,0 +1,222 @@ +--- player-data is a basic resource to showcase player identifier storage +-- +-- it works in a fairly simple way: a set of identifiers is assigned to an account ID, and said +-- account ID is then returned/added as state bag +-- +-- it also implements the `cfx.re/playerData.v1alpha1` spec, which is exposed through the following: +-- - getPlayerId(source: string) +-- - getPlayerById(dbId: string) +-- - getPlayerIdFromIdentifier(identifier: string) +-- - setting `cfx.re/playerData@id` state bag field on the player + +-- identifiers that we'll ignore (e.g. IP) as they're low-trust/high-variance +local identifierBlocklist = { + ip = true +} + +-- function to check if the identifier is blocked +local function isIdentifierBlocked(identifier) + -- Lua pattern to correctly split + local idType = identifier:match('([^:]+):') + + -- ensure it's a boolean + return identifierBlocklist[idType] or false +end + +-- our database schema, in hierarchical KVS syntax: +-- player: +-- : +-- identifier: +-- : 'true' +-- identifier: +-- : + +-- list of player indices to data +local players = {} + +-- list of player DBIDs to player indices +local playersById = {} + +-- a sequence field using KVS +local function incrementId() + local nextId = GetResourceKvpInt('nextId') + nextId = nextId + 1 + SetResourceKvpInt('nextId', nextId) + + return nextId +end + +-- gets the ID tied to an identifier in the schema, or nil +local function getPlayerIdFromIdentifier(identifier) + local str = GetResourceKvpString(('identifier:%s'):format(identifier)) + + if not str then + return nil + end + + return msgpack.unpack(str).id +end + +-- stores the identifier + adds to a logging list +local function setPlayerIdFromIdentifier(identifier, id) + local str = ('identifier:%s'):format(identifier) + SetResourceKvp(str, msgpack.pack({ id = id })) + SetResourceKvp(('player:%s:identifier:%s'):format(id, identifier), 'true') +end + +-- stores any new identifiers for this player ID +local function storeIdentifiers(playerIdx, newId) + for _, identifier in ipairs(GetPlayerIdentifiers(playerIdx)) do + if not isIdentifierBlocked(identifier) then + -- TODO: check if the player already has an identifier of this type + setPlayerIdFromIdentifier(identifier, newId) + end + end +end + +-- registers a new player (increments sequence, stores data, returns ID) +local function registerPlayer(playerIdx) + local newId = incrementId() + storeIdentifiers(playerIdx, newId) + + return newId +end + +-- initializes a player's data set +local function setupPlayer(playerIdx) + -- try getting the oldest-known identity from all the player's identifiers + local defaultId = 0xFFFFFFFFFF + local lowestId = defaultId + + for _, identifier in ipairs(GetPlayerIdentifiers(playerIdx)) do + if not isIdentifierBlocked(identifier) then + local dbId = getPlayerIdFromIdentifier(identifier) + + if dbId then + if dbId < lowestId then + lowestId = dbId + end + end + end + end + + -- if this is the default ID, register. if not, update + local playerId + + if lowestId == defaultId then + playerId = registerPlayer(playerIdx) + else + storeIdentifiers(playerIdx, lowestId) + playerId = lowestId + end + + -- add state bag field + if Player then + Player(playerIdx).state['cfx.re/playerData@id'] = playerId + end + + -- and add to our caching tables + players[playerIdx] = { + dbId = playerId + } + + playersById[tostring(playerId)] = playerIdx +end + +-- we want to add a player pretty early +AddEventHandler('playerConnecting', function() + local playerIdx = tostring(source) + setupPlayer(playerIdx) +end) + +-- and migrate them to a 'joining' ID where possible +RegisterNetEvent('playerJoining') + +AddEventHandler('playerJoining', function(oldIdx) + -- resource restart race condition + local oldPlayer = players[tostring(oldIdx)] + + if oldPlayer then + players[tostring(source)] = oldPlayer + players[tostring(oldIdx)] = nil + else + setupPlayer(tostring(source)) + end +end) + +-- remove them if they're dropped +AddEventHandler('playerDropped', function() + local player = players[tostring(source)] + + if player then + playersById[tostring(player.dbId)] = nil + end + + players[tostring(source)] = nil +end) + +-- and when the resource is restarted, set up all players that are on right now +for _, player in ipairs(GetPlayers()) do + setupPlayer(player) +end + +-- also a quick command to get the current state +RegisterCommand('playerData', function(source, args) + if not args[1] then + print('Usage:') + print('\tplayerData getId : gets identifiers for ID') + print('\tplayerData getIdentifier : gets ID for identifier') + + return + end + + if args[1] == 'getId' then + local prefix = ('player:%s:identifier:'):format(args[2]) + local handle = StartFindKvp(prefix) + local key + + repeat + key = FindKvp(handle) + + if key then + print('result:', key:sub(#prefix + 1)) + end + until not key + + EndFindKvp(handle) + elseif args[1] == 'getIdentifier' then + print('result:', getPlayerIdFromIdentifier(args[2])) + end +end, true) + +-- COMPATIBILITY for server versions that don't export provide +local function getExportEventName(resource, name) + return string.format('__cfx_export_%s_%s', resource, name) +end + +function AddExport(name, fn) + if not Citizen.Traits or not Citizen.Traits.ProvidesExports then + AddEventHandler(getExportEventName('cfx.re/playerData.v1alpha1', name), function(setCB) + setCB(fn) + end) + end + + exports(name, fn) +end + +-- exports +AddExport('getPlayerIdFromIdentifier', getPlayerIdFromIdentifier) + +AddExport('getPlayerId', function(playerIdx) + local player = players[tostring(playerIdx)] + + if not player then + return nil + end + + return player.dbId +end) + +AddExport('getPlayerById', function(playerId) + return playersById[tostring(playerId)] +end) \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/playernames/fxmanifest.lua b/resources/[cfx-default]/[gameplay]/playernames/fxmanifest.lua new file mode 100644 index 0000000..547afc1 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/playernames/fxmanifest.lua @@ -0,0 +1,36 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'A basic resource for displaying player names.' +repository 'https://github.com/citizenfx/cfx-server-data' + +-- add scripts +client_script 'playernames_api.lua' +server_script 'playernames_api.lua' + +client_script 'playernames_cl.lua' +server_script 'playernames_sv.lua' + +-- make exports +local exportList = { + 'setComponentColor', + 'setComponentAlpha', + 'setComponentVisibility', + 'setWantedLevel', + 'setHealthBarColor', + 'setNameTemplate' +} + +exports(exportList) +server_exports(exportList) + +-- add files +files { + 'template/template.lua' +} + +-- support the latest resource manifest +fx_version 'adamant' +game 'gta5' diff --git a/resources/[cfx-default]/[gameplay]/playernames/playernames_api.lua b/resources/[cfx-default]/[gameplay]/playernames/playernames_api.lua new file mode 100644 index 0000000..e592946 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/playernames/playernames_api.lua @@ -0,0 +1,80 @@ +local ids = {} + +local function getTriggerFunction(key) + return function(id, ...) + -- if on the client, it's easy + if not IsDuplicityVersion() then + TriggerEvent('playernames:configure', GetPlayerServerId(id), key, ...) + else + -- if on the server, save configuration + if not ids[id] then + ids[id] = {} + end + + -- save the setting + ids[id][key] = table.pack(...) + + -- broadcast to clients + TriggerClientEvent('playernames:configure', -1, id, key, ...) + end + end +end + +if IsDuplicityVersion() then + function reconfigure(source) + for id, data in pairs(ids) do + for key, args in pairs(data) do + TriggerClientEvent('playernames:configure', source, id, key, table.unpack(args)) + end + end + end + + AddEventHandler('playerDropped', function() + ids[source] = nil + end) +end + +setComponentColor = getTriggerFunction('setc') +setComponentAlpha = getTriggerFunction('seta') +setComponentVisibility = getTriggerFunction('tglc') +setWantedLevel = getTriggerFunction('setw') +setHealthBarColor = getTriggerFunction('sehc') +setNameTemplate = getTriggerFunction('tpl') +setName = getTriggerFunction('name') + +if not io then + io = { write = nil, open = nil } +end + +local template = load(LoadResourceFile(GetCurrentResourceName(), 'template/template.lua'))() + +function formatPlayerNameTag(i, templateStr) + --return ('%s <%d>'):format(GetPlayerName(i), GetPlayerServerId(i)) + local str = '' + + template.print = function(txt) + str = str .. txt + end + + local context = { + name = GetPlayerName(i), + i = i, + global = _G + } + + if IsDuplicityVersion() then + context.id = i + else + context.id = GetPlayerServerId(i) + end + + TriggerEvent('playernames:extendContext', i, function(k, v) + context[k] = v + end) + + template.render(templateStr, context, nil, true) + + template.print = print + + return str +end \ No newline at end of file diff --git a/resources/[cfx-default]/[gameplay]/playernames/playernames_cl.lua b/resources/[cfx-default]/[gameplay]/playernames/playernames_cl.lua new file mode 100644 index 0000000..b39737a --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/playernames/playernames_cl.lua @@ -0,0 +1,191 @@ +local mpGamerTags = {} +local mpGamerTagSettings = {} + +local gtComponent = { + GAMER_NAME = 0, + CREW_TAG = 1, + healthArmour = 2, + BIG_TEXT = 3, + AUDIO_ICON = 4, + MP_USING_MENU = 5, + MP_PASSIVE_MODE = 6, + WANTED_STARS = 7, + MP_DRIVER = 8, + MP_CO_DRIVER = 9, + MP_TAGGED = 10, + GAMER_NAME_NEARBY = 11, + ARROW = 12, + MP_PACKAGES = 13, + INV_IF_PED_FOLLOWING = 14, + RANK_TEXT = 15, + MP_TYPING = 16 +} + +local function makeSettings() + return { + alphas = {}, + colors = {}, + healthColor = false, + toggles = {}, + wantedLevel = false + } +end + +local templateStr + +function updatePlayerNames() + -- re-run this function the next frame + SetTimeout(0, updatePlayerNames) + + -- return if no template string is set + if not templateStr then + return + end + + -- get local coordinates to compare to + local localCoords = GetEntityCoords(PlayerPedId()) + + -- for each valid player index + for _, i in ipairs(GetActivePlayers()) do + -- if the player exists + if i ~= PlayerId() then + -- get their ped + local ped = GetPlayerPed(i) + local pedCoords = GetEntityCoords(ped) + + -- make a new settings list if needed + if not mpGamerTagSettings[i] then + mpGamerTagSettings[i] = makeSettings() + end + + -- check the ped, because changing player models may recreate the ped + -- also check gamer tag activity in case the game deleted the gamer tag + if not mpGamerTags[i] or mpGamerTags[i].ped ~= ped or not IsMpGamerTagActive(mpGamerTags[i].tag) then + local nameTag = formatPlayerNameTag(i, templateStr) + + -- remove any existing tag + if mpGamerTags[i] then + RemoveMpGamerTag(mpGamerTags[i].tag) + end + + -- store the new tag + mpGamerTags[i] = { + tag = CreateMpGamerTag(GetPlayerPed(i), nameTag, false, false, '', 0), + ped = ped + } + end + + -- store the tag in a local + local tag = mpGamerTags[i].tag + + -- should the player be renamed? this is set by events + if mpGamerTagSettings[i].rename then + SetMpGamerTagName(tag, formatPlayerNameTag(i, templateStr)) + mpGamerTagSettings[i].rename = nil + end + + -- check distance + local distance = #(pedCoords - localCoords) + + -- show/hide based on nearbyness/line-of-sight + -- nearby checks are primarily to prevent a lot of LOS checks + if distance < 250 and HasEntityClearLosToEntity(PlayerPedId(), ped, 17) then + SetMpGamerTagVisibility(tag, gtComponent.GAMER_NAME, true) + SetMpGamerTagVisibility(tag, gtComponent.healthArmour, IsPlayerTargettingEntity(PlayerId(), ped)) + SetMpGamerTagVisibility(tag, gtComponent.AUDIO_ICON, NetworkIsPlayerTalking(i)) + + SetMpGamerTagAlpha(tag, gtComponent.AUDIO_ICON, 255) + SetMpGamerTagAlpha(tag, gtComponent.healthArmour, 255) + + -- override settings + local settings = mpGamerTagSettings[i] + + for k, v in pairs(settings.toggles) do + SetMpGamerTagVisibility(tag, gtComponent[k], v) + end + + for k, v in pairs(settings.alphas) do + SetMpGamerTagAlpha(tag, gtComponent[k], v) + end + + for k, v in pairs(settings.colors) do + SetMpGamerTagColour(tag, gtComponent[k], v) + end + + if settings.wantedLevel then + SetMpGamerTagWantedLevel(tag, settings.wantedLevel) + end + + if settings.healthColor then + SetMpGamerTagHealthBarColour(tag, settings.healthColor) + end + else + SetMpGamerTagVisibility(tag, gtComponent.GAMER_NAME, false) + SetMpGamerTagVisibility(tag, gtComponent.healthArmour, false) + SetMpGamerTagVisibility(tag, gtComponent.AUDIO_ICON, false) + end + elseif mpGamerTags[i] then + RemoveMpGamerTag(mpGamerTags[i].tag) + + mpGamerTags[i] = nil + end + end +end + +local function getSettings(id) + local i = GetPlayerFromServerId(tonumber(id)) + + if not mpGamerTagSettings[i] then + mpGamerTagSettings[i] = makeSettings() + end + + return mpGamerTagSettings[i] +end + +RegisterNetEvent('playernames:configure') + +AddEventHandler('playernames:configure', function(id, key, ...) + local args = table.pack(...) + + if key == 'tglc' then + getSettings(id).toggles[args[1]] = args[2] + elseif key == 'seta' then + getSettings(id).alphas[args[1]] = args[2] + elseif key == 'setc' then + getSettings(id).colors[args[1]] = args[2] + elseif key == 'setw' then + getSettings(id).wantedLevel = args[1] + elseif key == 'sehc' then + getSettings(id).healthColor = args[1] + elseif key == 'rnme' then + getSettings(id).rename = true + elseif key == 'name' then + getSettings(id).serverName = args[1] + getSettings(id).rename = true + elseif key == 'tpl' then + for _, v in pairs(mpGamerTagSettings) do + v.rename = true + end + + templateStr = args[1] + end +end) + +AddEventHandler('playernames:extendContext', function(i, cb) + cb('serverName', getSettings(GetPlayerServerId(i)).serverName) +end) + +AddEventHandler('onResourceStop', function(name) + if name == GetCurrentResourceName() then + for _, v in pairs(mpGamerTags) do + RemoveMpGamerTag(v.tag) + end + end +end) + +SetTimeout(0, function() + TriggerServerEvent('playernames:init') +end) + +-- run this function every frame +SetTimeout(0, updatePlayerNames) diff --git a/resources/[cfx-default]/[gameplay]/playernames/playernames_sv.lua b/resources/[cfx-default]/[gameplay]/playernames/playernames_sv.lua new file mode 100644 index 0000000..4677e39 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/playernames/playernames_sv.lua @@ -0,0 +1,46 @@ +local curTemplate +local curTags = {} + +local activePlayers = {} + +local function detectUpdates() + SetTimeout(500, detectUpdates) + + local template = GetConvar('playerNames_template', '[{{id}}] {{name}}') + + if curTemplate ~= template then + setNameTemplate(-1, template) + + curTemplate = template + end + + template = GetConvar('playerNames_svTemplate', '[{{id}}] {{name}}') + + for v, _ in pairs(activePlayers) do + local newTag = formatPlayerNameTag(v, template) + if newTag ~= curTags[v] then + setName(v, newTag) + + curTags[v] = newTag + end + end + + for i, tag in pairs(curTags) do + if not activePlayers[i] then + curTags[i] = nil -- in case curTags doesnt get cleared when the player left, clear it now. + end + end +end + +AddEventHandler('playerDropped', function() + curTags[source] = nil + activePlayers[source] = nil +end) + +RegisterNetEvent('playernames:init') +AddEventHandler('playernames:init', function() + reconfigure(source) + activePlayers[source] = true +end) + +detectUpdates() diff --git a/resources/[cfx-default]/[gameplay]/playernames/template/LICENSE b/resources/[cfx-default]/[gameplay]/playernames/template/LICENSE new file mode 100644 index 0000000..f0e57b1 --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/playernames/template/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 - 2017 Aapo Talvensaari +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/resources/[cfx-default]/[gameplay]/playernames/template/template.lua b/resources/[cfx-default]/[gameplay]/playernames/template/template.lua new file mode 100644 index 0000000..0de71bd --- /dev/null +++ b/resources/[cfx-default]/[gameplay]/playernames/template/template.lua @@ -0,0 +1,478 @@ +local setmetatable = setmetatable +local loadstring = loadstring +local loadchunk +local tostring = tostring +local setfenv = setfenv +local require = require +local capture +local concat = table.concat +local assert = assert +local prefix +local write = io.write +local pcall = pcall +local phase +local open = io.open +local load = load +local type = type +local dump = string.dump +local find = string.find +local gsub = string.gsub +local byte = string.byte +local null +local sub = string.sub +local ngx = ngx +local jit = jit +local var + +local _VERSION = _VERSION +local _ENV = _ENV +local _G = _G + +local HTML_ENTITIES = { + ["&"] = "&", + ["<"] = "<", + [">"] = ">", + ['"'] = """, + ["'"] = "'", + ["/"] = "/" +} + +local CODE_ENTITIES = { + ["{"] = "{", + ["}"] = "}", + ["&"] = "&", + ["<"] = "<", + [">"] = ">", + ['"'] = """, + ["'"] = "'", + ["/"] = "/" +} + +local VAR_PHASES + +local ok, newtab = pcall(require, "table.new") +if not ok then newtab = function() return {} end end + +local caching = true +local template = newtab(0, 12) + +template._VERSION = "1.9" +template.cache = {} + +local function enabled(val) + if val == nil then return true end + return val == true or (val == "1" or val == "true" or val == "on") +end + +local function trim(s) + return gsub(gsub(s, "^%s+", ""), "%s+$", "") +end + +local function rpos(view, s) + while s > 0 do + local c = sub(view, s, s) + if c == " " or c == "\t" or c == "\0" or c == "\x0B" then + s = s - 1 + else + break + end + end + return s +end + +local function escaped(view, s) + if s > 1 and sub(view, s - 1, s - 1) == "\\" then + if s > 2 and sub(view, s - 2, s - 2) == "\\" then + return false, 1 + else + return true, 1 + end + end + return false, 0 +end + +local function readfile(path) + local file = open(path, "rb") + if not file then return nil end + local content = file:read "*a" + file:close() + return content +end + +local function loadlua(path) + return readfile(path) or path +end + +local function loadngx(path) + local vars = VAR_PHASES[phase()] + local file, location = path, vars and var.template_location + if sub(file, 1) == "/" then file = sub(file, 2) end + if location and location ~= "" then + if sub(location, -1) == "/" then location = sub(location, 1, -2) end + local res = capture(concat{ location, '/', file}) + if res.status == 200 then return res.body end + end + local root = vars and (var.template_root or var.document_root) or prefix + if sub(root, -1) == "/" then root = sub(root, 1, -2) end + return readfile(concat{ root, "/", file }) or path +end + +do + if ngx then + VAR_PHASES = { + set = true, + rewrite = true, + access = true, + content = true, + header_filter = true, + body_filter = true, + log = true + } + template.print = ngx.print or write + template.load = loadngx + prefix, var, capture, null, phase = ngx.config.prefix(), ngx.var, ngx.location.capture, ngx.null, ngx.get_phase + if VAR_PHASES[phase()] then + caching = enabled(var.template_cache) + end + else + template.print = write + template.load = loadlua + end + if _VERSION == "Lua 5.1" then + local context = { __index = function(t, k) + return t.context[k] or t.template[k] or _G[k] + end } + if jit then + loadchunk = function(view) + return assert(load(view, nil, nil, setmetatable({ template = template }, context))) + end + else + loadchunk = function(view) + local func = assert(loadstring(view)) + setfenv(func, setmetatable({ template = template }, context)) + return func + end + end + else + local context = { __index = function(t, k) + return t.context[k] or t.template[k] or _ENV[k] + end } + loadchunk = function(view) + return assert(load(view, nil, nil, setmetatable({ template = template }, context))) + end + end +end + +function template.caching(enable) + if enable ~= nil then caching = enable == true end + return caching +end + +function template.output(s) + if s == nil or s == null then return "" end + if type(s) == "function" then return template.output(s()) end + return tostring(s) +end + +function template.escape(s, c) + if type(s) == "string" then + if c then return gsub(s, "[}{\">/<'&]", CODE_ENTITIES) end + return gsub(s, "[\">/<'&]", HTML_ENTITIES) + end + return template.output(s) +end + +function template.new(view, layout) + assert(view, "view was not provided for template.new(view, layout).") + local render, compile = template.render, template.compile + if layout then + if type(layout) == "table" then + return setmetatable({ render = function(self, context) + local context = context or self + context.blocks = context.blocks or {} + context.view = compile(view)(context) + layout.blocks = context.blocks or {} + layout.view = context.view or "" + return layout:render() + end }, { __tostring = function(self) + local context = self + context.blocks = context.blocks or {} + context.view = compile(view)(context) + layout.blocks = context.blocks or {} + layout.view = context.view + return tostring(layout) + end }) + else + return setmetatable({ render = function(self, context) + local context = context or self + context.blocks = context.blocks or {} + context.view = compile(view)(context) + return render(layout, context) + end }, { __tostring = function(self) + local context = self + context.blocks = context.blocks or {} + context.view = compile(view)(context) + return compile(layout)(context) + end }) + end + end + return setmetatable({ render = function(self, context) + return render(view, context or self) + end }, { __tostring = function(self) + return compile(view)(self) + end }) +end + +function template.precompile(view, path, strip) + local chunk = dump(template.compile(view), strip ~= false) + if path then + local file = open(path, "wb") + file:write(chunk) + file:close() + end + return chunk +end + +function template.compile(view, key, plain) + assert(view, "view was not provided for template.compile(view, key, plain).") + if key == "no-cache" then + return loadchunk(template.parse(view, plain)), false + end + key = key or view + local cache = template.cache + if cache[key] then return cache[key], true end + local func = loadchunk(template.parse(view, plain)) + if caching then cache[key] = func end + return func, false +end + +function template.parse(view, plain) + assert(view, "view was not provided for template.parse(view, plain).") + if not plain then + view = template.load(view) + if byte(view, 1, 1) == 27 then return view end + end + local j = 2 + local c = {[[ +context=... or {} +local function include(v, c) return template.compile(v)(c or context) end +local ___,blocks,layout={},blocks or {} +]] } + local i, s = 1, find(view, "{", 1, true) + while s do + local t, p = sub(view, s + 1, s + 1), s + 2 + if t == "{" then + local e = find(view, "}}", p, true) + if e then + local z, w = escaped(view, s) + if i < s - w then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, s - 1 - w) + c[j+2] = "]=]\n" + j=j+3 + end + if z then + i = s + else + c[j] = "___[#___+1]=template.escape(" + c[j+1] = trim(sub(view, p, e - 1)) + c[j+2] = ")\n" + j=j+3 + s, i = e + 1, e + 2 + end + end + elseif t == "*" then + local e = find(view, "*}", p, true) + if e then + local z, w = escaped(view, s) + if i < s - w then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, s - 1 - w) + c[j+2] = "]=]\n" + j=j+3 + end + if z then + i = s + else + c[j] = "___[#___+1]=template.output(" + c[j+1] = trim(sub(view, p, e - 1)) + c[j+2] = ")\n" + j=j+3 + s, i = e + 1, e + 2 + end + end + elseif t == "%" then + local e = find(view, "%}", p, true) + if e then + local z, w = escaped(view, s) + if z then + if i < s - w then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, s - 1 - w) + c[j+2] = "]=]\n" + j=j+3 + end + i = s + else + local n = e + 2 + if sub(view, n, n) == "\n" then + n = n + 1 + end + local r = rpos(view, s - 1) + if i <= r then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, r) + c[j+2] = "]=]\n" + j=j+3 + end + c[j] = trim(sub(view, p, e - 1)) + c[j+1] = "\n" + j=j+2 + s, i = n - 1, n + end + end + elseif t == "(" then + local e = find(view, ")}", p, true) + if e then + local z, w = escaped(view, s) + if i < s - w then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, s - 1 - w) + c[j+2] = "]=]\n" + j=j+3 + end + if z then + i = s + else + local f = sub(view, p, e - 1) + local x = find(f, ",", 2, true) + if x then + c[j] = "___[#___+1]=include([=[" + c[j+1] = trim(sub(f, 1, x - 1)) + c[j+2] = "]=]," + c[j+3] = trim(sub(f, x + 1)) + c[j+4] = ")\n" + j=j+5 + else + c[j] = "___[#___+1]=include([=[" + c[j+1] = trim(f) + c[j+2] = "]=])\n" + j=j+3 + end + s, i = e + 1, e + 2 + end + end + elseif t == "[" then + local e = find(view, "]}", p, true) + if e then + local z, w = escaped(view, s) + if i < s - w then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, s - 1 - w) + c[j+2] = "]=]\n" + j=j+3 + end + if z then + i = s + else + c[j] = "___[#___+1]=include(" + c[j+1] = trim(sub(view, p, e - 1)) + c[j+2] = ")\n" + j=j+3 + s, i = e + 1, e + 2 + end + end + elseif t == "-" then + local e = find(view, "-}", p, true) + if e then + local x, y = find(view, sub(view, s, e + 1), e + 2, true) + if x then + local z, w = escaped(view, s) + if z then + if i < s - w then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, s - 1 - w) + c[j+2] = "]=]\n" + j=j+3 + end + i = s + else + y = y + 1 + x = x - 1 + if sub(view, y, y) == "\n" then + y = y + 1 + end + local b = trim(sub(view, p, e - 1)) + if b == "verbatim" or b == "raw" then + if i < s - w then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, s - 1 - w) + c[j+2] = "]=]\n" + j=j+3 + end + c[j] = "___[#___+1]=[=[" + c[j+1] = sub(view, e + 2, x) + c[j+2] = "]=]\n" + j=j+3 + else + if sub(view, x, x) == "\n" then + x = x - 1 + end + local r = rpos(view, s - 1) + if i <= r then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, r) + c[j+2] = "]=]\n" + j=j+3 + end + c[j] = 'blocks["' + c[j+1] = b + c[j+2] = '"]=include[=[' + c[j+3] = sub(view, e + 2, x) + c[j+4] = "]=]\n" + j=j+5 + end + s, i = y - 1, y + end + end + end + elseif t == "#" then + local e = find(view, "#}", p, true) + if e then + local z, w = escaped(view, s) + if i < s - w then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = sub(view, i, s - 1 - w) + c[j+2] = "]=]\n" + j=j+3 + end + if z then + i = s + else + e = e + 2 + if sub(view, e, e) == "\n" then + e = e + 1 + end + s, i = e - 1, e + end + end + end + s = find(view, "{", s + 1, true) + end + s = sub(view, i) + if s and s ~= "" then + c[j] = "___[#___+1]=[=[\n" + c[j+1] = s + c[j+2] = "]=]\n" + j=j+3 + end + c[j] = "return layout and include(layout,setmetatable({view=table.concat(___),blocks=blocks},{__index=context})) or table.concat(___)" + return concat(c) +end + +function template.render(view, context, key, plain) + assert(view, "view was not provided for template.render(view, context, key, plain).") + return template.print(template.compile(view, key, plain)(context)) +end + +return template diff --git a/resources/[cfx-default]/[local]/.gitkeep b/resources/[cfx-default]/[local]/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resources/[cfx-default]/[managers]/mapmanager/fxmanifest.lua b/resources/[cfx-default]/[managers]/mapmanager/fxmanifest.lua new file mode 100644 index 0000000..9e89921 --- /dev/null +++ b/resources/[cfx-default]/[managers]/mapmanager/fxmanifest.lua @@ -0,0 +1,30 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'A flexible handler for game type/map association.' +repository 'https://github.com/citizenfx/cfx-server-data' + +client_scripts { + "mapmanager_shared.lua", + "mapmanager_client.lua" +} + +server_scripts { + "mapmanager_shared.lua", + "mapmanager_server.lua" +} + +fx_version 'adamant' +games { 'gta5', 'rdr3' } + +server_export "getCurrentGameType" +server_export "getCurrentMap" +server_export "changeGameType" +server_export "changeMap" +server_export "doesMapSupportGameType" +server_export "getMaps" +server_export "roundEnded" + +rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.' diff --git a/resources/[cfx-default]/[managers]/mapmanager/mapmanager_client.lua b/resources/[cfx-default]/[managers]/mapmanager/mapmanager_client.lua new file mode 100644 index 0000000..510c24e --- /dev/null +++ b/resources/[cfx-default]/[managers]/mapmanager/mapmanager_client.lua @@ -0,0 +1,108 @@ +local maps = {} +local gametypes = {} + +AddEventHandler('onClientResourceStart', function(res) + -- parse metadata for this resource + + -- map files + local num = GetNumResourceMetadata(res, 'map') + + if num > 0 then + for i = 0, num-1 do + local file = GetResourceMetadata(res, 'map', i) + + if file then + addMap(file, res) + end + end + end + + -- resource type data + local type = GetResourceMetadata(res, 'resource_type', 0) + + if type then + local extraData = GetResourceMetadata(res, 'resource_type_extra', 0) + + if extraData then + extraData = json.decode(extraData) + else + extraData = {} + end + + if type == 'map' then + maps[res] = extraData + elseif type == 'gametype' then + gametypes[res] = extraData + end + end + + -- handle starting + loadMap(res) + + -- defer this to the next game tick to work around a lack of dependencies + Citizen.CreateThread(function() + Citizen.Wait(15) + + if maps[res] then + TriggerEvent('onClientMapStart', res) + elseif gametypes[res] then + TriggerEvent('onClientGameTypeStart', res) + end + end) +end) + +AddEventHandler('onResourceStop', function(res) + if maps[res] then + TriggerEvent('onClientMapStop', res) + elseif gametypes[res] then + TriggerEvent('onClientGameTypeStop', res) + end + + unloadMap(res) +end) + +AddEventHandler('getMapDirectives', function(add) + if not CreateScriptVehicleGenerator then + return + end + + add('vehicle_generator', function(state, name) + return function(opts) + local x, y, z, heading + local color1, color2 + + if opts.x then + x = opts.x + y = opts.y + z = opts.z + else + x = opts[1] + y = opts[2] + z = opts[3] + end + + heading = opts.heading or 1.0 + color1 = opts.color1 or -1 + color2 = opts.color2 or -1 + + CreateThread(function() + local hash = GetHashKey(name) + RequestModel(hash) + + while not HasModelLoaded(hash) do + Wait(0) + end + + local carGen = CreateScriptVehicleGenerator(x, y, z, heading, 5.0, 3.0, hash, color1, color2, -1, -1, true, false, false, true, true, -1) + SetScriptVehicleGenerator(carGen, true) + SetAllVehicleGeneratorsActive(true) + + state.add('cargen', carGen) + end) + end + end, function(state, arg) + Citizen.Trace("deleting car gen " .. tostring(state.cargen) .. "\n") + + DeleteScriptVehicleGenerator(state.cargen) + end) +end) diff --git a/resources/[cfx-default]/[managers]/mapmanager/mapmanager_server.lua b/resources/[cfx-default]/[managers]/mapmanager/mapmanager_server.lua new file mode 100644 index 0000000..3f2cf70 --- /dev/null +++ b/resources/[cfx-default]/[managers]/mapmanager/mapmanager_server.lua @@ -0,0 +1,331 @@ +-- loosely based on MTA's https://code.google.com/p/mtasa-resources/source/browse/trunk/%5Bmanagers%5D/mapmanager/mapmanager_main.lua + +local maps = {} +local gametypes = {} + +local function refreshResources() + local numResources = GetNumResources() + + for i = 0, numResources - 1 do + local resource = GetResourceByFindIndex(i) + + if GetNumResourceMetadata(resource, 'resource_type') > 0 then + local type = GetResourceMetadata(resource, 'resource_type', 0) + local params = json.decode(GetResourceMetadata(resource, 'resource_type_extra', 0)) + + local valid = false + + local games = GetNumResourceMetadata(resource, 'game') + if games > 0 then + for j = 0, games - 1 do + local game = GetResourceMetadata(resource, 'game', j) + + if game == GetConvar('gamename', 'gta5') or game == 'common' then + valid = true + end + end + end + + if valid then + if type == 'map' then + maps[resource] = params + elseif type == 'gametype' then + gametypes[resource] = params + end + end + end + end +end + +AddEventHandler('onResourceListRefresh', function() + refreshResources() +end) + +refreshResources() + +AddEventHandler('onResourceStarting', function(resource) + local num = GetNumResourceMetadata(resource, 'map') + + if num then + for i = 0, num-1 do + local file = GetResourceMetadata(resource, 'map', i) + + if file then + addMap(file, resource) + end + end + end + + if maps[resource] then + if getCurrentMap() and getCurrentMap() ~= resource then + if doesMapSupportGameType(getCurrentGameType(), resource) then + print("Changing map from " .. getCurrentMap() .. " to " .. resource) + + changeMap(resource) + else + -- check if there's only one possible game type for the map + local map = maps[resource] + local count = 0 + local gt + + for type, flag in pairs(map.gameTypes) do + if flag then + count = count + 1 + gt = type + end + end + + if count == 1 then + print("Changing map from " .. getCurrentMap() .. " to " .. resource .. " (gt " .. gt .. ")") + + changeGameType(gt) + changeMap(resource) + end + end + + CancelEvent() + end + elseif gametypes[resource] then + if getCurrentGameType() and getCurrentGameType() ~= resource then + print("Changing gametype from " .. getCurrentGameType() .. " to " .. resource) + + changeGameType(resource) + + CancelEvent() + end + end +end) + +math.randomseed(GetInstanceId()) + +local currentGameType = nil +local currentMap = nil + +AddEventHandler('onResourceStart', function(resource) + if maps[resource] then + if not getCurrentGameType() then + for gt, _ in pairs(maps[resource].gameTypes) do + changeGameType(gt) + break + end + end + + if getCurrentGameType() and not getCurrentMap() then + if doesMapSupportGameType(currentGameType, resource) then + if TriggerEvent('onMapStart', resource, maps[resource]) then + if maps[resource].name then + print('Started map ' .. maps[resource].name) + SetMapName(maps[resource].name) + else + print('Started map ' .. resource) + SetMapName(resource) + end + + currentMap = resource + else + currentMap = nil + end + end + end + elseif gametypes[resource] then + if not getCurrentGameType() then + if TriggerEvent('onGameTypeStart', resource, gametypes[resource]) then + currentGameType = resource + + local gtName = gametypes[resource].name or resource + + SetGameType(gtName) + + print('Started gametype ' .. gtName) + + SetTimeout(50, function() + if not currentMap then + local possibleMaps = {} + + for map, data in pairs(maps) do + if data.gameTypes[currentGameType] then + table.insert(possibleMaps, map) + end + end + + if #possibleMaps > 0 then + local rnd = math.random(#possibleMaps) + changeMap(possibleMaps[rnd]) + end + end + end) + else + currentGameType = nil + end + end + end + + -- handle starting + loadMap(resource) +end) + +local function handleRoundEnd() + local possibleMaps = {} + + for map, data in pairs(maps) do + if data.gameTypes[currentGameType] then + table.insert(possibleMaps, map) + end + end + + if #possibleMaps > 1 then + local mapname = currentMap + + while mapname == currentMap do + local rnd = math.random(#possibleMaps) + mapname = possibleMaps[rnd] + end + + changeMap(mapname) + elseif #possibleMaps > 0 then + local rnd = math.random(#possibleMaps) + changeMap(possibleMaps[rnd]) + end +end + +AddEventHandler('mapmanager:roundEnded', function() + -- set a timeout as we don't want to return to a dead environment + SetTimeout(50, handleRoundEnd) -- not a closure as to work around some issue in neolua? +end) + +function roundEnded() + SetTimeout(50, handleRoundEnd) +end + +AddEventHandler('onResourceStop', function(resource) + if resource == currentGameType then + TriggerEvent('onGameTypeStop', resource) + + currentGameType = nil + + if currentMap then + StopResource(currentMap) + end + elseif resource == currentMap then + TriggerEvent('onMapStop', resource) + + currentMap = nil + end + + -- unload the map + unloadMap(resource) +end) + +AddEventHandler('rconCommand', function(commandName, args) + if commandName == 'map' then + if #args ~= 1 then + RconPrint("usage: map [mapname]\n") + end + + if not maps[args[1]] then + RconPrint('no such map ' .. args[1] .. "\n") + CancelEvent() + + return + end + + if currentGameType == nil or not doesMapSupportGameType(currentGameType, args[1]) then + local map = maps[args[1]] + local count = 0 + local gt + + for type, flag in pairs(map.gameTypes) do + if flag then + count = count + 1 + gt = type + end + end + + if count == 1 then + print("Changing map from " .. getCurrentMap() .. " to " .. args[1] .. " (gt " .. gt .. ")") + + changeGameType(gt) + changeMap(args[1]) + + RconPrint('map ' .. args[1] .. "\n") + else + RconPrint('map ' .. args[1] .. ' does not support ' .. currentGameType .. "\n") + end + + CancelEvent() + + return + end + + changeMap(args[1]) + + RconPrint('map ' .. args[1] .. "\n") + + CancelEvent() + elseif commandName == 'gametype' then + if #args ~= 1 then + RconPrint("usage: gametype [name]\n") + end + + if not gametypes[args[1]] then + RconPrint('no such gametype ' .. args[1] .. "\n") + CancelEvent() + + return + end + + changeGameType(args[1]) + + RconPrint('gametype ' .. args[1] .. "\n") + + CancelEvent() + end +end) + +function getCurrentGameType() + return currentGameType +end + +function getCurrentMap() + return currentMap +end + +function getMaps() + return maps +end + +function changeGameType(gameType) + if currentMap and not doesMapSupportGameType(gameType, currentMap) then + StopResource(currentMap) + end + + if currentGameType then + StopResource(currentGameType) + end + + StartResource(gameType) +end + +function changeMap(map) + if currentMap then + StopResource(currentMap) + end + + StartResource(map) +end + +function doesMapSupportGameType(gameType, map) + if not gametypes[gameType] then + return false + end + + if not maps[map] then + return false + end + + if not maps[map].gameTypes then + return true + end + + return maps[map].gameTypes[gameType] +end diff --git a/resources/[cfx-default]/[managers]/mapmanager/mapmanager_shared.lua b/resources/[cfx-default]/[managers]/mapmanager/mapmanager_shared.lua new file mode 100644 index 0000000..cac5b6c --- /dev/null +++ b/resources/[cfx-default]/[managers]/mapmanager/mapmanager_shared.lua @@ -0,0 +1,87 @@ +-- shared logic file for map manager - don't call any subsystem-specific functions here +mapFiles = {} + +function addMap(file, owningResource) + if not mapFiles[owningResource] then + mapFiles[owningResource] = {} + end + + table.insert(mapFiles[owningResource], file) +end + +undoCallbacks = {} + +function loadMap(res) + if mapFiles[res] then + for _, file in ipairs(mapFiles[res]) do + parseMap(file, res) + end + end +end + +function unloadMap(res) + if undoCallbacks[res] then + for _, cb in ipairs(undoCallbacks[res]) do + cb() + end + + undoCallbacks[res] = nil + mapFiles[res] = nil + end +end + +function parseMap(file, owningResource) + if not undoCallbacks[owningResource] then + undoCallbacks[owningResource] = {} + end + + local env = { + math = math, pairs = pairs, ipairs = ipairs, next = next, tonumber = tonumber, tostring = tostring, + type = type, table = table, string = string, _G = env, + vector3 = vector3, quat = quat, vec = vec, vector2 = vector2 + } + + TriggerEvent('getMapDirectives', function(key, cb, undocb) + env[key] = function(...) + local state = {} + + state.add = function(k, v) + state[k] = v + end + + local result = cb(state, ...) + local args = table.pack(...) + + table.insert(undoCallbacks[owningResource], function() + undocb(state) + end) + + return result + end + end) + + local mt = { + __index = function(t, k) + if rawget(t, k) ~= nil then return rawget(t, k) end + + -- as we're not going to return nothing here (to allow unknown directives to be ignored) + local f = function() + return f + end + + return function() return f end + end + } + + setmetatable(env, mt) + + local fileData = LoadResourceFile(owningResource, file) + local mapFunction, err = load(fileData, file, 't', env) + + if not mapFunction then + Citizen.Trace("Couldn't load map " .. file .. ": " .. err .. " (type of fileData: " .. type(fileData) .. ")\n") + return + end + + mapFunction() +end \ No newline at end of file diff --git a/resources/[cfx-default]/[managers]/spawnmanager/fxmanifest.lua b/resources/[cfx-default]/[managers]/spawnmanager/fxmanifest.lua new file mode 100644 index 0000000..13eb96b --- /dev/null +++ b/resources/[cfx-default]/[managers]/spawnmanager/fxmanifest.lua @@ -0,0 +1,14 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'Handles spawning a player in a unified fashion to prevent resources from having to implement custom spawn logic.' +repository 'https://github.com/citizenfx/cfx-server-data' + +client_script 'spawnmanager.lua' + +fx_version 'adamant' +games { 'rdr3', 'gta5' } + +rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.' diff --git a/resources/[cfx-default]/[managers]/spawnmanager/spawnmanager.lua b/resources/[cfx-default]/[managers]/spawnmanager/spawnmanager.lua new file mode 100644 index 0000000..9e940d8 --- /dev/null +++ b/resources/[cfx-default]/[managers]/spawnmanager/spawnmanager.lua @@ -0,0 +1,386 @@ +-- in-memory spawnpoint array for this script execution instance +local spawnPoints = {} + +-- auto-spawn enabled flag +local autoSpawnEnabled = false +local autoSpawnCallback + +-- support for mapmanager maps +AddEventHandler('getMapDirectives', function(add) + -- call the remote callback + add('spawnpoint', function(state, model) + -- return another callback to pass coordinates and so on (as such syntax would be [spawnpoint 'model' { options/coords }]) + return function(opts) + local x, y, z, heading + + local s, e = pcall(function() + -- is this a map or an array? + if opts.x then + x = opts.x + y = opts.y + z = opts.z + else + x = opts[1] + y = opts[2] + z = opts[3] + end + + x = x + 0.0001 + y = y + 0.0001 + z = z + 0.0001 + + -- get a heading and force it to a float, or just default to null + heading = opts.heading and (opts.heading + 0.01) or 0 + + -- add the spawnpoint + addSpawnPoint({ + x = x, y = y, z = z, + heading = heading, + model = model + }) + + -- recalculate the model for storage + if not tonumber(model) then + model = GetHashKey(model, _r) + end + + -- store the spawn data in the state so we can erase it later on + state.add('xyz', { x, y, z }) + state.add('model', model) + end) + + if not s then + Citizen.Trace(e .. "\n") + end + end + -- delete callback follows on the next line + end, function(state, arg) + -- loop through all spawn points to find one with our state + for i, sp in ipairs(spawnPoints) do + -- if it matches... + if sp.x == state.xyz[1] and sp.y == state.xyz[2] and sp.z == state.xyz[3] and sp.model == state.model then + -- remove it. + table.remove(spawnPoints, i) + return + end + end + end) +end) + + +-- loads a set of spawn points from a JSON string +function loadSpawns(spawnString) + -- decode the JSON string + local data = json.decode(spawnString) + + -- do we have a 'spawns' field? + if not data.spawns then + error("no 'spawns' in JSON data") + end + + -- loop through the spawns + for i, spawn in ipairs(data.spawns) do + -- and add it to the list (validating as we go) + addSpawnPoint(spawn) + end +end + +local spawnNum = 1 + +function addSpawnPoint(spawn) + -- validate the spawn (position) + if not tonumber(spawn.x) or not tonumber(spawn.y) or not tonumber(spawn.z) then + error("invalid spawn position") + end + + -- heading + if not tonumber(spawn.heading) then + error("invalid spawn heading") + end + + -- model (try integer first, if not, hash it) + local model = spawn.model + + if not tonumber(spawn.model) then + model = GetHashKey(spawn.model) + end + + -- is the model actually a model? + if not IsModelInCdimage(model) then + error("invalid spawn model") + end + + -- is is even a ped? + -- not in V? + --[[if not IsThisModelAPed(model) then + error("this model ain't a ped!") + end]] + + -- overwrite the model in case we hashed it + spawn.model = model + + -- add an index + spawn.idx = spawnNum + spawnNum = spawnNum + 1 + + -- all OK, add the spawn entry to the list + table.insert(spawnPoints, spawn) + + return spawn.idx +end + +-- removes a spawn point +function removeSpawnPoint(spawn) + for i = 1, #spawnPoints do + if spawnPoints[i].idx == spawn then + table.remove(spawnPoints, i) + return + end + end +end + +-- changes the auto-spawn flag +function setAutoSpawn(enabled) + autoSpawnEnabled = enabled +end + +-- sets a callback to execute instead of 'native' spawning when trying to auto-spawn +function setAutoSpawnCallback(cb) + autoSpawnCallback = cb + autoSpawnEnabled = true +end + +-- function as existing in original R* scripts +local function freezePlayer(id, freeze) + local player = id + SetPlayerControl(player, not freeze, false) + + local ped = GetPlayerPed(player) + + if not freeze then + if not IsEntityVisible(ped) then + SetEntityVisible(ped, true) + end + + if not IsPedInAnyVehicle(ped) then + SetEntityCollision(ped, true) + end + + FreezeEntityPosition(ped, false) + --SetCharNeverTargetted(ped, false) + SetPlayerInvincible(player, false) + else + if IsEntityVisible(ped) then + SetEntityVisible(ped, false) + end + + SetEntityCollision(ped, false) + FreezeEntityPosition(ped, true) + --SetCharNeverTargetted(ped, true) + SetPlayerInvincible(player, true) + --RemovePtfxFromPed(ped) + + if not IsPedFatallyInjured(ped) then + ClearPedTasksImmediately(ped) + end + end +end + +function loadScene(x, y, z) + if not NewLoadSceneStart then + return + end + + NewLoadSceneStart(x, y, z, 0.0, 0.0, 0.0, 20.0, 0) + + while IsNewLoadSceneActive() do + networkTimer = GetNetworkTimer() + + NetworkUpdateLoadScene() + end +end + +-- to prevent trying to spawn multiple times +local spawnLock = false + +-- spawns the current player at a certain spawn point index (or a random one, for that matter) +function spawnPlayer(spawnIdx, cb) + if spawnLock then + return + end + + spawnLock = true + + Citizen.CreateThread(function() + -- if the spawn isn't set, select a random one + if not spawnIdx then + spawnIdx = GetRandomIntInRange(1, #spawnPoints + 1) + end + + -- get the spawn from the array + local spawn + + if type(spawnIdx) == 'table' then + spawn = spawnIdx + + -- prevent errors when passing spawn table + spawn.x = spawn.x + 0.00 + spawn.y = spawn.y + 0.00 + spawn.z = spawn.z + 0.00 + + spawn.heading = spawn.heading and (spawn.heading + 0.00) or 0 + else + spawn = spawnPoints[spawnIdx] + end + + if not spawn.skipFade then + DoScreenFadeOut(500) + + while not IsScreenFadedOut() do + Citizen.Wait(0) + end + end + + -- validate the index + if not spawn then + Citizen.Trace("tried to spawn at an invalid spawn index\n") + + spawnLock = false + + return + end + + -- freeze the local player + freezePlayer(PlayerId(), true) + + -- if the spawn has a model set + if spawn.model then + RequestModel(spawn.model) + + -- load the model for this spawn + while not HasModelLoaded(spawn.model) do + RequestModel(spawn.model) + + Wait(0) + end + + -- change the player model + SetPlayerModel(PlayerId(), spawn.model) + + -- release the player model + SetModelAsNoLongerNeeded(spawn.model) + + -- RDR3 player model bits + if N_0x283978a15512b2fe then + N_0x283978a15512b2fe(PlayerPedId(), true) + end + end + + -- preload collisions for the spawnpoint + RequestCollisionAtCoord(spawn.x, spawn.y, spawn.z) + + -- spawn the player + local ped = PlayerPedId() + + -- V requires setting coords as well + SetEntityCoordsNoOffset(ped, spawn.x, spawn.y, spawn.z, false, false, false, true) + + NetworkResurrectLocalPlayer(spawn.x, spawn.y, spawn.z, spawn.heading, true, true, false) + + -- gamelogic-style cleanup stuff + ClearPedTasksImmediately(ped) + --SetEntityHealth(ped, 300) -- TODO: allow configuration of this? + RemoveAllPedWeapons(ped) -- TODO: make configurable (V behavior?) + ClearPlayerWantedLevel(PlayerId()) + + -- why is this even a flag? + --SetCharWillFlyThroughWindscreen(ped, false) + + -- set primary camera heading + --SetGameCamHeading(spawn.heading) + --CamRestoreJumpcut(GetGameCam()) + + -- load the scene; streaming expects us to do it + --ForceLoadingScreen(true) + --loadScene(spawn.x, spawn.y, spawn.z) + --ForceLoadingScreen(false) + + local time = GetGameTimer() + + while (not HasCollisionLoadedAroundEntity(ped) and (GetGameTimer() - time) < 5000) do + Citizen.Wait(0) + end + + ShutdownLoadingScreen() + + if IsScreenFadedOut() then + DoScreenFadeIn(500) + + while not IsScreenFadedIn() do + Citizen.Wait(0) + end + end + + -- and unfreeze the player + freezePlayer(PlayerId(), false) + + TriggerEvent('playerSpawned', spawn) + + if cb then + cb(spawn) + end + + spawnLock = false + end) +end + +-- automatic spawning monitor thread, too +local respawnForced +local diedAt + +Citizen.CreateThread(function() + -- main loop thing + while true do + Citizen.Wait(50) + + local playerPed = PlayerPedId() + + if playerPed and playerPed ~= -1 then + -- check if we want to autospawn + if autoSpawnEnabled then + if NetworkIsPlayerActive(PlayerId()) then + if (diedAt and (math.abs(GetTimeDifference(GetGameTimer(), diedAt)) > 2000)) or respawnForced then + if autoSpawnCallback then + autoSpawnCallback() + else + spawnPlayer() + end + + respawnForced = false + end + end + end + + if IsEntityDead(playerPed) then + if not diedAt then + diedAt = GetGameTimer() + end + else + diedAt = nil + end + end + end +end) + +function forceRespawn() + spawnLock = false + respawnForced = true +end + +exports('spawnPlayer', spawnPlayer) +exports('addSpawnPoint', addSpawnPoint) +exports('removeSpawnPoint', removeSpawnPoint) +exports('loadSpawns', loadSpawns) +exports('setAutoSpawn', setAutoSpawn) +exports('setAutoSpawnCallback', setAutoSpawnCallback) +exports('forceRespawn', forceRespawn) diff --git a/resources/[cfx-default]/[system]/[builders]/webpack/.gitignore b/resources/[cfx-default]/[system]/[builders]/webpack/.gitignore new file mode 100644 index 0000000..b5e9127 --- /dev/null +++ b/resources/[cfx-default]/[system]/[builders]/webpack/.gitignore @@ -0,0 +1,2 @@ +.yarn.installed +node_modules/ \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/[builders]/webpack/fxmanifest.lua b/resources/[cfx-default]/[system]/[builders]/webpack/fxmanifest.lua new file mode 100644 index 0000000..b8b8a4b --- /dev/null +++ b/resources/[cfx-default]/[system]/[builders]/webpack/fxmanifest.lua @@ -0,0 +1,13 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'Builds resources with webpack. To learn more: https://webpack.js.org' +repository 'https://github.com/citizenfx/cfx-server-data' + +dependency 'yarn' +server_script 'webpack_builder.js' + +fx_version 'adamant' +game 'common' diff --git a/resources/[cfx-default]/[system]/[builders]/webpack/package.json b/resources/[cfx-default]/[system]/[builders]/webpack/package.json new file mode 100644 index 0000000..45b2438 --- /dev/null +++ b/resources/[cfx-default]/[system]/[builders]/webpack/package.json @@ -0,0 +1,16 @@ +{ + "name": "webpack-builder", + "version": "1.0.1", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "async": "^3.1.0", + "webpack": "^4.41.2", + "worker-farm": "^1.7.0" + } +} diff --git a/resources/[cfx-default]/[system]/[builders]/webpack/webpack_builder.js b/resources/[cfx-default]/[system]/[builders]/webpack/webpack_builder.js new file mode 100644 index 0000000..b487e13 --- /dev/null +++ b/resources/[cfx-default]/[system]/[builders]/webpack/webpack_builder.js @@ -0,0 +1,173 @@ +const fs = require('fs'); +const path = require('path'); +const workerFarm = require('worker-farm'); +const async = require('async'); +let buildingInProgress = false; +let currentBuildingModule = ''; + +// some modules will not like the custom stack trace logic +const ops = Error.prepareStackTrace; +Error.prepareStackTrace = undefined; + +const webpackBuildTask = { + shouldBuild(resourceName) { + const numMetaData = GetNumResourceMetadata(resourceName, 'webpack_config'); + + if (numMetaData > 0) { + for (let i = 0; i < numMetaData; i++) { + const configName = GetResourceMetadata(resourceName, 'webpack_config'); + + if (shouldBuild(configName)) { + return true; + } + } + } + + return false; + + function loadCache(config) { + const cachePath = `cache/${resourceName}/${config.replace(/\//g, '_')}.json`; + + try { + return JSON.parse(fs.readFileSync(cachePath, {encoding: 'utf8'})); + } catch { + return null; + } + } + + function shouldBuild(config) { + const cache = loadCache(config); + + if (!cache) { + return true; + } + + for (const file of cache) { + const stats = getStat(file.name); + + if (!stats || + stats.mtime !== file.stats.mtime || + stats.size !== file.stats.size || + stats.inode !== file.stats.inode) { + return true; + } + } + + return false; + } + + function getStat(path) { + try { + const stat = fs.statSync(path); + + return stat ? { + mtime: stat.mtimeMs, + size: stat.size, + inode: stat.ino, + } : null; + } catch { + return null; + } + } + }, + + build(resourceName, cb) { + let buildWebpack = async () => { + let error = null; + const configs = []; + const promises = []; + const numMetaData = GetNumResourceMetadata(resourceName, 'webpack_config'); + + for (let i = 0; i < numMetaData; i++) { + configs.push(GetResourceMetadata(resourceName, 'webpack_config', i)); + } + + for (const configName of configs) { + const configPath = GetResourcePath(resourceName) + '/' + configName; + + const cachePath = `cache/${resourceName}/${configName.replace(/\//g, '_')}.json`; + + try { + fs.mkdirSync(path.dirname(cachePath)); + } catch { + } + + const config = require(configPath); + + const workers = workerFarm(require.resolve('./webpack_runner')); + + if (config) { + const resourcePath = path.resolve(GetResourcePath(resourceName)); + + while (buildingInProgress) { + console.log(`webpack is busy: we are waiting to compile ${resourceName} (${configName})`); + await sleep(3000); + } + + console.log(`${resourceName}: started building ${configName}`); + + buildingInProgress = true; + currentBuildingModule = resourceName; + + promises.push(new Promise((resolve, reject) => { + workers({ + configPath, + resourcePath, + cachePath + }, (err, outp) => { + workerFarm.end(workers); + + if (err) { + console.error(err.stack || err); + if (err.details) { + console.error(err.details); + } + + buildingInProgress = false; + currentBuildingModule = ''; + currentBuildingScript = ''; + reject("worker farm webpack errored out"); + return; + } + + if (outp.errors) { + for (const error of outp.errors) { + console.log(error); + } + buildingInProgress = false; + currentBuildingModule = ''; + currentBuildingScript = ''; + reject("webpack got an error"); + return; + } + + console.log(`${resourceName}: built ${configName}`); + buildingInProgress = false; + resolve(); + }); + })); + } + } + + try { + await Promise.all(promises); + } catch (e) { + error = e.toString(); + } + + buildingInProgress = false; + currentBuildingModule = ''; + + if (error) { + cb(false, error); + } else cb(true); + }; + buildWebpack().then(); + } +}; + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +RegisterResourceBuildTaskFactory('z_webpack', () => webpackBuildTask); diff --git a/resources/[cfx-default]/[system]/[builders]/webpack/webpack_runner.js b/resources/[cfx-default]/[system]/[builders]/webpack/webpack_runner.js new file mode 100644 index 0000000..1c48687 --- /dev/null +++ b/resources/[cfx-default]/[system]/[builders]/webpack/webpack_runner.js @@ -0,0 +1,75 @@ +const webpack = require('webpack'); +const path = require('path'); +const fs = require('fs'); + +function getStat(path) { + try { + const stat = fs.statSync(path); + + return stat ? { + mtime: stat.mtimeMs, + size: stat.size, + inode: stat.ino, + } : null; + } catch { + return null; + } +} + +class SaveStatePlugin { + constructor(inp) { + this.cache = []; + this.cachePath = inp.cachePath; + } + + apply(compiler) { + compiler.hooks.afterCompile.tap('SaveStatePlugin', (compilation) => { + for (const file of compilation.fileDependencies) { + this.cache.push({ + name: file, + stats: getStat(file) + }); + } + }); + + compiler.hooks.done.tap('SaveStatePlugin', (stats) => { + if (stats.hasErrors()) { + return; + } + + fs.writeFile(this.cachePath, JSON.stringify(this.cache), () => { + + }); + }); + } +} + +module.exports = (inp, callback) => { + const config = require(inp.configPath); + + config.context = inp.resourcePath; + + if (config.output && config.output.path) { + config.output.path = path.resolve(inp.resourcePath, config.output.path); + } + + if (!config.plugins) { + config.plugins = []; + } + + config.plugins.push(new SaveStatePlugin(inp)); + + webpack(config, (err, stats) => { + if (err) { + callback(err); + return; + } + + if (stats.hasErrors()) { + callback(null, stats.toJson()); + return; + } + + callback(null, {}); + }); +}; \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/[builders]/yarn/fxmanifest.lua b/resources/[cfx-default]/[system]/[builders]/yarn/fxmanifest.lua new file mode 100644 index 0000000..24aeba8 --- /dev/null +++ b/resources/[cfx-default]/[system]/[builders]/yarn/fxmanifest.lua @@ -0,0 +1,12 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'Builds resources with yarn. To learn more: https://classic.yarnpkg.com' +repository 'https://github.com/citizenfx/cfx-server-data' + +fx_version 'adamant' +game 'common' + +server_script 'yarn_builder.js' diff --git a/resources/[cfx-default]/[system]/[builders]/yarn/yarn_builder.js b/resources/[cfx-default]/[system]/[builders]/yarn/yarn_builder.js new file mode 100644 index 0000000..002a8d0 --- /dev/null +++ b/resources/[cfx-default]/[system]/[builders]/yarn/yarn_builder.js @@ -0,0 +1,81 @@ +const path = require('path'); +const fs = require('fs'); +const child_process = require('child_process'); +let buildingInProgress = false; +let currentBuildingModule = ''; + +const initCwd = process.cwd(); +const trimOutput = (data) => { + return `[yarn]\t` + data.toString().replace(/\s+$/, ''); +} + +const yarnBuildTask = { + shouldBuild(resourceName) { + try { + const resourcePath = GetResourcePath(resourceName); + + const packageJson = path.resolve(resourcePath, 'package.json'); + const yarnLock = path.resolve(resourcePath, '.yarn.installed'); + + const packageStat = fs.statSync(packageJson); + + try { + const yarnStat = fs.statSync(yarnLock); + + if (packageStat.mtimeMs > yarnStat.mtimeMs) { + return true; + } + } catch (e) { + // no yarn.installed, but package.json - install time! + return true; + } + } catch (e) { + + } + + return false; + }, + + build(resourceName, cb) { + (async () => { + while (buildingInProgress && currentBuildingModule !== resourceName) { + console.log(`yarn is currently busy: we are waiting to compile ${resourceName}`); + await sleep(3000); + } + buildingInProgress = true; + currentBuildingModule = resourceName; + const proc = child_process.fork( + require.resolve('./yarn_cli.js'), + ['install', '--ignore-scripts', '--cache-folder', path.join(initCwd, 'cache', 'yarn-cache'), '--mutex', 'file:' + path.join(initCwd, 'cache', 'yarn-mutex')], + { + cwd: path.resolve(GetResourcePath(resourceName)), + stdio: 'pipe', + }); + proc.stdout.on('data', (data) => console.log(trimOutput(data))); + proc.stderr.on('data', (data) => console.error(trimOutput(data))); + proc.on('exit', (code, signal) => { + setImmediate(() => { + if (code != 0 || signal) { + buildingInProgress = false; + currentBuildingModule = ''; + cb(false, 'yarn failed!'); + return; + } + + const resourcePath = GetResourcePath(resourceName); + const yarnLock = path.resolve(resourcePath, '.yarn.installed'); + fs.writeFileSync(yarnLock, ''); + + buildingInProgress = false; + currentBuildingModule = ''; + cb(true); + }); + }); + })(); + } +}; + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} +RegisterResourceBuildTaskFactory('yarn', () => yarnBuildTask); diff --git a/resources/[cfx-default]/[system]/[builders]/yarn/yarn_cli.js b/resources/[cfx-default]/[system]/[builders]/yarn/yarn_cli.js new file mode 100644 index 0000000..d31be0b --- /dev/null +++ b/resources/[cfx-default]/[system]/[builders]/yarn/yarn_cli.js @@ -0,0 +1,147392 @@ +#!/usr/bin/env node +module.exports = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // identity function for calling harmony imports with the correct context +/******/ __webpack_require__.i = function(value) { return value; }; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 549); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +module.exports = require("path"); + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = __extends; +/* unused harmony export __assign */ +/* unused harmony export __rest */ +/* unused harmony export __decorate */ +/* unused harmony export __param */ +/* unused harmony export __metadata */ +/* unused harmony export __awaiter */ +/* unused harmony export __generator */ +/* unused harmony export __exportStar */ +/* unused harmony export __values */ +/* unused harmony export __read */ +/* unused harmony export __spread */ +/* unused harmony export __await */ +/* unused harmony export __asyncGenerator */ +/* unused harmony export __asyncDelegator */ +/* unused harmony export __asyncValues */ +/* unused harmony export __makeTemplateObject */ +/* unused harmony export __importStar */ +/* unused harmony export __importDefault */ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ +/* global Reflect, Promise */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + } + return __assign.apply(this, arguments); +} + +function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +} + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +function __param(paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +} + +function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +} + +function __awaiter(thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +function __exportStar(m, exports) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} + +function __values(o) { + var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + if (m) return m.call(o); + return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; +} + +function __read(o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +} + +function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; +} + +function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} + +function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +} + +function __asyncDelegator(o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } +} + +function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +} + +function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; + +function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result.default = mod; + return result; +} + +function __importDefault(mod) { + return (mod && mod.__esModule) ? mod : { default: mod }; +} + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +var _promise = __webpack_require__(227); + +var _promise2 = _interopRequireDefault(_promise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new _promise2.default(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return _promise2.default.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; +}; + +/***/ }), +/* 3 */ +/***/ (function(module, exports) { + +module.exports = require("util"); + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getFirstSuitableFolder = exports.readFirstAvailableStream = exports.makeTempDir = exports.hardlinksWork = exports.writeFilePreservingEol = exports.getFileSizeOnDisk = exports.walk = exports.symlink = exports.find = exports.readJsonAndFile = exports.readJson = exports.readFileAny = exports.hardlinkBulk = exports.copyBulk = exports.unlink = exports.glob = exports.link = exports.chmod = exports.lstat = exports.exists = exports.mkdirp = exports.stat = exports.access = exports.rename = exports.readdir = exports.realpath = exports.readlink = exports.writeFile = exports.open = exports.readFileBuffer = exports.lockQueue = exports.constants = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +let buildActionsForCopy = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { + + // + let build = (() => { + var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + const src = data.src, + dest = data.dest, + type = data.type; + + const onFresh = data.onFresh || noop; + const onDone = data.onDone || noop; + + // TODO https://github.com/yarnpkg/yarn/issues/3751 + // related to bundled dependencies handling + if (files.has(dest.toLowerCase())) { + reporter.verbose(`The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`); + } else { + files.add(dest.toLowerCase()); + } + + if (type === 'symlink') { + yield mkdirp((_path || _load_path()).default.dirname(dest)); + onFresh(); + actions.symlink.push({ + dest, + linkname: src + }); + onDone(); + return; + } + + if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { + // ignored file + return; + } + + const srcStat = yield lstat(src); + let srcFiles; + + if (srcStat.isDirectory()) { + srcFiles = yield readdir(src); + } + + let destStat; + try { + // try accessing the destination + destStat = yield lstat(dest); + } catch (e) { + // proceed if destination doesn't exist, otherwise error + if (e.code !== 'ENOENT') { + throw e; + } + } + + // if destination exists + if (destStat) { + const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); + const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); + const bothFiles = srcStat.isFile() && destStat.isFile(); + + // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving + // us modes that aren't valid. investigate this, it's generally safe to proceed. + + /* if (srcStat.mode !== destStat.mode) { + try { + await access(dest, srcStat.mode); + } catch (err) {} + } */ + + if (bothFiles && artifactFiles.has(dest)) { + // this file gets changed during build, likely by a custom install script. Don't bother checking it. + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); + return; + } + + if (bothFiles && srcStat.size === destStat.size && (0, (_fsNormalized || _load_fsNormalized()).fileDatesEqual)(srcStat.mtime, destStat.mtime)) { + // we can safely assume this is the same file + onDone(); + reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime)); + return; + } + + if (bothSymlinks) { + const srcReallink = yield readlink(src); + if (srcReallink === (yield readlink(dest))) { + // if both symlinks are the same then we can continue on + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); + return; + } + } + + if (bothFolders) { + // mark files that aren't in this folder as possibly extraneous + const destFiles = yield readdir(dest); + invariant(srcFiles, 'src files not initialised'); + + for (var _iterator4 = destFiles, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref6; + + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref6 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref6 = _i4.value; + } + + const file = _ref6; + + if (srcFiles.indexOf(file) < 0) { + const loc = (_path || _load_path()).default.join(dest, file); + possibleExtraneous.add(loc); + + if ((yield lstat(loc)).isDirectory()) { + for (var _iterator5 = yield readdir(loc), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref7; + + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref7 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref7 = _i5.value; + } + + const file = _ref7; + + possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); + } + } + } + } + } + } + + if (destStat && destStat.isSymbolicLink()) { + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); + destStat = null; + } + + if (srcStat.isSymbolicLink()) { + onFresh(); + const linkname = yield readlink(src); + actions.symlink.push({ + dest, + linkname + }); + onDone(); + } else if (srcStat.isDirectory()) { + if (!destStat) { + reporter.verbose(reporter.lang('verboseFileFolder', dest)); + yield mkdirp(dest); + } + + const destParts = dest.split((_path || _load_path()).default.sep); + while (destParts.length) { + files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); + destParts.pop(); + } + + // push all files to queue + invariant(srcFiles, 'src files not initialised'); + let remaining = srcFiles.length; + if (!remaining) { + onDone(); + } + for (var _iterator6 = srcFiles, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref8; + + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref8 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref8 = _i6.value; + } + + const file = _ref8; + + queue.push({ + dest: (_path || _load_path()).default.join(dest, file), + onFresh, + onDone: function (_onDone) { + function onDone() { + return _onDone.apply(this, arguments); + } + + onDone.toString = function () { + return _onDone.toString(); + }; + + return onDone; + }(function () { + if (--remaining === 0) { + onDone(); + } + }), + src: (_path || _load_path()).default.join(src, file) + }); + } + } else if (srcStat.isFile()) { + onFresh(); + actions.file.push({ + src, + dest, + atime: srcStat.atime, + mtime: srcStat.mtime, + mode: srcStat.mode + }); + onDone(); + } else { + throw new Error(`unsure how to copy this: ${src}`); + } + }); + + return function build(_x5) { + return _ref5.apply(this, arguments); + }; + })(); + + const artifactFiles = new Set(events.artifactFiles || []); + const files = new Set(); + + // initialise events + for (var _iterator = queue, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref2; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref2 = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref2 = _i.value; + } + + const item = _ref2; + + const onDone = item.onDone; + item.onDone = function () { + events.onProgress(item.dest); + if (onDone) { + onDone(); + } + }; + } + events.onStart(queue.length); + + // start building actions + const actions = { + file: [], + symlink: [], + link: [] + }; + + // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items + // at a time due to the requirement to push items onto the queue + while (queue.length) { + const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); + yield Promise.all(items.map(build)); + } + + // simulate the existence of some files to prevent considering them extraneous + for (var _iterator2 = artifactFiles, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref3; + + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref3 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref3 = _i2.value; + } + + const file = _ref3; + + if (possibleExtraneous.has(file)) { + reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); + possibleExtraneous.delete(file); + } + } + + for (var _iterator3 = possibleExtraneous, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref4; + + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref4 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref4 = _i3.value; + } + + const loc = _ref4; + + if (files.has(loc.toLowerCase())) { + possibleExtraneous.delete(loc); + } + } + + return actions; + }); + + return function buildActionsForCopy(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); + +let buildActionsForHardlink = (() => { + var _ref9 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { + + // + let build = (() => { + var _ref13 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + const src = data.src, + dest = data.dest; + + const onFresh = data.onFresh || noop; + const onDone = data.onDone || noop; + if (files.has(dest.toLowerCase())) { + // Fixes issue https://github.com/yarnpkg/yarn/issues/2734 + // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1, + // package-linker passes that modules A1 and B1 need to be hardlinked, + // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case + // an exception. + onDone(); + return; + } + files.add(dest.toLowerCase()); + + if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { + // ignored file + return; + } + + const srcStat = yield lstat(src); + let srcFiles; + + if (srcStat.isDirectory()) { + srcFiles = yield readdir(src); + } + + const destExists = yield exists(dest); + if (destExists) { + const destStat = yield lstat(dest); + + const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); + const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); + const bothFiles = srcStat.isFile() && destStat.isFile(); + + if (srcStat.mode !== destStat.mode) { + try { + yield access(dest, srcStat.mode); + } catch (err) { + // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving + // us modes that aren't valid. investigate this, it's generally safe to proceed. + reporter.verbose(err); + } + } + + if (bothFiles && artifactFiles.has(dest)) { + // this file gets changed during build, likely by a custom install script. Don't bother checking it. + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); + return; + } + + // correct hardlink + if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) { + onDone(); + reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino)); + return; + } + + if (bothSymlinks) { + const srcReallink = yield readlink(src); + if (srcReallink === (yield readlink(dest))) { + // if both symlinks are the same then we can continue on + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); + return; + } + } + + if (bothFolders) { + // mark files that aren't in this folder as possibly extraneous + const destFiles = yield readdir(dest); + invariant(srcFiles, 'src files not initialised'); + + for (var _iterator10 = destFiles, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref14; + + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref14 = _iterator10[_i10++]; + } else { + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref14 = _i10.value; + } + + const file = _ref14; + + if (srcFiles.indexOf(file) < 0) { + const loc = (_path || _load_path()).default.join(dest, file); + possibleExtraneous.add(loc); + + if ((yield lstat(loc)).isDirectory()) { + for (var _iterator11 = yield readdir(loc), _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref15; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref15 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref15 = _i11.value; + } + + const file = _ref15; + + possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); + } + } + } + } + } + } + + if (srcStat.isSymbolicLink()) { + onFresh(); + const linkname = yield readlink(src); + actions.symlink.push({ + dest, + linkname + }); + onDone(); + } else if (srcStat.isDirectory()) { + reporter.verbose(reporter.lang('verboseFileFolder', dest)); + yield mkdirp(dest); + + const destParts = dest.split((_path || _load_path()).default.sep); + while (destParts.length) { + files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); + destParts.pop(); + } + + // push all files to queue + invariant(srcFiles, 'src files not initialised'); + let remaining = srcFiles.length; + if (!remaining) { + onDone(); + } + for (var _iterator12 = srcFiles, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref16; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref16 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref16 = _i12.value; + } + + const file = _ref16; + + queue.push({ + onFresh, + src: (_path || _load_path()).default.join(src, file), + dest: (_path || _load_path()).default.join(dest, file), + onDone: function (_onDone2) { + function onDone() { + return _onDone2.apply(this, arguments); + } + + onDone.toString = function () { + return _onDone2.toString(); + }; + + return onDone; + }(function () { + if (--remaining === 0) { + onDone(); + } + }) + }); + } + } else if (srcStat.isFile()) { + onFresh(); + actions.link.push({ + src, + dest, + removeDest: destExists + }); + onDone(); + } else { + throw new Error(`unsure how to copy this: ${src}`); + } + }); + + return function build(_x10) { + return _ref13.apply(this, arguments); + }; + })(); + + const artifactFiles = new Set(events.artifactFiles || []); + const files = new Set(); + + // initialise events + for (var _iterator7 = queue, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref10; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref10 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref10 = _i7.value; + } + + const item = _ref10; + + const onDone = item.onDone || noop; + item.onDone = function () { + events.onProgress(item.dest); + onDone(); + }; + } + events.onStart(queue.length); + + // start building actions + const actions = { + file: [], + symlink: [], + link: [] + }; + + // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items + // at a time due to the requirement to push items onto the queue + while (queue.length) { + const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); + yield Promise.all(items.map(build)); + } + + // simulate the existence of some files to prevent considering them extraneous + for (var _iterator8 = artifactFiles, _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { + var _ref11; + + if (_isArray8) { + if (_i8 >= _iterator8.length) break; + _ref11 = _iterator8[_i8++]; + } else { + _i8 = _iterator8.next(); + if (_i8.done) break; + _ref11 = _i8.value; + } + + const file = _ref11; + + if (possibleExtraneous.has(file)) { + reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); + possibleExtraneous.delete(file); + } + } + + for (var _iterator9 = possibleExtraneous, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref12; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref12 = _iterator9[_i9++]; + } else { + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref12 = _i9.value; + } + + const loc = _ref12; + + if (files.has(loc.toLowerCase())) { + possibleExtraneous.delete(loc); + } + } + + return actions; + }); + + return function buildActionsForHardlink(_x6, _x7, _x8, _x9) { + return _ref9.apply(this, arguments); + }; +})(); + +let copyBulk = exports.copyBulk = (() => { + var _ref17 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { + const events = { + onStart: _events && _events.onStart || noop, + onProgress: _events && _events.onProgress || noop, + possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), + ignoreBasenames: _events && _events.ignoreBasenames || [], + artifactFiles: _events && _events.artifactFiles || [] + }; + + const actions = yield buildActionsForCopy(queue, events, events.possibleExtraneous, reporter); + events.onStart(actions.file.length + actions.symlink.length + actions.link.length); + + const fileActions = actions.file; + + const currentlyWriting = new Map(); + + yield (_promise || _load_promise()).queue(fileActions, (() => { + var _ref18 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + let writePromise; + while (writePromise = currentlyWriting.get(data.dest)) { + yield writePromise; + } + + reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest)); + const copier = (0, (_fsNormalized || _load_fsNormalized()).copyFile)(data, function () { + return currentlyWriting.delete(data.dest); + }); + currentlyWriting.set(data.dest, copier); + events.onProgress(data.dest); + return copier; + }); + + return function (_x14) { + return _ref18.apply(this, arguments); + }; + })(), CONCURRENT_QUEUE_ITEMS); + + // we need to copy symlinks last as they could reference files we were copying + const symlinkActions = actions.symlink; + yield (_promise || _load_promise()).queue(symlinkActions, function (data) { + const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); + reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); + return symlink(linkname, data.dest); + }); + }); + + return function copyBulk(_x11, _x12, _x13) { + return _ref17.apply(this, arguments); + }; +})(); + +let hardlinkBulk = exports.hardlinkBulk = (() => { + var _ref19 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { + const events = { + onStart: _events && _events.onStart || noop, + onProgress: _events && _events.onProgress || noop, + possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), + artifactFiles: _events && _events.artifactFiles || [], + ignoreBasenames: [] + }; + + const actions = yield buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter); + events.onStart(actions.file.length + actions.symlink.length + actions.link.length); + + const fileActions = actions.link; + + yield (_promise || _load_promise()).queue(fileActions, (() => { + var _ref20 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest)); + if (data.removeDest) { + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(data.dest); + } + yield link(data.src, data.dest); + }); + + return function (_x18) { + return _ref20.apply(this, arguments); + }; + })(), CONCURRENT_QUEUE_ITEMS); + + // we need to copy symlinks last as they could reference files we were copying + const symlinkActions = actions.symlink; + yield (_promise || _load_promise()).queue(symlinkActions, function (data) { + const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); + reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); + return symlink(linkname, data.dest); + }); + }); + + return function hardlinkBulk(_x15, _x16, _x17) { + return _ref19.apply(this, arguments); + }; +})(); + +let readFileAny = exports.readFileAny = (() => { + var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (files) { + for (var _iterator13 = files, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { + var _ref22; + + if (_isArray13) { + if (_i13 >= _iterator13.length) break; + _ref22 = _iterator13[_i13++]; + } else { + _i13 = _iterator13.next(); + if (_i13.done) break; + _ref22 = _i13.value; + } + + const file = _ref22; + + if (yield exists(file)) { + return readFile(file); + } + } + return null; + }); + + return function readFileAny(_x19) { + return _ref21.apply(this, arguments); + }; +})(); + +let readJson = exports.readJson = (() => { + var _ref23 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { + return (yield readJsonAndFile(loc)).object; + }); + + return function readJson(_x20) { + return _ref23.apply(this, arguments); + }; +})(); + +let readJsonAndFile = exports.readJsonAndFile = (() => { + var _ref24 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { + const file = yield readFile(loc); + try { + return { + object: (0, (_map || _load_map()).default)(JSON.parse(stripBOM(file))), + content: file + }; + } catch (err) { + err.message = `${loc}: ${err.message}`; + throw err; + } + }); + + return function readJsonAndFile(_x21) { + return _ref24.apply(this, arguments); + }; +})(); + +let find = exports.find = (() => { + var _ref25 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (filename, dir) { + const parts = dir.split((_path || _load_path()).default.sep); + + while (parts.length) { + const loc = parts.concat(filename).join((_path || _load_path()).default.sep); + + if (yield exists(loc)) { + return loc; + } else { + parts.pop(); + } + } + + return false; + }); + + return function find(_x22, _x23) { + return _ref25.apply(this, arguments); + }; +})(); + +let symlink = exports.symlink = (() => { + var _ref26 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (src, dest) { + if (process.platform !== 'win32') { + // use relative paths otherwise which will be retained if the directory is moved + src = (_path || _load_path()).default.relative((_path || _load_path()).default.dirname(dest), src); + // When path.relative returns an empty string for the current directory, we should instead use + // '.', which is a valid fs.symlink target. + src = src || '.'; + } + + try { + const stats = yield lstat(dest); + if (stats.isSymbolicLink()) { + const resolved = dest; + if (resolved === src) { + return; + } + } + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + } + + // We use rimraf for unlink which never throws an ENOENT on missing target + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); + + if (process.platform === 'win32') { + // use directory junctions if possible on win32, this requires absolute paths + yield fsSymlink(src, dest, 'junction'); + } else { + yield fsSymlink(src, dest); + } + }); + + return function symlink(_x24, _x25) { + return _ref26.apply(this, arguments); + }; +})(); + +let walk = exports.walk = (() => { + var _ref27 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir, relativeDir, ignoreBasenames = new Set()) { + let files = []; + + let filenames = yield readdir(dir); + if (ignoreBasenames.size) { + filenames = filenames.filter(function (name) { + return !ignoreBasenames.has(name); + }); + } + + for (var _iterator14 = filenames, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { + var _ref28; + + if (_isArray14) { + if (_i14 >= _iterator14.length) break; + _ref28 = _iterator14[_i14++]; + } else { + _i14 = _iterator14.next(); + if (_i14.done) break; + _ref28 = _i14.value; + } + + const name = _ref28; + + const relative = relativeDir ? (_path || _load_path()).default.join(relativeDir, name) : name; + const loc = (_path || _load_path()).default.join(dir, name); + const stat = yield lstat(loc); + + files.push({ + relative, + basename: name, + absolute: loc, + mtime: +stat.mtime + }); + + if (stat.isDirectory()) { + files = files.concat((yield walk(loc, relative, ignoreBasenames))); + } + } + + return files; + }); + + return function walk(_x26, _x27) { + return _ref27.apply(this, arguments); + }; +})(); + +let getFileSizeOnDisk = exports.getFileSizeOnDisk = (() => { + var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { + const stat = yield lstat(loc); + const size = stat.size, + blockSize = stat.blksize; + + + return Math.ceil(size / blockSize) * blockSize; + }); + + return function getFileSizeOnDisk(_x28) { + return _ref29.apply(this, arguments); + }; +})(); + +let getEolFromFile = (() => { + var _ref30 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path) { + if (!(yield exists(path))) { + return undefined; + } + + const buffer = yield readFileBuffer(path); + + for (let i = 0; i < buffer.length; ++i) { + if (buffer[i] === cr) { + return '\r\n'; + } + if (buffer[i] === lf) { + return '\n'; + } + } + return undefined; + }); + + return function getEolFromFile(_x29) { + return _ref30.apply(this, arguments); + }; +})(); + +let writeFilePreservingEol = exports.writeFilePreservingEol = (() => { + var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path, data) { + const eol = (yield getEolFromFile(path)) || (_os || _load_os()).default.EOL; + if (eol !== '\n') { + data = data.replace(/\n/g, eol); + } + yield writeFile(path, data); + }); + + return function writeFilePreservingEol(_x30, _x31) { + return _ref31.apply(this, arguments); + }; +})(); + +let hardlinksWork = exports.hardlinksWork = (() => { + var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir) { + const filename = 'test-file' + Math.random(); + const file = (_path || _load_path()).default.join(dir, filename); + const fileLink = (_path || _load_path()).default.join(dir, filename + '-link'); + try { + yield writeFile(file, 'test'); + yield link(file, fileLink); + } catch (err) { + return false; + } finally { + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(file); + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(fileLink); + } + return true; + }); + + return function hardlinksWork(_x32) { + return _ref32.apply(this, arguments); + }; +})(); + +// not a strict polyfill for Node's fs.mkdtemp + + +let makeTempDir = exports.makeTempDir = (() => { + var _ref33 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (prefix) { + const dir = (_path || _load_path()).default.join((_os || _load_os()).default.tmpdir(), `yarn-${prefix || ''}-${Date.now()}-${Math.random()}`); + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dir); + yield mkdirp(dir); + return dir; + }); + + return function makeTempDir(_x33) { + return _ref33.apply(this, arguments); + }; +})(); + +let readFirstAvailableStream = exports.readFirstAvailableStream = (() => { + var _ref34 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths) { + for (var _iterator15 = paths, _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { + var _ref35; + + if (_isArray15) { + if (_i15 >= _iterator15.length) break; + _ref35 = _iterator15[_i15++]; + } else { + _i15 = _iterator15.next(); + if (_i15.done) break; + _ref35 = _i15.value; + } + + const path = _ref35; + + try { + const fd = yield open(path, 'r'); + return (_fs || _load_fs()).default.createReadStream(path, { fd }); + } catch (err) { + // Try the next one + } + } + return null; + }); + + return function readFirstAvailableStream(_x34) { + return _ref34.apply(this, arguments); + }; +})(); + +let getFirstSuitableFolder = exports.getFirstSuitableFolder = (() => { + var _ref36 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths, mode = constants.W_OK | constants.X_OK) { + const result = { + skipped: [], + folder: null + }; + + for (var _iterator16 = paths, _isArray16 = Array.isArray(_iterator16), _i16 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) { + var _ref37; + + if (_isArray16) { + if (_i16 >= _iterator16.length) break; + _ref37 = _iterator16[_i16++]; + } else { + _i16 = _iterator16.next(); + if (_i16.done) break; + _ref37 = _i16.value; + } + + const folder = _ref37; + + try { + yield mkdirp(folder); + yield access(folder, mode); + + result.folder = folder; + + return result; + } catch (error) { + result.skipped.push({ + error, + folder + }); + } + } + return result; + }); + + return function getFirstSuitableFolder(_x35) { + return _ref36.apply(this, arguments); + }; +})(); + +exports.copy = copy; +exports.readFile = readFile; +exports.readFileRaw = readFileRaw; +exports.normalizeOS = normalizeOS; + +var _fs; + +function _load_fs() { + return _fs = _interopRequireDefault(__webpack_require__(5)); +} + +var _glob; + +function _load_glob() { + return _glob = _interopRequireDefault(__webpack_require__(99)); +} + +var _os; + +function _load_os() { + return _os = _interopRequireDefault(__webpack_require__(46)); +} + +var _path; + +function _load_path() { + return _path = _interopRequireDefault(__webpack_require__(0)); +} + +var _blockingQueue; + +function _load_blockingQueue() { + return _blockingQueue = _interopRequireDefault(__webpack_require__(110)); +} + +var _promise; + +function _load_promise() { + return _promise = _interopRequireWildcard(__webpack_require__(50)); +} + +var _promise2; + +function _load_promise2() { + return _promise2 = __webpack_require__(50); +} + +var _map; + +function _load_map() { + return _map = _interopRequireDefault(__webpack_require__(29)); +} + +var _fsNormalized; + +function _load_fsNormalized() { + return _fsNormalized = __webpack_require__(218); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const constants = exports.constants = typeof (_fs || _load_fs()).default.constants !== 'undefined' ? (_fs || _load_fs()).default.constants : { + R_OK: (_fs || _load_fs()).default.R_OK, + W_OK: (_fs || _load_fs()).default.W_OK, + X_OK: (_fs || _load_fs()).default.X_OK +}; + +const lockQueue = exports.lockQueue = new (_blockingQueue || _load_blockingQueue()).default('fs lock'); + +const readFileBuffer = exports.readFileBuffer = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readFile); +const open = exports.open = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.open); +const writeFile = exports.writeFile = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.writeFile); +const readlink = exports.readlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readlink); +const realpath = exports.realpath = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.realpath); +const readdir = exports.readdir = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readdir); +const rename = exports.rename = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.rename); +const access = exports.access = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.access); +const stat = exports.stat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.stat); +const mkdirp = exports.mkdirp = (0, (_promise2 || _load_promise2()).promisify)(__webpack_require__(145)); +const exists = exports.exists = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.exists, true); +const lstat = exports.lstat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.lstat); +const chmod = exports.chmod = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.chmod); +const link = exports.link = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.link); +const glob = exports.glob = (0, (_promise2 || _load_promise2()).promisify)((_glob || _load_glob()).default); +exports.unlink = (_fsNormalized || _load_fsNormalized()).unlink; + +// fs.copyFile uses the native file copying instructions on the system, performing much better +// than any JS-based solution and consumes fewer resources. Repeated testing to fine tune the +// concurrency level revealed 128 as the sweet spot on a quad-core, 16 CPU Intel system with SSD. + +const CONCURRENT_QUEUE_ITEMS = (_fs || _load_fs()).default.copyFile ? 128 : 4; + +const fsSymlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.symlink); +const invariant = __webpack_require__(9); +const stripBOM = __webpack_require__(160); + +const noop = () => {}; + +function copy(src, dest, reporter) { + return copyBulk([{ src, dest }], reporter); +} + +function _readFile(loc, encoding) { + return new Promise((resolve, reject) => { + (_fs || _load_fs()).default.readFile(loc, encoding, function (err, content) { + if (err) { + reject(err); + } else { + resolve(content); + } + }); + }); +} + +function readFile(loc) { + return _readFile(loc, 'utf8').then(normalizeOS); +} + +function readFileRaw(loc) { + return _readFile(loc, 'binary'); +} + +function normalizeOS(body) { + return body.replace(/\r\n/g, '\n'); +} + +const cr = '\r'.charCodeAt(0); +const lf = '\n'.charCodeAt(0); + +/***/ }), +/* 5 */ +/***/ (function(module, exports) { + +module.exports = require("fs"); + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +class MessageError extends Error { + constructor(msg, code) { + super(msg); + this.code = code; + } + +} + +exports.MessageError = MessageError; +class ProcessSpawnError extends MessageError { + constructor(msg, code, process) { + super(msg, code); + this.process = process; + } + +} + +exports.ProcessSpawnError = ProcessSpawnError; +class SecurityError extends MessageError {} + +exports.SecurityError = SecurityError; +class ProcessTermError extends MessageError {} + +exports.ProcessTermError = ProcessTermError; +class ResponseError extends Error { + constructor(msg, responseCode) { + super(msg); + this.responseCode = responseCode; + } + +} + +exports.ResponseError = ResponseError; +class OneTimePasswordError extends Error {} +exports.OneTimePasswordError = OneTimePasswordError; + +/***/ }), +/* 7 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscriber; }); +/* unused harmony export SafeSubscriber */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isFunction__ = __webpack_require__(154); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Observer__ = __webpack_require__(420); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__ = __webpack_require__(321); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__config__ = __webpack_require__(185); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__ = __webpack_require__(323); +/** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */ + + + + + + + +var Subscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subscriber, _super); + function Subscriber(destinationOrNext, error, complete) { + var _this = _super.call(this) || this; + _this.syncErrorValue = null; + _this.syncErrorThrown = false; + _this.syncErrorThrowable = false; + _this.isStopped = false; + _this._parentSubscription = null; + switch (arguments.length) { + case 0: + _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; + break; + case 1: + if (!destinationOrNext) { + _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; + break; + } + if (typeof destinationOrNext === 'object') { + if (destinationOrNext instanceof Subscriber) { + _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable; + _this.destination = destinationOrNext; + destinationOrNext.add(_this); + } + else { + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext); + } + break; + } + default: + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete); + break; + } + return _this; + } + Subscriber.prototype[__WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { return this; }; + Subscriber.create = function (next, error, complete) { + var subscriber = new Subscriber(next, error, complete); + subscriber.syncErrorThrowable = false; + return subscriber; + }; + Subscriber.prototype.next = function (value) { + if (!this.isStopped) { + this._next(value); + } + }; + Subscriber.prototype.error = function (err) { + if (!this.isStopped) { + this.isStopped = true; + this._error(err); + } + }; + Subscriber.prototype.complete = function () { + if (!this.isStopped) { + this.isStopped = true; + this._complete(); + } + }; + Subscriber.prototype.unsubscribe = function () { + if (this.closed) { + return; + } + this.isStopped = true; + _super.prototype.unsubscribe.call(this); + }; + Subscriber.prototype._next = function (value) { + this.destination.next(value); + }; + Subscriber.prototype._error = function (err) { + this.destination.error(err); + this.unsubscribe(); + }; + Subscriber.prototype._complete = function () { + this.destination.complete(); + this.unsubscribe(); + }; + Subscriber.prototype._unsubscribeAndRecycle = function () { + var _a = this, _parent = _a._parent, _parents = _a._parents; + this._parent = null; + this._parents = null; + this.unsubscribe(); + this.closed = false; + this.isStopped = false; + this._parent = _parent; + this._parents = _parents; + this._parentSubscription = null; + return this; + }; + return Subscriber; +}(__WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */])); + +var SafeSubscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SafeSubscriber, _super); + function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) { + var _this = _super.call(this) || this; + _this._parentSubscriber = _parentSubscriber; + var next; + var context = _this; + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(observerOrNext)) { + next = observerOrNext; + } + else if (observerOrNext) { + next = observerOrNext.next; + error = observerOrNext.error; + complete = observerOrNext.complete; + if (observerOrNext !== __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]) { + context = Object.create(observerOrNext); + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(context.unsubscribe)) { + _this.add(context.unsubscribe.bind(context)); + } + context.unsubscribe = _this.unsubscribe.bind(_this); + } + } + _this._context = context; + _this._next = next; + _this._error = error; + _this._complete = complete; + return _this; + } + SafeSubscriber.prototype.next = function (value) { + if (!this.isStopped && this._next) { + var _parentSubscriber = this._parentSubscriber; + if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._next, value); + } + else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + var useDeprecatedSynchronousErrorHandling = __WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling; + if (this._error) { + if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._error, err); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, this._error, err); + this.unsubscribe(); + } + } + else if (!_parentSubscriber.syncErrorThrowable) { + this.unsubscribe(); + if (useDeprecatedSynchronousErrorHandling) { + throw err; + } + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + } + else { + if (useDeprecatedSynchronousErrorHandling) { + _parentSubscriber.syncErrorValue = err; + _parentSubscriber.syncErrorThrown = true; + } + else { + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + } + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.complete = function () { + var _this = this; + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + if (this._complete) { + var wrappedComplete = function () { return _this._complete.call(_this._context); }; + if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(wrappedComplete); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, wrappedComplete); + this.unsubscribe(); + } + } + else { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) { + try { + fn.call(this._context, value); + } + catch (err) { + this.unsubscribe(); + if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + throw err; + } + else { + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + } + } + }; + SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) { + if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + throw new Error('bad call'); + } + try { + fn.call(this._context, value); + } + catch (err) { + if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + parent.syncErrorValue = err; + parent.syncErrorThrown = true; + return true; + } + else { + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + return true; + } + } + return false; + }; + SafeSubscriber.prototype._unsubscribe = function () { + var _parentSubscriber = this._parentSubscriber; + this._context = null; + this._parentSubscriber = null; + _parentSubscriber.unsubscribe(); + }; + return SafeSubscriber; +}(Subscriber)); + +//# sourceMappingURL=Subscriber.js.map + + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getPathKey = getPathKey; +const os = __webpack_require__(46); +const path = __webpack_require__(0); +const userHome = __webpack_require__(67).default; + +var _require = __webpack_require__(225); + +const getCacheDir = _require.getCacheDir, + getConfigDir = _require.getConfigDir, + getDataDir = _require.getDataDir; + +const isWebpackBundle = __webpack_require__(278); + +const DEPENDENCY_TYPES = exports.DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies', 'peerDependencies']; +const OWNED_DEPENDENCY_TYPES = exports.OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies']; + +const RESOLUTIONS = exports.RESOLUTIONS = 'resolutions'; +const MANIFEST_FIELDS = exports.MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]; + +const SUPPORTED_NODE_VERSIONS = exports.SUPPORTED_NODE_VERSIONS = '^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.0'; + +const YARN_REGISTRY = exports.YARN_REGISTRY = 'https://registry.yarnpkg.com'; +const NPM_REGISTRY_RE = exports.NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g; + +const YARN_DOCS = exports.YARN_DOCS = 'https://yarnpkg.com/en/docs/cli/'; +const YARN_INSTALLER_SH = exports.YARN_INSTALLER_SH = 'https://yarnpkg.com/install.sh'; +const YARN_INSTALLER_MSI = exports.YARN_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi'; + +const SELF_UPDATE_VERSION_URL = exports.SELF_UPDATE_VERSION_URL = 'https://yarnpkg.com/latest-version'; + +// cache version, bump whenever we make backwards incompatible changes +const CACHE_VERSION = exports.CACHE_VERSION = 6; + +// lockfile version, bump whenever we make backwards incompatible changes +const LOCKFILE_VERSION = exports.LOCKFILE_VERSION = 1; + +// max amount of network requests to perform concurrently +const NETWORK_CONCURRENCY = exports.NETWORK_CONCURRENCY = 8; + +// HTTP timeout used when downloading packages +const NETWORK_TIMEOUT = exports.NETWORK_TIMEOUT = 30 * 1000; // in milliseconds + +// max amount of child processes to execute concurrently +const CHILD_CONCURRENCY = exports.CHILD_CONCURRENCY = 5; + +const REQUIRED_PACKAGE_KEYS = exports.REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid']; + +function getPreferredCacheDirectories() { + const preferredCacheDirectories = [getCacheDir()]; + + if (process.getuid) { + // $FlowFixMe: process.getuid exists, dammit + preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache-${process.getuid()}`)); + } + + preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache`)); + + return preferredCacheDirectories; +} + +const PREFERRED_MODULE_CACHE_DIRECTORIES = exports.PREFERRED_MODULE_CACHE_DIRECTORIES = getPreferredCacheDirectories(); +const CONFIG_DIRECTORY = exports.CONFIG_DIRECTORY = getConfigDir(); +const DATA_DIRECTORY = exports.DATA_DIRECTORY = getDataDir(); +const LINK_REGISTRY_DIRECTORY = exports.LINK_REGISTRY_DIRECTORY = path.join(DATA_DIRECTORY, 'link'); +const GLOBAL_MODULE_DIRECTORY = exports.GLOBAL_MODULE_DIRECTORY = path.join(DATA_DIRECTORY, 'global'); + +const NODE_BIN_PATH = exports.NODE_BIN_PATH = process.execPath; +const YARN_BIN_PATH = exports.YARN_BIN_PATH = getYarnBinPath(); + +// Webpack needs to be configured with node.__dirname/__filename = false +function getYarnBinPath() { + if (isWebpackBundle) { + return __filename; + } else { + return path.join(__dirname, '..', 'bin', 'yarn.js'); + } +} + +const NODE_MODULES_FOLDER = exports.NODE_MODULES_FOLDER = 'node_modules'; +const NODE_PACKAGE_JSON = exports.NODE_PACKAGE_JSON = 'package.json'; + +const PNP_FILENAME = exports.PNP_FILENAME = '.pnp.js'; + +const POSIX_GLOBAL_PREFIX = exports.POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`; +const FALLBACK_GLOBAL_PREFIX = exports.FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.yarn'); + +const META_FOLDER = exports.META_FOLDER = '.yarn-meta'; +const INTEGRITY_FILENAME = exports.INTEGRITY_FILENAME = '.yarn-integrity'; +const LOCKFILE_FILENAME = exports.LOCKFILE_FILENAME = 'yarn.lock'; +const METADATA_FILENAME = exports.METADATA_FILENAME = '.yarn-metadata.json'; +const TARBALL_FILENAME = exports.TARBALL_FILENAME = '.yarn-tarball.tgz'; +const CLEAN_FILENAME = exports.CLEAN_FILENAME = '.yarnclean'; + +const NPM_LOCK_FILENAME = exports.NPM_LOCK_FILENAME = 'package-lock.json'; +const NPM_SHRINKWRAP_FILENAME = exports.NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json'; + +const DEFAULT_INDENT = exports.DEFAULT_INDENT = ' '; +const SINGLE_INSTANCE_PORT = exports.SINGLE_INSTANCE_PORT = 31997; +const SINGLE_INSTANCE_FILENAME = exports.SINGLE_INSTANCE_FILENAME = '.yarn-single-instance'; + +const ENV_PATH_KEY = exports.ENV_PATH_KEY = getPathKey(process.platform, process.env); + +function getPathKey(platform, env) { + let pathKey = 'PATH'; + + // windows calls its path "Path" usually, but this is not guaranteed. + if (platform === 'win32') { + pathKey = 'Path'; + + for (const key in env) { + if (key.toLowerCase() === 'path') { + pathKey = key; + } + } + } + + return pathKey; +} + +const VERSION_COLOR_SCHEME = exports.VERSION_COLOR_SCHEME = { + major: 'red', + premajor: 'red', + minor: 'yellow', + preminor: 'yellow', + patch: 'green', + prepatch: 'green', + prerelease: 'red', + unchanged: 'white', + unknown: 'red' +}; + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + + +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + +var NODE_ENV = process.env.NODE_ENV; + +var invariant = function(condition, format, a, b, c, d, e, f) { + if (NODE_ENV !== 'production') { + if (format === undefined) { + throw new Error('invariant requires an error message argument'); + } + } + + if (!condition) { + var error; + if (format === undefined) { + error = new Error( + 'Minified exception occurred; use the non-minified dev environment ' + + 'for the full error message and additional helpful warnings.' + ); + } else { + var args = [a, b, c, d, e, f]; + var argIndex = 0; + error = new Error( + format.replace(/%s/g, function() { return args[argIndex++]; }) + ); + error.name = 'Invariant Violation'; + } + + error.framesToPop = 1; // we don't care about invariant's own frame + throw error; + } +}; + +module.exports = invariant; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var YAMLException = __webpack_require__(54); + +var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'defaultStyle', + 'styleAliases' +]; + +var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' +]; + +function compileStyleAliases(map) { + var result = {}; + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } + + return result; +} + +function Type(tag, options) { + options = options || {}; + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } +} + +module.exports = Type; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports) { + +module.exports = require("crypto"); + +/***/ }), +/* 12 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Observable; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_canReportError__ = __webpack_require__(322); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__ = __webpack_require__(932); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__ = __webpack_require__(117); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_pipe__ = __webpack_require__(324); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__config__ = __webpack_require__(185); +/** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_internal_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */ + + + + + +var Observable = /*@__PURE__*/ (function () { + function Observable(subscribe) { + this._isScalar = false; + if (subscribe) { + this._subscribe = subscribe; + } + } + Observable.prototype.lift = function (operator) { + var observable = new Observable(); + observable.source = this; + observable.operator = operator; + return observable; + }; + Observable.prototype.subscribe = function (observerOrNext, error, complete) { + var operator = this.operator; + var sink = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__["a" /* toSubscriber */])(observerOrNext, error, complete); + if (operator) { + operator.call(sink, this.source); + } + else { + sink.add(this.source || (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ? + this._subscribe(sink) : + this._trySubscribe(sink)); + } + if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + if (sink.syncErrorThrowable) { + sink.syncErrorThrowable = false; + if (sink.syncErrorThrown) { + throw sink.syncErrorValue; + } + } + } + return sink; + }; + Observable.prototype._trySubscribe = function (sink) { + try { + return this._subscribe(sink); + } + catch (err) { + if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + sink.syncErrorThrown = true; + sink.syncErrorValue = err; + } + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_canReportError__["a" /* canReportError */])(sink)) { + sink.error(err); + } + else { + console.warn(err); + } + } + }; + Observable.prototype.forEach = function (next, promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var subscription; + subscription = _this.subscribe(function (value) { + try { + next(value); + } + catch (err) { + reject(err); + if (subscription) { + subscription.unsubscribe(); + } + } + }, reject, resolve); + }); + }; + Observable.prototype._subscribe = function (subscriber) { + var source = this.source; + return source && source.subscribe(subscriber); + }; + Observable.prototype[__WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__["a" /* observable */]] = function () { + return this; + }; + Observable.prototype.pipe = function () { + var operations = []; + for (var _i = 0; _i < arguments.length; _i++) { + operations[_i] = arguments[_i]; + } + if (operations.length === 0) { + return this; + } + return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_pipe__["b" /* pipeFromArray */])(operations)(this); + }; + Observable.prototype.toPromise = function (promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var value; + _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); }); + }); + }; + Observable.create = function (subscribe) { + return new Observable(subscribe); + }; + return Observable; +}()); + +function getPromiseCtor(promiseCtor) { + if (!promiseCtor) { + promiseCtor = __WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].Promise || Promise; + } + if (!promiseCtor) { + throw new Error('no Promise impl found'); + } + return promiseCtor; +} +//# sourceMappingURL=Observable.js.map + + +/***/ }), +/* 13 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return OuterSubscriber; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subscriber__ = __webpack_require__(7); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + + +var OuterSubscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](OuterSubscriber, _super); + function OuterSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; + } + OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.destination.next(innerValue); + }; + OuterSubscriber.prototype.notifyError = function (error, innerSub) { + this.destination.error(error); + }; + OuterSubscriber.prototype.notifyComplete = function (innerSub) { + this.destination.complete(); + }; + return OuterSubscriber; +}(__WEBPACK_IMPORTED_MODULE_1__Subscriber__["a" /* Subscriber */])); + +//# sourceMappingURL=OuterSubscriber.js.map + + +/***/ }), +/* 14 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = subscribeToResult; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__ = __webpack_require__(84); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__subscribeTo__ = __webpack_require__(446); +/** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo PURE_IMPORTS_END */ + + +function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, destination) { + if (destination === void 0) { + destination = new __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__["a" /* InnerSubscriber */](outerSubscriber, outerValue, outerIndex); + } + if (destination.closed) { + return; + } + return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__subscribeTo__["a" /* subscribeTo */])(result)(destination); +} +//# sourceMappingURL=subscribeToResult.js.map + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* eslint-disable node/no-deprecated-api */ + + + +var buffer = __webpack_require__(64) +var Buffer = buffer.Buffer + +var safer = {} + +var key + +for (key in buffer) { + if (!buffer.hasOwnProperty(key)) continue + if (key === 'SlowBuffer' || key === 'Buffer') continue + safer[key] = buffer[key] +} + +var Safer = safer.Buffer = {} +for (key in Buffer) { + if (!Buffer.hasOwnProperty(key)) continue + if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue + Safer[key] = Buffer[key] +} + +safer.Buffer.prototype = Buffer.prototype + +if (!Safer.from || Safer.from === Uint8Array.from) { + Safer.from = function (value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('The "value" argument must not be of type number. Received type ' + typeof value) + } + if (value && typeof value.length === 'undefined') { + throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value) + } + return Buffer(value, encodingOrOffset, length) + } +} + +if (!Safer.alloc) { + Safer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) + } + if (size < 0 || size >= 2 * (1 << 30)) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } + var buf = Buffer(size) + if (!fill || fill.length === 0) { + buf.fill(0) + } else if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + return buf + } +} + +if (!safer.kStringMaxLength) { + try { + safer.kStringMaxLength = process.binding('buffer').kStringMaxLength + } catch (e) { + // we can't determine kStringMaxLength in environments where process.binding + // is unsupported, so let's not set it + } +} + +if (!safer.constants) { + safer.constants = { + MAX_LENGTH: safer.kMaxLength + } + if (safer.kStringMaxLength) { + safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength + } +} + +module.exports = safer + + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright (c) 2012, Mark Cavage. All rights reserved. +// Copyright 2015 Joyent, Inc. + +var assert = __webpack_require__(28); +var Stream = __webpack_require__(23).Stream; +var util = __webpack_require__(3); + + +///--- Globals + +/* JSSTYLED */ +var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/; + + +///--- Internal + +function _capitalize(str) { + return (str.charAt(0).toUpperCase() + str.slice(1)); +} + +function _toss(name, expected, oper, arg, actual) { + throw new assert.AssertionError({ + message: util.format('%s (%s) is required', name, expected), + actual: (actual === undefined) ? typeof (arg) : actual(arg), + expected: expected, + operator: oper || '===', + stackStartFunction: _toss.caller + }); +} + +function _getClass(arg) { + return (Object.prototype.toString.call(arg).slice(8, -1)); +} + +function noop() { + // Why even bother with asserts? +} + + +///--- Exports + +var types = { + bool: { + check: function (arg) { return typeof (arg) === 'boolean'; } + }, + func: { + check: function (arg) { return typeof (arg) === 'function'; } + }, + string: { + check: function (arg) { return typeof (arg) === 'string'; } + }, + object: { + check: function (arg) { + return typeof (arg) === 'object' && arg !== null; + } + }, + number: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg); + } + }, + finite: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg); + } + }, + buffer: { + check: function (arg) { return Buffer.isBuffer(arg); }, + operator: 'Buffer.isBuffer' + }, + array: { + check: function (arg) { return Array.isArray(arg); }, + operator: 'Array.isArray' + }, + stream: { + check: function (arg) { return arg instanceof Stream; }, + operator: 'instanceof', + actual: _getClass + }, + date: { + check: function (arg) { return arg instanceof Date; }, + operator: 'instanceof', + actual: _getClass + }, + regexp: { + check: function (arg) { return arg instanceof RegExp; }, + operator: 'instanceof', + actual: _getClass + }, + uuid: { + check: function (arg) { + return typeof (arg) === 'string' && UUID_REGEXP.test(arg); + }, + operator: 'isUUID' + } +}; + +function _setExports(ndebug) { + var keys = Object.keys(types); + var out; + + /* re-export standard assert */ + if (process.env.NODE_NDEBUG) { + out = noop; + } else { + out = function (arg, msg) { + if (!arg) { + _toss(msg, 'true', arg); + } + }; + } + + /* standard checks */ + keys.forEach(function (k) { + if (ndebug) { + out[k] = noop; + return; + } + var type = types[k]; + out[k] = function (arg, msg) { + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* optional checks */ + keys.forEach(function (k) { + var name = 'optional' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* arrayOf checks */ + keys.forEach(function (k) { + var name = 'arrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* optionalArrayOf checks */ + keys.forEach(function (k) { + var name = 'optionalArrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* re-export built-in assertions */ + Object.keys(assert).forEach(function (k) { + if (k === 'AssertionError') { + out[k] = assert[k]; + return; + } + if (ndebug) { + out[k] = noop; + return; + } + out[k] = assert[k]; + }); + + /* export ourselves (for unit tests _only_) */ + out._setExports = _setExports; + + return out; +} + +module.exports = _setExports(process.env.NODE_NDEBUG); + + +/***/ }), +/* 17 */ +/***/ (function(module, exports) { + +// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 +var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self + // eslint-disable-next-line no-new-func + : Function('return this')(); +if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef + + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.sortAlpha = sortAlpha; +exports.sortOptionsByFlags = sortOptionsByFlags; +exports.entries = entries; +exports.removePrefix = removePrefix; +exports.removeSuffix = removeSuffix; +exports.addSuffix = addSuffix; +exports.hyphenate = hyphenate; +exports.camelCase = camelCase; +exports.compareSortedArrays = compareSortedArrays; +exports.sleep = sleep; +const _camelCase = __webpack_require__(230); + +function sortAlpha(a, b) { + // sort alphabetically in a deterministic way + const shortLen = Math.min(a.length, b.length); + for (let i = 0; i < shortLen; i++) { + const aChar = a.charCodeAt(i); + const bChar = b.charCodeAt(i); + if (aChar !== bChar) { + return aChar - bChar; + } + } + return a.length - b.length; +} + +function sortOptionsByFlags(a, b) { + const aOpt = a.flags.replace(/-/g, ''); + const bOpt = b.flags.replace(/-/g, ''); + return sortAlpha(aOpt, bOpt); +} + +function entries(obj) { + const entries = []; + if (obj) { + for (const key in obj) { + entries.push([key, obj[key]]); + } + } + return entries; +} + +function removePrefix(pattern, prefix) { + if (pattern.startsWith(prefix)) { + pattern = pattern.slice(prefix.length); + } + + return pattern; +} + +function removeSuffix(pattern, suffix) { + if (pattern.endsWith(suffix)) { + return pattern.slice(0, -suffix.length); + } + + return pattern; +} + +function addSuffix(pattern, suffix) { + if (!pattern.endsWith(suffix)) { + return pattern + suffix; + } + + return pattern; +} + +function hyphenate(str) { + return str.replace(/[A-Z]/g, match => { + return '-' + match.charAt(0).toLowerCase(); + }); +} + +function camelCase(str) { + if (/[A-Z]/.test(str)) { + return null; + } else { + return _camelCase(str); + } +} + +function compareSortedArrays(array1, array2) { + if (array1.length !== array2.length) { + return false; + } + for (let i = 0, len = array1.length; i < len; i++) { + if (array1[i] !== array2[i]) { + return false; + } + } + return true; +} + +function sleep(ms) { + return new Promise(resolve => { + setTimeout(resolve, ms); + }); +} + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.stringify = exports.parse = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +var _parse; + +function _load_parse() { + return _parse = __webpack_require__(105); +} + +Object.defineProperty(exports, 'parse', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_parse || _load_parse()).default; + } +}); + +var _stringify; + +function _load_stringify() { + return _stringify = __webpack_require__(199); +} + +Object.defineProperty(exports, 'stringify', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_stringify || _load_stringify()).default; + } +}); +exports.implodeEntry = implodeEntry; +exports.explodeEntry = explodeEntry; + +var _misc; + +function _load_misc() { + return _misc = __webpack_require__(18); +} + +var _normalizePattern; + +function _load_normalizePattern() { + return _normalizePattern = __webpack_require__(37); +} + +var _parse2; + +function _load_parse2() { + return _parse2 = _interopRequireDefault(__webpack_require__(105)); +} + +var _constants; + +function _load_constants() { + return _constants = __webpack_require__(8); +} + +var _fs; + +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(4)); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const invariant = __webpack_require__(9); + +const path = __webpack_require__(0); +const ssri = __webpack_require__(65); + +function getName(pattern) { + return (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern).name; +} + +function blankObjectUndefined(obj) { + return obj && Object.keys(obj).length ? obj : undefined; +} + +function keyForRemote(remote) { + return remote.resolved || (remote.reference && remote.hash ? `${remote.reference}#${remote.hash}` : null); +} + +function serializeIntegrity(integrity) { + // We need this because `Integrity.toString()` does not use sorting to ensure a stable string output + // See https://git.io/vx2Hy + return integrity.toString().split(' ').sort().join(' '); +} + +function implodeEntry(pattern, obj) { + const inferredName = getName(pattern); + const integrity = obj.integrity ? serializeIntegrity(obj.integrity) : ''; + const imploded = { + name: inferredName === obj.name ? undefined : obj.name, + version: obj.version, + uid: obj.uid === obj.version ? undefined : obj.uid, + resolved: obj.resolved, + registry: obj.registry === 'npm' ? undefined : obj.registry, + dependencies: blankObjectUndefined(obj.dependencies), + optionalDependencies: blankObjectUndefined(obj.optionalDependencies), + permissions: blankObjectUndefined(obj.permissions), + prebuiltVariants: blankObjectUndefined(obj.prebuiltVariants) + }; + if (integrity) { + imploded.integrity = integrity; + } + return imploded; +} + +function explodeEntry(pattern, obj) { + obj.optionalDependencies = obj.optionalDependencies || {}; + obj.dependencies = obj.dependencies || {}; + obj.uid = obj.uid || obj.version; + obj.permissions = obj.permissions || {}; + obj.registry = obj.registry || 'npm'; + obj.name = obj.name || getName(pattern); + const integrity = obj.integrity; + if (integrity && integrity.isIntegrity) { + obj.integrity = ssri.parse(integrity); + } + return obj; +} + +class Lockfile { + constructor({ cache, source, parseResultType } = {}) { + this.source = source || ''; + this.cache = cache; + this.parseResultType = parseResultType; + } + + // source string if the `cache` was parsed + + + // if true, we're parsing an old yarn file and need to update integrity fields + hasEntriesExistWithoutIntegrity() { + if (!this.cache) { + return false; + } + + for (const key in this.cache) { + // $FlowFixMe - `this.cache` is clearly defined at this point + if (!/^.*@(file:|http)/.test(key) && this.cache[key] && !this.cache[key].integrity) { + return true; + } + } + + return false; + } + + static fromDirectory(dir, reporter) { + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // read the manifest in this directory + const lockfileLoc = path.join(dir, (_constants || _load_constants()).LOCKFILE_FILENAME); + + let lockfile; + let rawLockfile = ''; + let parseResult; + + if (yield (_fs || _load_fs()).exists(lockfileLoc)) { + rawLockfile = yield (_fs || _load_fs()).readFile(lockfileLoc); + parseResult = (0, (_parse2 || _load_parse2()).default)(rawLockfile, lockfileLoc); + + if (reporter) { + if (parseResult.type === 'merge') { + reporter.info(reporter.lang('lockfileMerged')); + } else if (parseResult.type === 'conflict') { + reporter.warn(reporter.lang('lockfileConflict')); + } + } + + lockfile = parseResult.object; + } else if (reporter) { + reporter.info(reporter.lang('noLockfileFound')); + } + + if (lockfile && lockfile.__metadata) { + const lockfilev2 = lockfile; + lockfile = {}; + } + + return new Lockfile({ cache: lockfile, source: rawLockfile, parseResultType: parseResult && parseResult.type }); + })(); + } + + getLocked(pattern) { + const cache = this.cache; + if (!cache) { + return undefined; + } + + const shrunk = pattern in cache && cache[pattern]; + + if (typeof shrunk === 'string') { + return this.getLocked(shrunk); + } else if (shrunk) { + explodeEntry(pattern, shrunk); + return shrunk; + } + + return undefined; + } + + removePattern(pattern) { + const cache = this.cache; + if (!cache) { + return; + } + delete cache[pattern]; + } + + getLockfile(patterns) { + const lockfile = {}; + const seen = new Map(); + + // order by name so that lockfile manifest is assigned to the first dependency with this manifest + // the others that have the same remoteKey will just refer to the first + // ordering allows for consistency in lockfile when it is serialized + const sortedPatternsKeys = Object.keys(patterns).sort((_misc || _load_misc()).sortAlpha); + + for (var _iterator = sortedPatternsKeys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + const pattern = _ref; + + const pkg = patterns[pattern]; + const remote = pkg._remote, + ref = pkg._reference; + + invariant(ref, 'Package is missing a reference'); + invariant(remote, 'Package is missing a remote'); + + const remoteKey = keyForRemote(remote); + const seenPattern = remoteKey && seen.get(remoteKey); + if (seenPattern) { + // no point in duplicating it + lockfile[pattern] = seenPattern; + + // if we're relying on our name being inferred and two of the patterns have + // different inferred names then we need to set it + if (!seenPattern.name && getName(pattern) !== pkg.name) { + seenPattern.name = pkg.name; + } + continue; + } + const obj = implodeEntry(pattern, { + name: pkg.name, + version: pkg.version, + uid: pkg._uid, + resolved: remote.resolved, + integrity: remote.integrity, + registry: remote.registry, + dependencies: pkg.dependencies, + peerDependencies: pkg.peerDependencies, + optionalDependencies: pkg.optionalDependencies, + permissions: ref.permissions, + prebuiltVariants: pkg.prebuiltVariants + }); + + lockfile[pattern] = obj; + + if (remoteKey) { + seen.set(remoteKey, obj); + } + } + + return lockfile; + } +} +exports.default = Lockfile; + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +var store = __webpack_require__(133)('wks'); +var uid = __webpack_require__(137); +var Symbol = __webpack_require__(17).Symbol; +var USE_SYMBOL = typeof Symbol == 'function'; + +var $exports = module.exports = function (name) { + return store[name] || (store[name] = + USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); +}; + +$exports.store = store; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +var _assign = __webpack_require__(591); + +var _assign2 = _interopRequireDefault(_assign); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = _assign2.default || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; +}; + +/***/ }), +/* 22 */ +/***/ (function(module, exports) { + +exports = module.exports = SemVer; + +// The debug function is excluded entirely from the minified version. +/* nomin */ var debug; +/* nomin */ if (typeof process === 'object' && + /* nomin */ process.env && + /* nomin */ process.env.NODE_DEBUG && + /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG)) + /* nomin */ debug = function() { + /* nomin */ var args = Array.prototype.slice.call(arguments, 0); + /* nomin */ args.unshift('SEMVER'); + /* nomin */ console.log.apply(console, args); + /* nomin */ }; +/* nomin */ else + /* nomin */ debug = function() {}; + +// Note: this is the semver.org version of the spec that it implements +// Not necessarily the package version of this code. +exports.SEMVER_SPEC_VERSION = '2.0.0'; + +var MAX_LENGTH = 256; +var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; + +// Max safe segment length for coercion. +var MAX_SAFE_COMPONENT_LENGTH = 16; + +// The actual regexps go on exports.re +var re = exports.re = []; +var src = exports.src = []; +var R = 0; + +// The following Regular Expressions can be used for tokenizing, +// validating, and parsing SemVer version strings. + +// ## Numeric Identifier +// A single `0`, or a non-zero digit followed by zero or more digits. + +var NUMERICIDENTIFIER = R++; +src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'; +var NUMERICIDENTIFIERLOOSE = R++; +src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'; + + +// ## Non-numeric Identifier +// Zero or more digits, followed by a letter or hyphen, and then zero or +// more letters, digits, or hyphens. + +var NONNUMERICIDENTIFIER = R++; +src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'; + + +// ## Main Version +// Three dot-separated numeric identifiers. + +var MAINVERSION = R++; +src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')'; + +var MAINVERSIONLOOSE = R++; +src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')'; + +// ## Pre-release Version Identifier +// A numeric identifier, or a non-numeric identifier. + +var PRERELEASEIDENTIFIER = R++; +src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + + '|' + src[NONNUMERICIDENTIFIER] + ')'; + +var PRERELEASEIDENTIFIERLOOSE = R++; +src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + + '|' + src[NONNUMERICIDENTIFIER] + ')'; + + +// ## Pre-release Version +// Hyphen, followed by one or more dot-separated pre-release version +// identifiers. + +var PRERELEASE = R++; +src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + + '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'; + +var PRERELEASELOOSE = R++; +src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + + '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'; + +// ## Build Metadata Identifier +// Any combination of digits, letters, or hyphens. + +var BUILDIDENTIFIER = R++; +src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'; + +// ## Build Metadata +// Plus sign, followed by one or more period-separated build metadata +// identifiers. + +var BUILD = R++; +src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + + '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'; + + +// ## Full Version String +// A main version, followed optionally by a pre-release version and +// build metadata. + +// Note that the only major, minor, patch, and pre-release sections of +// the version string are capturing groups. The build metadata is not a +// capturing group, because it should not ever be used in version +// comparison. + +var FULL = R++; +var FULLPLAIN = 'v?' + src[MAINVERSION] + + src[PRERELEASE] + '?' + + src[BUILD] + '?'; + +src[FULL] = '^' + FULLPLAIN + '$'; + +// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. +// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty +// common in the npm registry. +var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + + src[PRERELEASELOOSE] + '?' + + src[BUILD] + '?'; + +var LOOSE = R++; +src[LOOSE] = '^' + LOOSEPLAIN + '$'; + +var GTLT = R++; +src[GTLT] = '((?:<|>)?=?)'; + +// Something like "2.*" or "1.2.x". +// Note that "x.x" is a valid xRange identifer, meaning "any version" +// Only the first item is strictly required. +var XRANGEIDENTIFIERLOOSE = R++; +src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'; +var XRANGEIDENTIFIER = R++; +src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'; + +var XRANGEPLAIN = R++; +src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:' + src[PRERELEASE] + ')?' + + src[BUILD] + '?' + + ')?)?'; + +var XRANGEPLAINLOOSE = R++; +src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:' + src[PRERELEASELOOSE] + ')?' + + src[BUILD] + '?' + + ')?)?'; + +var XRANGE = R++; +src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'; +var XRANGELOOSE = R++; +src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'; + +// Coercion. +// Extract anything that could conceivably be a part of a valid semver +var COERCE = R++; +src[COERCE] = '(?:^|[^\\d])' + + '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:$|[^\\d])'; + +// Tilde ranges. +// Meaning is "reasonably at or greater than" +var LONETILDE = R++; +src[LONETILDE] = '(?:~>?)'; + +var TILDETRIM = R++; +src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'; +re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g'); +var tildeTrimReplace = '$1~'; + +var TILDE = R++; +src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'; +var TILDELOOSE = R++; +src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'; + +// Caret ranges. +// Meaning is "at least and backwards compatible with" +var LONECARET = R++; +src[LONECARET] = '(?:\\^)'; + +var CARETTRIM = R++; +src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'; +re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g'); +var caretTrimReplace = '$1^'; + +var CARET = R++; +src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'; +var CARETLOOSE = R++; +src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'; + +// A simple gt/lt/eq thing, or just "" to indicate "any version" +var COMPARATORLOOSE = R++; +src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'; +var COMPARATOR = R++; +src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'; + + +// An expression to strip any whitespace between the gtlt and the thing +// it modifies, so that `> 1.2.3` ==> `>1.2.3` +var COMPARATORTRIM = R++; +src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + + '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'; + +// this one has to use the /g flag +re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g'); +var comparatorTrimReplace = '$1$2$3'; + + +// Something like `1.2.3 - 1.2.4` +// Note that these all use the loose form, because they'll be +// checked against either the strict or loose comparator form +// later. +var HYPHENRANGE = R++; +src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAIN] + ')' + + '\\s*$'; + +var HYPHENRANGELOOSE = R++; +src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s*$'; + +// Star ranges basically just allow anything at all. +var STAR = R++; +src[STAR] = '(<|>)?=?\\s*\\*'; + +// Compile to actual regexp objects. +// All are flag-free, unless they were created above with a flag. +for (var i = 0; i < R; i++) { + debug(i, src[i]); + if (!re[i]) + re[i] = new RegExp(src[i]); +} + +exports.parse = parse; +function parse(version, loose) { + if (version instanceof SemVer) + return version; + + if (typeof version !== 'string') + return null; + + if (version.length > MAX_LENGTH) + return null; + + var r = loose ? re[LOOSE] : re[FULL]; + if (!r.test(version)) + return null; + + try { + return new SemVer(version, loose); + } catch (er) { + return null; + } +} + +exports.valid = valid; +function valid(version, loose) { + var v = parse(version, loose); + return v ? v.version : null; +} + + +exports.clean = clean; +function clean(version, loose) { + var s = parse(version.trim().replace(/^[=v]+/, ''), loose); + return s ? s.version : null; +} + +exports.SemVer = SemVer; + +function SemVer(version, loose) { + if (version instanceof SemVer) { + if (version.loose === loose) + return version; + else + version = version.version; + } else if (typeof version !== 'string') { + throw new TypeError('Invalid Version: ' + version); + } + + if (version.length > MAX_LENGTH) + throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') + + if (!(this instanceof SemVer)) + return new SemVer(version, loose); + + debug('SemVer', version, loose); + this.loose = loose; + var m = version.trim().match(loose ? re[LOOSE] : re[FULL]); + + if (!m) + throw new TypeError('Invalid Version: ' + version); + + this.raw = version; + + // these are actually numbers + this.major = +m[1]; + this.minor = +m[2]; + this.patch = +m[3]; + + if (this.major > MAX_SAFE_INTEGER || this.major < 0) + throw new TypeError('Invalid major version') + + if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) + throw new TypeError('Invalid minor version') + + if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) + throw new TypeError('Invalid patch version') + + // numberify any prerelease numeric ids + if (!m[4]) + this.prerelease = []; + else + this.prerelease = m[4].split('.').map(function(id) { + if (/^[0-9]+$/.test(id)) { + var num = +id; + if (num >= 0 && num < MAX_SAFE_INTEGER) + return num; + } + return id; + }); + + this.build = m[5] ? m[5].split('.') : []; + this.format(); +} + +SemVer.prototype.format = function() { + this.version = this.major + '.' + this.minor + '.' + this.patch; + if (this.prerelease.length) + this.version += '-' + this.prerelease.join('.'); + return this.version; +}; + +SemVer.prototype.toString = function() { + return this.version; +}; + +SemVer.prototype.compare = function(other) { + debug('SemVer.compare', this.version, this.loose, other); + if (!(other instanceof SemVer)) + other = new SemVer(other, this.loose); + + return this.compareMain(other) || this.comparePre(other); +}; + +SemVer.prototype.compareMain = function(other) { + if (!(other instanceof SemVer)) + other = new SemVer(other, this.loose); + + return compareIdentifiers(this.major, other.major) || + compareIdentifiers(this.minor, other.minor) || + compareIdentifiers(this.patch, other.patch); +}; + +SemVer.prototype.comparePre = function(other) { + if (!(other instanceof SemVer)) + other = new SemVer(other, this.loose); + + // NOT having a prerelease is > having one + if (this.prerelease.length && !other.prerelease.length) + return -1; + else if (!this.prerelease.length && other.prerelease.length) + return 1; + else if (!this.prerelease.length && !other.prerelease.length) + return 0; + + var i = 0; + do { + var a = this.prerelease[i]; + var b = other.prerelease[i]; + debug('prerelease compare', i, a, b); + if (a === undefined && b === undefined) + return 0; + else if (b === undefined) + return 1; + else if (a === undefined) + return -1; + else if (a === b) + continue; + else + return compareIdentifiers(a, b); + } while (++i); +}; + +// preminor will bump the version up to the next minor release, and immediately +// down to pre-release. premajor and prepatch work the same way. +SemVer.prototype.inc = function(release, identifier) { + switch (release) { + case 'premajor': + this.prerelease.length = 0; + this.patch = 0; + this.minor = 0; + this.major++; + this.inc('pre', identifier); + break; + case 'preminor': + this.prerelease.length = 0; + this.patch = 0; + this.minor++; + this.inc('pre', identifier); + break; + case 'prepatch': + // If this is already a prerelease, it will bump to the next version + // drop any prereleases that might already exist, since they are not + // relevant at this point. + this.prerelease.length = 0; + this.inc('patch', identifier); + this.inc('pre', identifier); + break; + // If the input is a non-prerelease version, this acts the same as + // prepatch. + case 'prerelease': + if (this.prerelease.length === 0) + this.inc('patch', identifier); + this.inc('pre', identifier); + break; + + case 'major': + // If this is a pre-major version, bump up to the same major version. + // Otherwise increment major. + // 1.0.0-5 bumps to 1.0.0 + // 1.1.0 bumps to 2.0.0 + if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) + this.major++; + this.minor = 0; + this.patch = 0; + this.prerelease = []; + break; + case 'minor': + // If this is a pre-minor version, bump up to the same minor version. + // Otherwise increment minor. + // 1.2.0-5 bumps to 1.2.0 + // 1.2.1 bumps to 1.3.0 + if (this.patch !== 0 || this.prerelease.length === 0) + this.minor++; + this.patch = 0; + this.prerelease = []; + break; + case 'patch': + // If this is not a pre-release version, it will increment the patch. + // If it is a pre-release it will bump up to the same patch version. + // 1.2.0-5 patches to 1.2.0 + // 1.2.0 patches to 1.2.1 + if (this.prerelease.length === 0) + this.patch++; + this.prerelease = []; + break; + // This probably shouldn't be used publicly. + // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. + case 'pre': + if (this.prerelease.length === 0) + this.prerelease = [0]; + else { + var i = this.prerelease.length; + while (--i >= 0) { + if (typeof this.prerelease[i] === 'number') { + this.prerelease[i]++; + i = -2; + } + } + if (i === -1) // didn't increment anything + this.prerelease.push(0); + } + if (identifier) { + // 1.2.0-beta.1 bumps to 1.2.0-beta.2, + // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 + if (this.prerelease[0] === identifier) { + if (isNaN(this.prerelease[1])) + this.prerelease = [identifier, 0]; + } else + this.prerelease = [identifier, 0]; + } + break; + + default: + throw new Error('invalid increment argument: ' + release); + } + this.format(); + this.raw = this.version; + return this; +}; + +exports.inc = inc; +function inc(version, release, loose, identifier) { + if (typeof(loose) === 'string') { + identifier = loose; + loose = undefined; + } + + try { + return new SemVer(version, loose).inc(release, identifier).version; + } catch (er) { + return null; + } +} + +exports.diff = diff; +function diff(version1, version2) { + if (eq(version1, version2)) { + return null; + } else { + var v1 = parse(version1); + var v2 = parse(version2); + if (v1.prerelease.length || v2.prerelease.length) { + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return 'pre'+key; + } + } + } + return 'prerelease'; + } + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return key; + } + } + } + } +} + +exports.compareIdentifiers = compareIdentifiers; + +var numeric = /^[0-9]+$/; +function compareIdentifiers(a, b) { + var anum = numeric.test(a); + var bnum = numeric.test(b); + + if (anum && bnum) { + a = +a; + b = +b; + } + + return (anum && !bnum) ? -1 : + (bnum && !anum) ? 1 : + a < b ? -1 : + a > b ? 1 : + 0; +} + +exports.rcompareIdentifiers = rcompareIdentifiers; +function rcompareIdentifiers(a, b) { + return compareIdentifiers(b, a); +} + +exports.major = major; +function major(a, loose) { + return new SemVer(a, loose).major; +} + +exports.minor = minor; +function minor(a, loose) { + return new SemVer(a, loose).minor; +} + +exports.patch = patch; +function patch(a, loose) { + return new SemVer(a, loose).patch; +} + +exports.compare = compare; +function compare(a, b, loose) { + return new SemVer(a, loose).compare(new SemVer(b, loose)); +} + +exports.compareLoose = compareLoose; +function compareLoose(a, b) { + return compare(a, b, true); +} + +exports.rcompare = rcompare; +function rcompare(a, b, loose) { + return compare(b, a, loose); +} + +exports.sort = sort; +function sort(list, loose) { + return list.sort(function(a, b) { + return exports.compare(a, b, loose); + }); +} + +exports.rsort = rsort; +function rsort(list, loose) { + return list.sort(function(a, b) { + return exports.rcompare(a, b, loose); + }); +} + +exports.gt = gt; +function gt(a, b, loose) { + return compare(a, b, loose) > 0; +} + +exports.lt = lt; +function lt(a, b, loose) { + return compare(a, b, loose) < 0; +} + +exports.eq = eq; +function eq(a, b, loose) { + return compare(a, b, loose) === 0; +} + +exports.neq = neq; +function neq(a, b, loose) { + return compare(a, b, loose) !== 0; +} + +exports.gte = gte; +function gte(a, b, loose) { + return compare(a, b, loose) >= 0; +} + +exports.lte = lte; +function lte(a, b, loose) { + return compare(a, b, loose) <= 0; +} + +exports.cmp = cmp; +function cmp(a, op, b, loose) { + var ret; + switch (op) { + case '===': + if (typeof a === 'object') a = a.version; + if (typeof b === 'object') b = b.version; + ret = a === b; + break; + case '!==': + if (typeof a === 'object') a = a.version; + if (typeof b === 'object') b = b.version; + ret = a !== b; + break; + case '': case '=': case '==': ret = eq(a, b, loose); break; + case '!=': ret = neq(a, b, loose); break; + case '>': ret = gt(a, b, loose); break; + case '>=': ret = gte(a, b, loose); break; + case '<': ret = lt(a, b, loose); break; + case '<=': ret = lte(a, b, loose); break; + default: throw new TypeError('Invalid operator: ' + op); + } + return ret; +} + +exports.Comparator = Comparator; +function Comparator(comp, loose) { + if (comp instanceof Comparator) { + if (comp.loose === loose) + return comp; + else + comp = comp.value; + } + + if (!(this instanceof Comparator)) + return new Comparator(comp, loose); + + debug('comparator', comp, loose); + this.loose = loose; + this.parse(comp); + + if (this.semver === ANY) + this.value = ''; + else + this.value = this.operator + this.semver.version; + + debug('comp', this); +} + +var ANY = {}; +Comparator.prototype.parse = function(comp) { + var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; + var m = comp.match(r); + + if (!m) + throw new TypeError('Invalid comparator: ' + comp); + + this.operator = m[1]; + if (this.operator === '=') + this.operator = ''; + + // if it literally is just '>' or '' then allow anything. + if (!m[2]) + this.semver = ANY; + else + this.semver = new SemVer(m[2], this.loose); +}; + +Comparator.prototype.toString = function() { + return this.value; +}; + +Comparator.prototype.test = function(version) { + debug('Comparator.test', version, this.loose); + + if (this.semver === ANY) + return true; + + if (typeof version === 'string') + version = new SemVer(version, this.loose); + + return cmp(version, this.operator, this.semver, this.loose); +}; + +Comparator.prototype.intersects = function(comp, loose) { + if (!(comp instanceof Comparator)) { + throw new TypeError('a Comparator is required'); + } + + var rangeTmp; + + if (this.operator === '') { + rangeTmp = new Range(comp.value, loose); + return satisfies(this.value, rangeTmp, loose); + } else if (comp.operator === '') { + rangeTmp = new Range(this.value, loose); + return satisfies(comp.semver, rangeTmp, loose); + } + + var sameDirectionIncreasing = + (this.operator === '>=' || this.operator === '>') && + (comp.operator === '>=' || comp.operator === '>'); + var sameDirectionDecreasing = + (this.operator === '<=' || this.operator === '<') && + (comp.operator === '<=' || comp.operator === '<'); + var sameSemVer = this.semver.version === comp.semver.version; + var differentDirectionsInclusive = + (this.operator === '>=' || this.operator === '<=') && + (comp.operator === '>=' || comp.operator === '<='); + var oppositeDirectionsLessThan = + cmp(this.semver, '<', comp.semver, loose) && + ((this.operator === '>=' || this.operator === '>') && + (comp.operator === '<=' || comp.operator === '<')); + var oppositeDirectionsGreaterThan = + cmp(this.semver, '>', comp.semver, loose) && + ((this.operator === '<=' || this.operator === '<') && + (comp.operator === '>=' || comp.operator === '>')); + + return sameDirectionIncreasing || sameDirectionDecreasing || + (sameSemVer && differentDirectionsInclusive) || + oppositeDirectionsLessThan || oppositeDirectionsGreaterThan; +}; + + +exports.Range = Range; +function Range(range, loose) { + if (range instanceof Range) { + if (range.loose === loose) { + return range; + } else { + return new Range(range.raw, loose); + } + } + + if (range instanceof Comparator) { + return new Range(range.value, loose); + } + + if (!(this instanceof Range)) + return new Range(range, loose); + + this.loose = loose; + + // First, split based on boolean or || + this.raw = range; + this.set = range.split(/\s*\|\|\s*/).map(function(range) { + return this.parseRange(range.trim()); + }, this).filter(function(c) { + // throw out any that are not relevant for whatever reason + return c.length; + }); + + if (!this.set.length) { + throw new TypeError('Invalid SemVer Range: ' + range); + } + + this.format(); +} + +Range.prototype.format = function() { + this.range = this.set.map(function(comps) { + return comps.join(' ').trim(); + }).join('||').trim(); + return this.range; +}; + +Range.prototype.toString = function() { + return this.range; +}; + +Range.prototype.parseRange = function(range) { + var loose = this.loose; + range = range.trim(); + debug('range', range, loose); + // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` + var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]; + range = range.replace(hr, hyphenReplace); + debug('hyphen replace', range); + // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` + range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace); + debug('comparator trim', range, re[COMPARATORTRIM]); + + // `~ 1.2.3` => `~1.2.3` + range = range.replace(re[TILDETRIM], tildeTrimReplace); + + // `^ 1.2.3` => `^1.2.3` + range = range.replace(re[CARETTRIM], caretTrimReplace); + + // normalize spaces + range = range.split(/\s+/).join(' '); + + // At this point, the range is completely trimmed and + // ready to be split into comparators. + + var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; + var set = range.split(' ').map(function(comp) { + return parseComparator(comp, loose); + }).join(' ').split(/\s+/); + if (this.loose) { + // in loose mode, throw out any that are not valid comparators + set = set.filter(function(comp) { + return !!comp.match(compRe); + }); + } + set = set.map(function(comp) { + return new Comparator(comp, loose); + }); + + return set; +}; + +Range.prototype.intersects = function(range, loose) { + if (!(range instanceof Range)) { + throw new TypeError('a Range is required'); + } + + return this.set.some(function(thisComparators) { + return thisComparators.every(function(thisComparator) { + return range.set.some(function(rangeComparators) { + return rangeComparators.every(function(rangeComparator) { + return thisComparator.intersects(rangeComparator, loose); + }); + }); + }); + }); +}; + +// Mostly just for testing and legacy API reasons +exports.toComparators = toComparators; +function toComparators(range, loose) { + return new Range(range, loose).set.map(function(comp) { + return comp.map(function(c) { + return c.value; + }).join(' ').trim().split(' '); + }); +} + +// comprised of xranges, tildes, stars, and gtlt's at this point. +// already replaced the hyphen ranges +// turn into a set of JUST comparators. +function parseComparator(comp, loose) { + debug('comp', comp); + comp = replaceCarets(comp, loose); + debug('caret', comp); + comp = replaceTildes(comp, loose); + debug('tildes', comp); + comp = replaceXRanges(comp, loose); + debug('xrange', comp); + comp = replaceStars(comp, loose); + debug('stars', comp); + return comp; +} + +function isX(id) { + return !id || id.toLowerCase() === 'x' || id === '*'; +} + +// ~, ~> --> * (any, kinda silly) +// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 +// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 +// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 +// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 +// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 +function replaceTildes(comp, loose) { + return comp.trim().split(/\s+/).map(function(comp) { + return replaceTilde(comp, loose); + }).join(' '); +} + +function replaceTilde(comp, loose) { + var r = loose ? re[TILDELOOSE] : re[TILDE]; + return comp.replace(r, function(_, M, m, p, pr) { + debug('tilde', comp, _, M, m, p, pr); + var ret; + + if (isX(M)) + ret = ''; + else if (isX(m)) + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + else if (isX(p)) + // ~1.2 == >=1.2.0 <1.3.0 + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + else if (pr) { + debug('replaceTilde pr', pr); + if (pr.charAt(0) !== '-') + pr = '-' + pr; + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + M + '.' + (+m + 1) + '.0'; + } else + // ~1.2.3 == >=1.2.3 <1.3.0 + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0'; + + debug('tilde return', ret); + return ret; + }); +} + +// ^ --> * (any, kinda silly) +// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 +// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 +// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 +// ^1.2.3 --> >=1.2.3 <2.0.0 +// ^1.2.0 --> >=1.2.0 <2.0.0 +function replaceCarets(comp, loose) { + return comp.trim().split(/\s+/).map(function(comp) { + return replaceCaret(comp, loose); + }).join(' '); +} + +function replaceCaret(comp, loose) { + debug('caret', comp, loose); + var r = loose ? re[CARETLOOSE] : re[CARET]; + return comp.replace(r, function(_, M, m, p, pr) { + debug('caret', comp, _, M, m, p, pr); + var ret; + + if (isX(M)) + ret = ''; + else if (isX(m)) + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + else if (isX(p)) { + if (M === '0') + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + else + ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'; + } else if (pr) { + debug('replaceCaret pr', pr); + if (pr.charAt(0) !== '-') + pr = '-' + pr; + if (M === '0') { + if (m === '0') + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + M + '.' + m + '.' + (+p + 1); + else + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + M + '.' + (+m + 1) + '.0'; + } else + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + (+M + 1) + '.0.0'; + } else { + debug('no pr'); + if (M === '0') { + if (m === '0') + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + m + '.' + (+p + 1); + else + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0'; + } else + ret = '>=' + M + '.' + m + '.' + p + + ' <' + (+M + 1) + '.0.0'; + } + + debug('caret return', ret); + return ret; + }); +} + +function replaceXRanges(comp, loose) { + debug('replaceXRanges', comp, loose); + return comp.split(/\s+/).map(function(comp) { + return replaceXRange(comp, loose); + }).join(' '); +} + +function replaceXRange(comp, loose) { + comp = comp.trim(); + var r = loose ? re[XRANGELOOSE] : re[XRANGE]; + return comp.replace(r, function(ret, gtlt, M, m, p, pr) { + debug('xRange', comp, ret, gtlt, M, m, p, pr); + var xM = isX(M); + var xm = xM || isX(m); + var xp = xm || isX(p); + var anyX = xp; + + if (gtlt === '=' && anyX) + gtlt = ''; + + if (xM) { + if (gtlt === '>' || gtlt === '<') { + // nothing is allowed + ret = '<0.0.0'; + } else { + // nothing is forbidden + ret = '*'; + } + } else if (gtlt && anyX) { + // replace X with 0 + if (xm) + m = 0; + if (xp) + p = 0; + + if (gtlt === '>') { + // >1 => >=2.0.0 + // >1.2 => >=1.3.0 + // >1.2.3 => >= 1.2.4 + gtlt = '>='; + if (xm) { + M = +M + 1; + m = 0; + p = 0; + } else if (xp) { + m = +m + 1; + p = 0; + } + } else if (gtlt === '<=') { + // <=0.7.x is actually <0.8.0, since any 0.7.x should + // pass. Similarly, <=7.x is actually <8.0.0, etc. + gtlt = '<'; + if (xm) + M = +M + 1; + else + m = +m + 1; + } + + ret = gtlt + M + '.' + m + '.' + p; + } else if (xm) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + } else if (xp) { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + } + + debug('xRange return', ret); + + return ret; + }); +} + +// Because * is AND-ed with everything else in the comparator, +// and '' means "any version", just remove the *s entirely. +function replaceStars(comp, loose) { + debug('replaceStars', comp, loose); + // Looseness is ignored here. star is always as loose as it gets! + return comp.trim().replace(re[STAR], ''); +} + +// This function is passed to string.replace(re[HYPHENRANGE]) +// M, m, patch, prerelease, build +// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 +// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do +// 1.2 - 3.4 => >=1.2.0 <3.5.0 +function hyphenReplace($0, + from, fM, fm, fp, fpr, fb, + to, tM, tm, tp, tpr, tb) { + + if (isX(fM)) + from = ''; + else if (isX(fm)) + from = '>=' + fM + '.0.0'; + else if (isX(fp)) + from = '>=' + fM + '.' + fm + '.0'; + else + from = '>=' + from; + + if (isX(tM)) + to = ''; + else if (isX(tm)) + to = '<' + (+tM + 1) + '.0.0'; + else if (isX(tp)) + to = '<' + tM + '.' + (+tm + 1) + '.0'; + else if (tpr) + to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr; + else + to = '<=' + to; + + return (from + ' ' + to).trim(); +} + + +// if ANY of the sets match ALL of its comparators, then pass +Range.prototype.test = function(version) { + if (!version) + return false; + + if (typeof version === 'string') + version = new SemVer(version, this.loose); + + for (var i = 0; i < this.set.length; i++) { + if (testSet(this.set[i], version)) + return true; + } + return false; +}; + +function testSet(set, version) { + for (var i = 0; i < set.length; i++) { + if (!set[i].test(version)) + return false; + } + + if (version.prerelease.length) { + // Find the set of versions that are allowed to have prereleases + // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 + // That should allow `1.2.3-pr.2` to pass. + // However, `1.2.4-alpha.notready` should NOT be allowed, + // even though it's within the range set by the comparators. + for (var i = 0; i < set.length; i++) { + debug(set[i].semver); + if (set[i].semver === ANY) + continue; + + if (set[i].semver.prerelease.length > 0) { + var allowed = set[i].semver; + if (allowed.major === version.major && + allowed.minor === version.minor && + allowed.patch === version.patch) + return true; + } + } + + // Version has a -pre, but it's not one of the ones we like. + return false; + } + + return true; +} + +exports.satisfies = satisfies; +function satisfies(version, range, loose) { + try { + range = new Range(range, loose); + } catch (er) { + return false; + } + return range.test(version); +} + +exports.maxSatisfying = maxSatisfying; +function maxSatisfying(versions, range, loose) { + var max = null; + var maxSV = null; + try { + var rangeObj = new Range(range, loose); + } catch (er) { + return null; + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { // satisfies(v, range, loose) + if (!max || maxSV.compare(v) === -1) { // compare(max, v, true) + max = v; + maxSV = new SemVer(max, loose); + } + } + }) + return max; +} + +exports.minSatisfying = minSatisfying; +function minSatisfying(versions, range, loose) { + var min = null; + var minSV = null; + try { + var rangeObj = new Range(range, loose); + } catch (er) { + return null; + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { // satisfies(v, range, loose) + if (!min || minSV.compare(v) === 1) { // compare(min, v, true) + min = v; + minSV = new SemVer(min, loose); + } + } + }) + return min; +} + +exports.validRange = validRange; +function validRange(range, loose) { + try { + // Return '*' instead of '' so that truthiness works. + // This will throw if it's invalid anyway + return new Range(range, loose).range || '*'; + } catch (er) { + return null; + } +} + +// Determine if version is less than all the versions possible in the range +exports.ltr = ltr; +function ltr(version, range, loose) { + return outside(version, range, '<', loose); +} + +// Determine if version is greater than all the versions possible in the range. +exports.gtr = gtr; +function gtr(version, range, loose) { + return outside(version, range, '>', loose); +} + +exports.outside = outside; +function outside(version, range, hilo, loose) { + version = new SemVer(version, loose); + range = new Range(range, loose); + + var gtfn, ltefn, ltfn, comp, ecomp; + switch (hilo) { + case '>': + gtfn = gt; + ltefn = lte; + ltfn = lt; + comp = '>'; + ecomp = '>='; + break; + case '<': + gtfn = lt; + ltefn = gte; + ltfn = gt; + comp = '<'; + ecomp = '<='; + break; + default: + throw new TypeError('Must provide a hilo val of "<" or ">"'); + } + + // If it satisifes the range it is not outside + if (satisfies(version, range, loose)) { + return false; + } + + // From now on, variable terms are as if we're in "gtr" mode. + // but note that everything is flipped for the "ltr" function. + + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i]; + + var high = null; + var low = null; + + comparators.forEach(function(comparator) { + if (comparator.semver === ANY) { + comparator = new Comparator('>=0.0.0') + } + high = high || comparator; + low = low || comparator; + if (gtfn(comparator.semver, high.semver, loose)) { + high = comparator; + } else if (ltfn(comparator.semver, low.semver, loose)) { + low = comparator; + } + }); + + // If the edge version comparator has a operator then our version + // isn't outside it + if (high.operator === comp || high.operator === ecomp) { + return false; + } + + // If the lowest version comparator has an operator and our version + // is less than it then it isn't higher than the range + if ((!low.operator || low.operator === comp) && + ltefn(version, low.semver)) { + return false; + } else if (low.operator === ecomp && ltfn(version, low.semver)) { + return false; + } + } + return true; +} + +exports.prerelease = prerelease; +function prerelease(version, loose) { + var parsed = parse(version, loose); + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null; +} + +exports.intersects = intersects; +function intersects(r1, r2, loose) { + r1 = new Range(r1, loose) + r2 = new Range(r2, loose) + return r1.intersects(r2) +} + +exports.coerce = coerce; +function coerce(version) { + if (version instanceof SemVer) + return version; + + if (typeof version !== 'string') + return null; + + var match = version.match(re[COERCE]); + + if (match == null) + return null; + + return parse((match[1] || '0') + '.' + (match[2] || '0') + '.' + (match[3] || '0')); +} + + +/***/ }), +/* 23 */ +/***/ (function(module, exports) { + +module.exports = require("stream"); + +/***/ }), +/* 24 */ +/***/ (function(module, exports) { + +module.exports = require("url"); + +/***/ }), +/* 25 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscription; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_isArray__ = __webpack_require__(41); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isObject__ = __webpack_require__(444); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_isFunction__ = __webpack_require__(154); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_tryCatch__ = __webpack_require__(56); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_errorObject__ = __webpack_require__(48); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__ = __webpack_require__(441); +/** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_tryCatch,_util_errorObject,_util_UnsubscriptionError PURE_IMPORTS_END */ + + + + + + +var Subscription = /*@__PURE__*/ (function () { + function Subscription(unsubscribe) { + this.closed = false; + this._parent = null; + this._parents = null; + this._subscriptions = null; + if (unsubscribe) { + this._unsubscribe = unsubscribe; + } + } + Subscription.prototype.unsubscribe = function () { + var hasErrors = false; + var errors; + if (this.closed) { + return; + } + var _a = this, _parent = _a._parent, _parents = _a._parents, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions; + this.closed = true; + this._parent = null; + this._parents = null; + this._subscriptions = null; + var index = -1; + var len = _parents ? _parents.length : 0; + while (_parent) { + _parent.remove(this); + _parent = ++index < len && _parents[index] || null; + } + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__util_isFunction__["a" /* isFunction */])(_unsubscribe)) { + var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(_unsubscribe).call(this); + if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { + hasErrors = true; + errors = errors || (__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */] ? + flattenUnsubscriptionErrors(__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e.errors) : [__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e]); + } + } + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_isArray__["a" /* isArray */])(_subscriptions)) { + index = -1; + len = _subscriptions.length; + while (++index < len) { + var sub = _subscriptions[index]; + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isObject__["a" /* isObject */])(sub)) { + var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(sub.unsubscribe).call(sub); + if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { + hasErrors = true; + errors = errors || []; + var err = __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e; + if (err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) { + errors = errors.concat(flattenUnsubscriptionErrors(err.errors)); + } + else { + errors.push(err); + } + } + } + } + } + if (hasErrors) { + throw new __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */](errors); + } + }; + Subscription.prototype.add = function (teardown) { + if (!teardown || (teardown === Subscription.EMPTY)) { + return Subscription.EMPTY; + } + if (teardown === this) { + return this; + } + var subscription = teardown; + switch (typeof teardown) { + case 'function': + subscription = new Subscription(teardown); + case 'object': + if (subscription.closed || typeof subscription.unsubscribe !== 'function') { + return subscription; + } + else if (this.closed) { + subscription.unsubscribe(); + return subscription; + } + else if (typeof subscription._addParent !== 'function') { + var tmp = subscription; + subscription = new Subscription(); + subscription._subscriptions = [tmp]; + } + break; + default: + throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.'); + } + var subscriptions = this._subscriptions || (this._subscriptions = []); + subscriptions.push(subscription); + subscription._addParent(this); + return subscription; + }; + Subscription.prototype.remove = function (subscription) { + var subscriptions = this._subscriptions; + if (subscriptions) { + var subscriptionIndex = subscriptions.indexOf(subscription); + if (subscriptionIndex !== -1) { + subscriptions.splice(subscriptionIndex, 1); + } + } + }; + Subscription.prototype._addParent = function (parent) { + var _a = this, _parent = _a._parent, _parents = _a._parents; + if (!_parent || _parent === parent) { + this._parent = parent; + } + else if (!_parents) { + this._parents = [parent]; + } + else if (_parents.indexOf(parent) === -1) { + _parents.push(parent); + } + }; + Subscription.EMPTY = (function (empty) { + empty.closed = true; + return empty; + }(new Subscription())); + return Subscription; +}()); + +function flattenUnsubscriptionErrors(errors) { + return errors.reduce(function (errs, err) { return errs.concat((err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) ? err.errors : err); }, []); +} +//# sourceMappingURL=Subscription.js.map + + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2015 Joyent, Inc. + +module.exports = { + bufferSplit: bufferSplit, + addRSAMissing: addRSAMissing, + calculateDSAPublic: calculateDSAPublic, + calculateED25519Public: calculateED25519Public, + calculateX25519Public: calculateX25519Public, + mpNormalize: mpNormalize, + mpDenormalize: mpDenormalize, + ecNormalize: ecNormalize, + countZeros: countZeros, + assertCompatible: assertCompatible, + isCompatible: isCompatible, + opensslKeyDeriv: opensslKeyDeriv, + opensshCipherInfo: opensshCipherInfo, + publicFromPrivateECDSA: publicFromPrivateECDSA, + zeroPadToLength: zeroPadToLength, + writeBitString: writeBitString, + readBitString: readBitString +}; + +var assert = __webpack_require__(16); +var Buffer = __webpack_require__(15).Buffer; +var PrivateKey = __webpack_require__(33); +var Key = __webpack_require__(27); +var crypto = __webpack_require__(11); +var algs = __webpack_require__(32); +var asn1 = __webpack_require__(66); + +var ec, jsbn; +var nacl; + +var MAX_CLASS_DEPTH = 3; + +function isCompatible(obj, klass, needVer) { + if (obj === null || typeof (obj) !== 'object') + return (false); + if (needVer === undefined) + needVer = klass.prototype._sshpkApiVersion; + if (obj instanceof klass && + klass.prototype._sshpkApiVersion[0] == needVer[0]) + return (true); + var proto = Object.getPrototypeOf(obj); + var depth = 0; + while (proto.constructor.name !== klass.name) { + proto = Object.getPrototypeOf(proto); + if (!proto || ++depth > MAX_CLASS_DEPTH) + return (false); + } + if (proto.constructor.name !== klass.name) + return (false); + var ver = proto._sshpkApiVersion; + if (ver === undefined) + ver = klass._oldVersionDetect(obj); + if (ver[0] != needVer[0] || ver[1] < needVer[1]) + return (false); + return (true); +} + +function assertCompatible(obj, klass, needVer, name) { + if (name === undefined) + name = 'object'; + assert.ok(obj, name + ' must not be null'); + assert.object(obj, name + ' must be an object'); + if (needVer === undefined) + needVer = klass.prototype._sshpkApiVersion; + if (obj instanceof klass && + klass.prototype._sshpkApiVersion[0] == needVer[0]) + return; + var proto = Object.getPrototypeOf(obj); + var depth = 0; + while (proto.constructor.name !== klass.name) { + proto = Object.getPrototypeOf(proto); + assert.ok(proto && ++depth <= MAX_CLASS_DEPTH, + name + ' must be a ' + klass.name + ' instance'); + } + assert.strictEqual(proto.constructor.name, klass.name, + name + ' must be a ' + klass.name + ' instance'); + var ver = proto._sshpkApiVersion; + if (ver === undefined) + ver = klass._oldVersionDetect(obj); + assert.ok(ver[0] == needVer[0] && ver[1] >= needVer[1], + name + ' must be compatible with ' + klass.name + ' klass ' + + 'version ' + needVer[0] + '.' + needVer[1]); +} + +var CIPHER_LEN = { + 'des-ede3-cbc': { key: 7, iv: 8 }, + 'aes-128-cbc': { key: 16, iv: 16 } +}; +var PKCS5_SALT_LEN = 8; + +function opensslKeyDeriv(cipher, salt, passphrase, count) { + assert.buffer(salt, 'salt'); + assert.buffer(passphrase, 'passphrase'); + assert.number(count, 'iteration count'); + + var clen = CIPHER_LEN[cipher]; + assert.object(clen, 'supported cipher'); + + salt = salt.slice(0, PKCS5_SALT_LEN); + + var D, D_prev, bufs; + var material = Buffer.alloc(0); + while (material.length < clen.key + clen.iv) { + bufs = []; + if (D_prev) + bufs.push(D_prev); + bufs.push(passphrase); + bufs.push(salt); + D = Buffer.concat(bufs); + for (var j = 0; j < count; ++j) + D = crypto.createHash('md5').update(D).digest(); + material = Buffer.concat([material, D]); + D_prev = D; + } + + return ({ + key: material.slice(0, clen.key), + iv: material.slice(clen.key, clen.key + clen.iv) + }); +} + +/* Count leading zero bits on a buffer */ +function countZeros(buf) { + var o = 0, obit = 8; + while (o < buf.length) { + var mask = (1 << obit); + if ((buf[o] & mask) === mask) + break; + obit--; + if (obit < 0) { + o++; + obit = 8; + } + } + return (o*8 + (8 - obit) - 1); +} + +function bufferSplit(buf, chr) { + assert.buffer(buf); + assert.string(chr); + + var parts = []; + var lastPart = 0; + var matches = 0; + for (var i = 0; i < buf.length; ++i) { + if (buf[i] === chr.charCodeAt(matches)) + ++matches; + else if (buf[i] === chr.charCodeAt(0)) + matches = 1; + else + matches = 0; + + if (matches >= chr.length) { + var newPart = i + 1; + parts.push(buf.slice(lastPart, newPart - matches)); + lastPart = newPart; + matches = 0; + } + } + if (lastPart <= buf.length) + parts.push(buf.slice(lastPart, buf.length)); + + return (parts); +} + +function ecNormalize(buf, addZero) { + assert.buffer(buf); + if (buf[0] === 0x00 && buf[1] === 0x04) { + if (addZero) + return (buf); + return (buf.slice(1)); + } else if (buf[0] === 0x04) { + if (!addZero) + return (buf); + } else { + while (buf[0] === 0x00) + buf = buf.slice(1); + if (buf[0] === 0x02 || buf[0] === 0x03) + throw (new Error('Compressed elliptic curve points ' + + 'are not supported')); + if (buf[0] !== 0x04) + throw (new Error('Not a valid elliptic curve point')); + if (!addZero) + return (buf); + } + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x0; + buf.copy(b, 1); + return (b); +} + +function readBitString(der, tag) { + if (tag === undefined) + tag = asn1.Ber.BitString; + var buf = der.readString(tag, true); + assert.strictEqual(buf[0], 0x00, 'bit strings with unused bits are ' + + 'not supported (0x' + buf[0].toString(16) + ')'); + return (buf.slice(1)); +} + +function writeBitString(der, buf, tag) { + if (tag === undefined) + tag = asn1.Ber.BitString; + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x00; + buf.copy(b, 1); + der.writeBuffer(b, tag); +} + +function mpNormalize(buf) { + assert.buffer(buf); + while (buf.length > 1 && buf[0] === 0x00 && (buf[1] & 0x80) === 0x00) + buf = buf.slice(1); + if ((buf[0] & 0x80) === 0x80) { + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x00; + buf.copy(b, 1); + buf = b; + } + return (buf); +} + +function mpDenormalize(buf) { + assert.buffer(buf); + while (buf.length > 1 && buf[0] === 0x00) + buf = buf.slice(1); + return (buf); +} + +function zeroPadToLength(buf, len) { + assert.buffer(buf); + assert.number(len); + while (buf.length > len) { + assert.equal(buf[0], 0x00); + buf = buf.slice(1); + } + while (buf.length < len) { + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x00; + buf.copy(b, 1); + buf = b; + } + return (buf); +} + +function bigintToMpBuf(bigint) { + var buf = Buffer.from(bigint.toByteArray()); + buf = mpNormalize(buf); + return (buf); +} + +function calculateDSAPublic(g, p, x) { + assert.buffer(g); + assert.buffer(p); + assert.buffer(x); + try { + var bigInt = __webpack_require__(81).BigInteger; + } catch (e) { + throw (new Error('To load a PKCS#8 format DSA private key, ' + + 'the node jsbn library is required.')); + } + g = new bigInt(g); + p = new bigInt(p); + x = new bigInt(x); + var y = g.modPow(x, p); + var ybuf = bigintToMpBuf(y); + return (ybuf); +} + +function calculateED25519Public(k) { + assert.buffer(k); + + if (nacl === undefined) + nacl = __webpack_require__(76); + + var kp = nacl.sign.keyPair.fromSeed(new Uint8Array(k)); + return (Buffer.from(kp.publicKey)); +} + +function calculateX25519Public(k) { + assert.buffer(k); + + if (nacl === undefined) + nacl = __webpack_require__(76); + + var kp = nacl.box.keyPair.fromSeed(new Uint8Array(k)); + return (Buffer.from(kp.publicKey)); +} + +function addRSAMissing(key) { + assert.object(key); + assertCompatible(key, PrivateKey, [1, 1]); + try { + var bigInt = __webpack_require__(81).BigInteger; + } catch (e) { + throw (new Error('To write a PEM private key from ' + + 'this source, the node jsbn lib is required.')); + } + + var d = new bigInt(key.part.d.data); + var buf; + + if (!key.part.dmodp) { + var p = new bigInt(key.part.p.data); + var dmodp = d.mod(p.subtract(1)); + + buf = bigintToMpBuf(dmodp); + key.part.dmodp = {name: 'dmodp', data: buf}; + key.parts.push(key.part.dmodp); + } + if (!key.part.dmodq) { + var q = new bigInt(key.part.q.data); + var dmodq = d.mod(q.subtract(1)); + + buf = bigintToMpBuf(dmodq); + key.part.dmodq = {name: 'dmodq', data: buf}; + key.parts.push(key.part.dmodq); + } +} + +function publicFromPrivateECDSA(curveName, priv) { + assert.string(curveName, 'curveName'); + assert.buffer(priv); + if (ec === undefined) + ec = __webpack_require__(139); + if (jsbn === undefined) + jsbn = __webpack_require__(81).BigInteger; + var params = algs.curves[curveName]; + var p = new jsbn(params.p); + var a = new jsbn(params.a); + var b = new jsbn(params.b); + var curve = new ec.ECCurveFp(p, a, b); + var G = curve.decodePointHex(params.G.toString('hex')); + + var d = new jsbn(mpNormalize(priv)); + var pub = G.multiply(d); + pub = Buffer.from(curve.encodePointHex(pub), 'hex'); + + var parts = []; + parts.push({name: 'curve', data: Buffer.from(curveName)}); + parts.push({name: 'Q', data: pub}); + + var key = new Key({type: 'ecdsa', curve: curve, parts: parts}); + return (key); +} + +function opensshCipherInfo(cipher) { + var inf = {}; + switch (cipher) { + case '3des-cbc': + inf.keySize = 24; + inf.blockSize = 8; + inf.opensslName = 'des-ede3-cbc'; + break; + case 'blowfish-cbc': + inf.keySize = 16; + inf.blockSize = 8; + inf.opensslName = 'bf-cbc'; + break; + case 'aes128-cbc': + case 'aes128-ctr': + case 'aes128-gcm@openssh.com': + inf.keySize = 16; + inf.blockSize = 16; + inf.opensslName = 'aes-128-' + cipher.slice(7, 10); + break; + case 'aes192-cbc': + case 'aes192-ctr': + case 'aes192-gcm@openssh.com': + inf.keySize = 24; + inf.blockSize = 16; + inf.opensslName = 'aes-192-' + cipher.slice(7, 10); + break; + case 'aes256-cbc': + case 'aes256-ctr': + case 'aes256-gcm@openssh.com': + inf.keySize = 32; + inf.blockSize = 16; + inf.opensslName = 'aes-256-' + cipher.slice(7, 10); + break; + default: + throw (new Error( + 'Unsupported openssl cipher "' + cipher + '"')); + } + return (inf); +} + + +/***/ }), +/* 27 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2017 Joyent, Inc. + +module.exports = Key; + +var assert = __webpack_require__(16); +var algs = __webpack_require__(32); +var crypto = __webpack_require__(11); +var Fingerprint = __webpack_require__(156); +var Signature = __webpack_require__(75); +var DiffieHellman = __webpack_require__(325).DiffieHellman; +var errs = __webpack_require__(74); +var utils = __webpack_require__(26); +var PrivateKey = __webpack_require__(33); +var edCompat; + +try { + edCompat = __webpack_require__(454); +} catch (e) { + /* Just continue through, and bail out if we try to use it. */ +} + +var InvalidAlgorithmError = errs.InvalidAlgorithmError; +var KeyParseError = errs.KeyParseError; + +var formats = {}; +formats['auto'] = __webpack_require__(455); +formats['pem'] = __webpack_require__(86); +formats['pkcs1'] = __webpack_require__(327); +formats['pkcs8'] = __webpack_require__(157); +formats['rfc4253'] = __webpack_require__(103); +formats['ssh'] = __webpack_require__(456); +formats['ssh-private'] = __webpack_require__(192); +formats['openssh'] = formats['ssh-private']; +formats['dnssec'] = __webpack_require__(326); + +function Key(opts) { + assert.object(opts, 'options'); + assert.arrayOfObject(opts.parts, 'options.parts'); + assert.string(opts.type, 'options.type'); + assert.optionalString(opts.comment, 'options.comment'); + + var algInfo = algs.info[opts.type]; + if (typeof (algInfo) !== 'object') + throw (new InvalidAlgorithmError(opts.type)); + + var partLookup = {}; + for (var i = 0; i < opts.parts.length; ++i) { + var part = opts.parts[i]; + partLookup[part.name] = part; + } + + this.type = opts.type; + this.parts = opts.parts; + this.part = partLookup; + this.comment = undefined; + this.source = opts.source; + + /* for speeding up hashing/fingerprint operations */ + this._rfc4253Cache = opts._rfc4253Cache; + this._hashCache = {}; + + var sz; + this.curve = undefined; + if (this.type === 'ecdsa') { + var curve = this.part.curve.data.toString(); + this.curve = curve; + sz = algs.curves[curve].size; + } else if (this.type === 'ed25519' || this.type === 'curve25519') { + sz = 256; + this.curve = 'curve25519'; + } else { + var szPart = this.part[algInfo.sizePart]; + sz = szPart.data.length; + sz = sz * 8 - utils.countZeros(szPart.data); + } + this.size = sz; +} + +Key.formats = formats; + +Key.prototype.toBuffer = function (format, options) { + if (format === undefined) + format = 'ssh'; + assert.string(format, 'format'); + assert.object(formats[format], 'formats[format]'); + assert.optionalObject(options, 'options'); + + if (format === 'rfc4253') { + if (this._rfc4253Cache === undefined) + this._rfc4253Cache = formats['rfc4253'].write(this); + return (this._rfc4253Cache); + } + + return (formats[format].write(this, options)); +}; + +Key.prototype.toString = function (format, options) { + return (this.toBuffer(format, options).toString()); +}; + +Key.prototype.hash = function (algo) { + assert.string(algo, 'algorithm'); + algo = algo.toLowerCase(); + if (algs.hashAlgs[algo] === undefined) + throw (new InvalidAlgorithmError(algo)); + + if (this._hashCache[algo]) + return (this._hashCache[algo]); + var hash = crypto.createHash(algo). + update(this.toBuffer('rfc4253')).digest(); + this._hashCache[algo] = hash; + return (hash); +}; + +Key.prototype.fingerprint = function (algo) { + if (algo === undefined) + algo = 'sha256'; + assert.string(algo, 'algorithm'); + var opts = { + type: 'key', + hash: this.hash(algo), + algorithm: algo + }; + return (new Fingerprint(opts)); +}; + +Key.prototype.defaultHashAlgorithm = function () { + var hashAlgo = 'sha1'; + if (this.type === 'rsa') + hashAlgo = 'sha256'; + if (this.type === 'dsa' && this.size > 1024) + hashAlgo = 'sha256'; + if (this.type === 'ed25519') + hashAlgo = 'sha512'; + if (this.type === 'ecdsa') { + if (this.size <= 256) + hashAlgo = 'sha256'; + else if (this.size <= 384) + hashAlgo = 'sha384'; + else + hashAlgo = 'sha512'; + } + return (hashAlgo); +}; + +Key.prototype.createVerify = function (hashAlgo) { + if (hashAlgo === undefined) + hashAlgo = this.defaultHashAlgorithm(); + assert.string(hashAlgo, 'hash algorithm'); + + /* ED25519 is not supported by OpenSSL, use a javascript impl. */ + if (this.type === 'ed25519' && edCompat !== undefined) + return (new edCompat.Verifier(this, hashAlgo)); + if (this.type === 'curve25519') + throw (new Error('Curve25519 keys are not suitable for ' + + 'signing or verification')); + + var v, nm, err; + try { + nm = hashAlgo.toUpperCase(); + v = crypto.createVerify(nm); + } catch (e) { + err = e; + } + if (v === undefined || (err instanceof Error && + err.message.match(/Unknown message digest/))) { + nm = 'RSA-'; + nm += hashAlgo.toUpperCase(); + v = crypto.createVerify(nm); + } + assert.ok(v, 'failed to create verifier'); + var oldVerify = v.verify.bind(v); + var key = this.toBuffer('pkcs8'); + var curve = this.curve; + var self = this; + v.verify = function (signature, fmt) { + if (Signature.isSignature(signature, [2, 0])) { + if (signature.type !== self.type) + return (false); + if (signature.hashAlgorithm && + signature.hashAlgorithm !== hashAlgo) + return (false); + if (signature.curve && self.type === 'ecdsa' && + signature.curve !== curve) + return (false); + return (oldVerify(key, signature.toBuffer('asn1'))); + + } else if (typeof (signature) === 'string' || + Buffer.isBuffer(signature)) { + return (oldVerify(key, signature, fmt)); + + /* + * Avoid doing this on valid arguments, walking the prototype + * chain can be quite slow. + */ + } else if (Signature.isSignature(signature, [1, 0])) { + throw (new Error('signature was created by too old ' + + 'a version of sshpk and cannot be verified')); + + } else { + throw (new TypeError('signature must be a string, ' + + 'Buffer, or Signature object')); + } + }; + return (v); +}; + +Key.prototype.createDiffieHellman = function () { + if (this.type === 'rsa') + throw (new Error('RSA keys do not support Diffie-Hellman')); + + return (new DiffieHellman(this)); +}; +Key.prototype.createDH = Key.prototype.createDiffieHellman; + +Key.parse = function (data, format, options) { + if (typeof (data) !== 'string') + assert.buffer(data, 'data'); + if (format === undefined) + format = 'auto'; + assert.string(format, 'format'); + if (typeof (options) === 'string') + options = { filename: options }; + assert.optionalObject(options, 'options'); + if (options === undefined) + options = {}; + assert.optionalString(options.filename, 'options.filename'); + if (options.filename === undefined) + options.filename = '(unnamed)'; + + assert.object(formats[format], 'formats[format]'); + + try { + var k = formats[format].read(data, options); + if (k instanceof PrivateKey) + k = k.toPublic(); + if (!k.comment) + k.comment = options.filename; + return (k); + } catch (e) { + if (e.name === 'KeyEncryptedError') + throw (e); + throw (new KeyParseError(options.filename, format, e)); + } +}; + +Key.isKey = function (obj, ver) { + return (utils.isCompatible(obj, Key, ver)); +}; + +/* + * API versions for Key: + * [1,0] -- initial ver, may take Signature for createVerify or may not + * [1,1] -- added pkcs1, pkcs8 formats + * [1,2] -- added auto, ssh-private, openssh formats + * [1,3] -- added defaultHashAlgorithm + * [1,4] -- added ed support, createDH + * [1,5] -- first explicitly tagged version + * [1,6] -- changed ed25519 part names + */ +Key.prototype._sshpkApiVersion = [1, 6]; + +Key._oldVersionDetect = function (obj) { + assert.func(obj.toBuffer); + assert.func(obj.fingerprint); + if (obj.createDH) + return ([1, 4]); + if (obj.defaultHashAlgorithm) + return ([1, 3]); + if (obj.formats['auto']) + return ([1, 2]); + if (obj.formats['pkcs1']) + return ([1, 1]); + return ([1, 0]); +}; + + +/***/ }), +/* 28 */ +/***/ (function(module, exports) { + +module.exports = require("assert"); + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = nullify; +function nullify(obj = {}) { + if (Array.isArray(obj)) { + for (var _iterator = obj, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + const item = _ref; + + nullify(item); + } + } else if (obj !== null && typeof obj === 'object' || typeof obj === 'function') { + Object.setPrototypeOf(obj, null); + + // for..in can only be applied to 'object', not 'function' + if (typeof obj === 'object') { + for (const key in obj) { + nullify(obj[key]); + } + } + } + + return obj; +} + +/***/ }), +/* 30 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const escapeStringRegexp = __webpack_require__(388); +const ansiStyles = __webpack_require__(506); +const stdoutColor = __webpack_require__(598).stdout; + +const template = __webpack_require__(599); + +const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); + +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; + +// `color-convert` models to exclude from the Chalk API due to conflicts and such +const skipModels = new Set(['gray']); + +const styles = Object.create(null); + +function applyOptions(obj, options) { + options = options || {}; + + // Detect level if not set manually + const scLevel = stdoutColor ? stdoutColor.level : 0; + obj.level = options.level === undefined ? scLevel : options.level; + obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; +} + +function Chalk(options) { + // We check for this.template here since calling `chalk.constructor()` + // by itself will have a `this` of a previously constructed chalk object + if (!this || !(this instanceof Chalk) || this.template) { + const chalk = {}; + applyOptions(chalk, options); + + chalk.template = function () { + const args = [].slice.call(arguments); + return chalkTag.apply(null, [chalk.template].concat(args)); + }; + + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); + + chalk.template.constructor = Chalk; + + return chalk.template; + } + + applyOptions(this, options); +} + +// Use bright blue on Windows as the normal blue color is illegible +if (isSimpleWindowsTerm) { + ansiStyles.blue.open = '\u001B[94m'; +} + +for (const key of Object.keys(ansiStyles)) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); + + styles[key] = { + get() { + const codes = ansiStyles[key]; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + } + }; +} + +styles.visible = { + get() { + return build.call(this, this._styles || [], true, 'visible'); + } +}; + +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); +for (const model of Object.keys(ansiStyles.color.ansi)) { + if (skipModels.has(model)) { + continue; + } + + styles[model] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.color.close, + closeRe: ansiStyles.color.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} + +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); +for (const model of Object.keys(ansiStyles.bgColor.ansi)) { + if (skipModels.has(model)) { + continue; + } + + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.bgColor.close, + closeRe: ansiStyles.bgColor.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} + +const proto = Object.defineProperties(() => {}, styles); + +function build(_styles, _empty, key) { + const builder = function () { + return applyStyle.apply(builder, arguments); + }; + + builder._styles = _styles; + builder._empty = _empty; + + const self = this; + + Object.defineProperty(builder, 'level', { + enumerable: true, + get() { + return self.level; + }, + set(level) { + self.level = level; + } + }); + + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get() { + return self.enabled; + }, + set(enabled) { + self.enabled = enabled; + } + }); + + // See below for fix regarding invisible grey/dim combination on Windows + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + + // `__proto__` is used because we must return a function, but there is + // no way to create a function with a different prototype + builder.__proto__ = proto; // eslint-disable-line no-proto + + return builder; +} + +function applyStyle() { + // Support varags, but simply cast to string in case there's only one arg + const args = arguments; + const argsLen = args.length; + let str = String(arguments[0]); + + if (argsLen === 0) { + return ''; + } + + if (argsLen > 1) { + // Don't slice `arguments`, it prevents V8 optimizations + for (let a = 1; a < argsLen; a++) { + str += ' ' + args[a]; + } + } + + if (!this.enabled || this.level <= 0 || !str) { + return this._empty ? '' : str; + } + + // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, + // see https://github.com/chalk/chalk/issues/58 + // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. + const originalDim = ansiStyles.dim.open; + if (isSimpleWindowsTerm && this.hasGrey) { + ansiStyles.dim.open = ''; + } + + for (const code of this._styles.slice().reverse()) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + str = code.open + str.replace(code.closeRe, code.open) + code.close; + + // Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS + // https://github.com/chalk/chalk/pull/92 + str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); + } + + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue + ansiStyles.dim.open = originalDim; + + return str; +} + +function chalkTag(chalk, strings) { + if (!Array.isArray(strings)) { + // If chalk() was called by itself or with a string, + // return the string itself as a string. + return [].slice.call(arguments, 1).join(' '); + } + + const args = [].slice.call(arguments, 2); + const parts = [strings.raw[0]]; + + for (let i = 1; i < strings.length; i++) { + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); + parts.push(String(strings.raw[i])); + } + + return template(chalk, parts.join('')); +} + +Object.defineProperties(Chalk.prototype, styles); + +module.exports = Chalk(); // eslint-disable-line new-cap +module.exports.supportsColor = stdoutColor; +module.exports.default = module.exports; // For TypeScript + + +/***/ }), +/* 31 */ +/***/ (function(module, exports) { + +var core = module.exports = { version: '2.5.7' }; +if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef + + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2015 Joyent, Inc. + +var Buffer = __webpack_require__(15).Buffer; + +var algInfo = { + 'dsa': { + parts: ['p', 'q', 'g', 'y'], + sizePart: 'p' + }, + 'rsa': { + parts: ['e', 'n'], + sizePart: 'n' + }, + 'ecdsa': { + parts: ['curve', 'Q'], + sizePart: 'Q' + }, + 'ed25519': { + parts: ['A'], + sizePart: 'A' + } +}; +algInfo['curve25519'] = algInfo['ed25519']; + +var algPrivInfo = { + 'dsa': { + parts: ['p', 'q', 'g', 'y', 'x'] + }, + 'rsa': { + parts: ['n', 'e', 'd', 'iqmp', 'p', 'q'] + }, + 'ecdsa': { + parts: ['curve', 'Q', 'd'] + }, + 'ed25519': { + parts: ['A', 'k'] + } +}; +algPrivInfo['curve25519'] = algPrivInfo['ed25519']; + +var hashAlgs = { + 'md5': true, + 'sha1': true, + 'sha256': true, + 'sha384': true, + 'sha512': true +}; + +/* + * Taken from + * http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf + */ +var curves = { + 'nistp256': { + size: 256, + pkcs8oid: '1.2.840.10045.3.1.7', + p: Buffer.from(('00' + + 'ffffffff 00000001 00000000 00000000' + + '00000000 ffffffff ffffffff ffffffff'). + replace(/ /g, ''), 'hex'), + a: Buffer.from(('00' + + 'FFFFFFFF 00000001 00000000 00000000' + + '00000000 FFFFFFFF FFFFFFFF FFFFFFFC'). + replace(/ /g, ''), 'hex'), + b: Buffer.from(( + '5ac635d8 aa3a93e7 b3ebbd55 769886bc' + + '651d06b0 cc53b0f6 3bce3c3e 27d2604b'). + replace(/ /g, ''), 'hex'), + s: Buffer.from(('00' + + 'c49d3608 86e70493 6a6678e1 139d26b7' + + '819f7e90'). + replace(/ /g, ''), 'hex'), + n: Buffer.from(('00' + + 'ffffffff 00000000 ffffffff ffffffff' + + 'bce6faad a7179e84 f3b9cac2 fc632551'). + replace(/ /g, ''), 'hex'), + G: Buffer.from(('04' + + '6b17d1f2 e12c4247 f8bce6e5 63a440f2' + + '77037d81 2deb33a0 f4a13945 d898c296' + + '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16' + + '2bce3357 6b315ece cbb64068 37bf51f5'). + replace(/ /g, ''), 'hex') + }, + 'nistp384': { + size: 384, + pkcs8oid: '1.3.132.0.34', + p: Buffer.from(('00' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff fffffffe' + + 'ffffffff 00000000 00000000 ffffffff'). + replace(/ /g, ''), 'hex'), + a: Buffer.from(('00' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE' + + 'FFFFFFFF 00000000 00000000 FFFFFFFC'). + replace(/ /g, ''), 'hex'), + b: Buffer.from(( + 'b3312fa7 e23ee7e4 988e056b e3f82d19' + + '181d9c6e fe814112 0314088f 5013875a' + + 'c656398d 8a2ed19d 2a85c8ed d3ec2aef'). + replace(/ /g, ''), 'hex'), + s: Buffer.from(('00' + + 'a335926a a319a27a 1d00896a 6773a482' + + '7acdac73'). + replace(/ /g, ''), 'hex'), + n: Buffer.from(('00' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff c7634d81 f4372ddf' + + '581a0db2 48b0a77a ecec196a ccc52973'). + replace(/ /g, ''), 'hex'), + G: Buffer.from(('04' + + 'aa87ca22 be8b0537 8eb1c71e f320ad74' + + '6e1d3b62 8ba79b98 59f741e0 82542a38' + + '5502f25d bf55296c 3a545e38 72760ab7' + + '3617de4a 96262c6f 5d9e98bf 9292dc29' + + 'f8f41dbd 289a147c e9da3113 b5f0b8c0' + + '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f'). + replace(/ /g, ''), 'hex') + }, + 'nistp521': { + size: 521, + pkcs8oid: '1.3.132.0.35', + p: Buffer.from(( + '01ffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffff').replace(/ /g, ''), 'hex'), + a: Buffer.from(('01FF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC'). + replace(/ /g, ''), 'hex'), + b: Buffer.from(('51' + + '953eb961 8e1c9a1f 929a21a0 b68540ee' + + 'a2da725b 99b315f3 b8b48991 8ef109e1' + + '56193951 ec7e937b 1652c0bd 3bb1bf07' + + '3573df88 3d2c34f1 ef451fd4 6b503f00'). + replace(/ /g, ''), 'hex'), + s: Buffer.from(('00' + + 'd09e8800 291cb853 96cc6717 393284aa' + + 'a0da64ba').replace(/ /g, ''), 'hex'), + n: Buffer.from(('01ff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff fffffffa' + + '51868783 bf2f966b 7fcc0148 f709a5d0' + + '3bb5c9b8 899c47ae bb6fb71e 91386409'). + replace(/ /g, ''), 'hex'), + G: Buffer.from(('04' + + '00c6 858e06b7 0404e9cd 9e3ecb66 2395b442' + + '9c648139 053fb521 f828af60 6b4d3dba' + + 'a14b5e77 efe75928 fe1dc127 a2ffa8de' + + '3348b3c1 856a429b f97e7e31 c2e5bd66' + + '0118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9' + + '98f54449 579b4468 17afbd17 273e662c' + + '97ee7299 5ef42640 c550b901 3fad0761' + + '353c7086 a272c240 88be9476 9fd16650'). + replace(/ /g, ''), 'hex') + } +}; + +module.exports = { + info: algInfo, + privInfo: algPrivInfo, + hashAlgs: hashAlgs, + curves: curves +}; + + +/***/ }), +/* 33 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2017 Joyent, Inc. + +module.exports = PrivateKey; + +var assert = __webpack_require__(16); +var Buffer = __webpack_require__(15).Buffer; +var algs = __webpack_require__(32); +var crypto = __webpack_require__(11); +var Fingerprint = __webpack_require__(156); +var Signature = __webpack_require__(75); +var errs = __webpack_require__(74); +var util = __webpack_require__(3); +var utils = __webpack_require__(26); +var dhe = __webpack_require__(325); +var generateECDSA = dhe.generateECDSA; +var generateED25519 = dhe.generateED25519; +var edCompat; +var nacl; + +try { + edCompat = __webpack_require__(454); +} catch (e) { + /* Just continue through, and bail out if we try to use it. */ +} + +var Key = __webpack_require__(27); + +var InvalidAlgorithmError = errs.InvalidAlgorithmError; +var KeyParseError = errs.KeyParseError; +var KeyEncryptedError = errs.KeyEncryptedError; + +var formats = {}; +formats['auto'] = __webpack_require__(455); +formats['pem'] = __webpack_require__(86); +formats['pkcs1'] = __webpack_require__(327); +formats['pkcs8'] = __webpack_require__(157); +formats['rfc4253'] = __webpack_require__(103); +formats['ssh-private'] = __webpack_require__(192); +formats['openssh'] = formats['ssh-private']; +formats['ssh'] = formats['ssh-private']; +formats['dnssec'] = __webpack_require__(326); + +function PrivateKey(opts) { + assert.object(opts, 'options'); + Key.call(this, opts); + + this._pubCache = undefined; +} +util.inherits(PrivateKey, Key); + +PrivateKey.formats = formats; + +PrivateKey.prototype.toBuffer = function (format, options) { + if (format === undefined) + format = 'pkcs1'; + assert.string(format, 'format'); + assert.object(formats[format], 'formats[format]'); + assert.optionalObject(options, 'options'); + + return (formats[format].write(this, options)); +}; + +PrivateKey.prototype.hash = function (algo) { + return (this.toPublic().hash(algo)); +}; + +PrivateKey.prototype.toPublic = function () { + if (this._pubCache) + return (this._pubCache); + + var algInfo = algs.info[this.type]; + var pubParts = []; + for (var i = 0; i < algInfo.parts.length; ++i) { + var p = algInfo.parts[i]; + pubParts.push(this.part[p]); + } + + this._pubCache = new Key({ + type: this.type, + source: this, + parts: pubParts + }); + if (this.comment) + this._pubCache.comment = this.comment; + return (this._pubCache); +}; + +PrivateKey.prototype.derive = function (newType) { + assert.string(newType, 'type'); + var priv, pub, pair; + + if (this.type === 'ed25519' && newType === 'curve25519') { + if (nacl === undefined) + nacl = __webpack_require__(76); + + priv = this.part.k.data; + if (priv[0] === 0x00) + priv = priv.slice(1); + + pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv)); + pub = Buffer.from(pair.publicKey); + + return (new PrivateKey({ + type: 'curve25519', + parts: [ + { name: 'A', data: utils.mpNormalize(pub) }, + { name: 'k', data: utils.mpNormalize(priv) } + ] + })); + } else if (this.type === 'curve25519' && newType === 'ed25519') { + if (nacl === undefined) + nacl = __webpack_require__(76); + + priv = this.part.k.data; + if (priv[0] === 0x00) + priv = priv.slice(1); + + pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv)); + pub = Buffer.from(pair.publicKey); + + return (new PrivateKey({ + type: 'ed25519', + parts: [ + { name: 'A', data: utils.mpNormalize(pub) }, + { name: 'k', data: utils.mpNormalize(priv) } + ] + })); + } + throw (new Error('Key derivation not supported from ' + this.type + + ' to ' + newType)); +}; + +PrivateKey.prototype.createVerify = function (hashAlgo) { + return (this.toPublic().createVerify(hashAlgo)); +}; + +PrivateKey.prototype.createSign = function (hashAlgo) { + if (hashAlgo === undefined) + hashAlgo = this.defaultHashAlgorithm(); + assert.string(hashAlgo, 'hash algorithm'); + + /* ED25519 is not supported by OpenSSL, use a javascript impl. */ + if (this.type === 'ed25519' && edCompat !== undefined) + return (new edCompat.Signer(this, hashAlgo)); + if (this.type === 'curve25519') + throw (new Error('Curve25519 keys are not suitable for ' + + 'signing or verification')); + + var v, nm, err; + try { + nm = hashAlgo.toUpperCase(); + v = crypto.createSign(nm); + } catch (e) { + err = e; + } + if (v === undefined || (err instanceof Error && + err.message.match(/Unknown message digest/))) { + nm = 'RSA-'; + nm += hashAlgo.toUpperCase(); + v = crypto.createSign(nm); + } + assert.ok(v, 'failed to create verifier'); + var oldSign = v.sign.bind(v); + var key = this.toBuffer('pkcs1'); + var type = this.type; + var curve = this.curve; + v.sign = function () { + var sig = oldSign(key); + if (typeof (sig) === 'string') + sig = Buffer.from(sig, 'binary'); + sig = Signature.parse(sig, type, 'asn1'); + sig.hashAlgorithm = hashAlgo; + sig.curve = curve; + return (sig); + }; + return (v); +}; + +PrivateKey.parse = function (data, format, options) { + if (typeof (data) !== 'string') + assert.buffer(data, 'data'); + if (format === undefined) + format = 'auto'; + assert.string(format, 'format'); + if (typeof (options) === 'string') + options = { filename: options }; + assert.optionalObject(options, 'options'); + if (options === undefined) + options = {}; + assert.optionalString(options.filename, 'options.filename'); + if (options.filename === undefined) + options.filename = '(unnamed)'; + + assert.object(formats[format], 'formats[format]'); + + try { + var k = formats[format].read(data, options); + assert.ok(k instanceof PrivateKey, 'key is not a private key'); + if (!k.comment) + k.comment = options.filename; + return (k); + } catch (e) { + if (e.name === 'KeyEncryptedError') + throw (e); + throw (new KeyParseError(options.filename, format, e)); + } +}; + +PrivateKey.isPrivateKey = function (obj, ver) { + return (utils.isCompatible(obj, PrivateKey, ver)); +}; + +PrivateKey.generate = function (type, options) { + if (options === undefined) + options = {}; + assert.object(options, 'options'); + + switch (type) { + case 'ecdsa': + if (options.curve === undefined) + options.curve = 'nistp256'; + assert.string(options.curve, 'options.curve'); + return (generateECDSA(options.curve)); + case 'ed25519': + return (generateED25519()); + default: + throw (new Error('Key generation not supported with key ' + + 'type "' + type + '"')); + } +}; + +/* + * API versions for PrivateKey: + * [1,0] -- initial ver + * [1,1] -- added auto, pkcs[18], openssh/ssh-private formats + * [1,2] -- added defaultHashAlgorithm + * [1,3] -- added derive, ed, createDH + * [1,4] -- first tagged version + * [1,5] -- changed ed25519 part names and format + */ +PrivateKey.prototype._sshpkApiVersion = [1, 5]; + +PrivateKey._oldVersionDetect = function (obj) { + assert.func(obj.toPublic); + assert.func(obj.createSign); + if (obj.derive) + return ([1, 3]); + if (obj.defaultHashAlgorithm) + return ([1, 2]); + if (obj.formats['auto']) + return ([1, 1]); + return ([1, 0]); +}; + + +/***/ }), +/* 34 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.wrapLifecycle = exports.run = exports.install = exports.Install = undefined; + +var _extends2; + +function _load_extends() { + return _extends2 = _interopRequireDefault(__webpack_require__(21)); +} + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +let install = exports.install = (() => { + var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, lockfile) { + yield wrapLifecycle(config, flags, (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const install = new Install(flags, config, reporter, lockfile); + yield install.init(); + })); + }); + + return function install(_x7, _x8, _x9, _x10) { + return _ref29.apply(this, arguments); + }; +})(); + +let run = exports.run = (() => { + var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + let lockfile; + let error = 'installCommandRenamed'; + if (flags.lockfile === false) { + lockfile = new (_lockfile || _load_lockfile()).default(); + } else { + lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.lockfileFolder, reporter); + } + + if (args.length) { + const exampleArgs = args.slice(); + + if (flags.saveDev) { + exampleArgs.push('--dev'); + } + if (flags.savePeer) { + exampleArgs.push('--peer'); + } + if (flags.saveOptional) { + exampleArgs.push('--optional'); + } + if (flags.saveExact) { + exampleArgs.push('--exact'); + } + if (flags.saveTilde) { + exampleArgs.push('--tilde'); + } + let command = 'add'; + if (flags.global) { + error = 'globalFlagRemoved'; + command = 'global add'; + } + throw new (_errors || _load_errors()).MessageError(reporter.lang(error, `yarn ${command} ${exampleArgs.join(' ')}`)); + } + + yield install(config, reporter, flags, lockfile); + }); + + return function run(_x11, _x12, _x13, _x14) { + return _ref31.apply(this, arguments); + }; +})(); + +let wrapLifecycle = exports.wrapLifecycle = (() => { + var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, flags, factory) { + yield config.executeLifecycleScript('preinstall'); + + yield factory(); + + // npm behaviour, seems kinda funky but yay compatibility + yield config.executeLifecycleScript('install'); + yield config.executeLifecycleScript('postinstall'); + + if (!config.production) { + if (!config.disablePrepublish) { + yield config.executeLifecycleScript('prepublish'); + } + yield config.executeLifecycleScript('prepare'); + } + }); + + return function wrapLifecycle(_x15, _x16, _x17) { + return _ref32.apply(this, arguments); + }; +})(); + +exports.hasWrapper = hasWrapper; +exports.setFlags = setFlags; + +var _objectPath; + +function _load_objectPath() { + return _objectPath = _interopRequireDefault(__webpack_require__(304)); +} + +var _hooks; + +function _load_hooks() { + return _hooks = __webpack_require__(374); +} + +var _index; + +function _load_index() { + return _index = _interopRequireDefault(__webpack_require__(220)); +} + +var _errors; + +function _load_errors() { + return _errors = __webpack_require__(6); +} + +var _integrityChecker; + +function _load_integrityChecker() { + return _integrityChecker = _interopRequireDefault(__webpack_require__(208)); +} + +var _lockfile; + +function _load_lockfile() { + return _lockfile = _interopRequireDefault(__webpack_require__(19)); +} + +var _lockfile2; + +function _load_lockfile2() { + return _lockfile2 = __webpack_require__(19); +} + +var _packageFetcher; + +function _load_packageFetcher() { + return _packageFetcher = _interopRequireWildcard(__webpack_require__(210)); +} + +var _packageInstallScripts; + +function _load_packageInstallScripts() { + return _packageInstallScripts = _interopRequireDefault(__webpack_require__(557)); +} + +var _packageCompatibility; + +function _load_packageCompatibility() { + return _packageCompatibility = _interopRequireWildcard(__webpack_require__(209)); +} + +var _packageResolver; + +function _load_packageResolver() { + return _packageResolver = _interopRequireDefault(__webpack_require__(366)); +} + +var _packageLinker; + +function _load_packageLinker() { + return _packageLinker = _interopRequireDefault(__webpack_require__(211)); +} + +var _index2; + +function _load_index2() { + return _index2 = __webpack_require__(57); +} + +var _index3; + +function _load_index3() { + return _index3 = __webpack_require__(78); +} + +var _autoclean; + +function _load_autoclean() { + return _autoclean = __webpack_require__(354); +} + +var _constants; + +function _load_constants() { + return _constants = _interopRequireWildcard(__webpack_require__(8)); +} + +var _normalizePattern; + +function _load_normalizePattern() { + return _normalizePattern = __webpack_require__(37); +} + +var _fs; + +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(4)); +} + +var _map; + +function _load_map() { + return _map = _interopRequireDefault(__webpack_require__(29)); +} + +var _yarnVersion; + +function _load_yarnVersion() { + return _yarnVersion = __webpack_require__(120); +} + +var _generatePnpMap; + +function _load_generatePnpMap() { + return _generatePnpMap = __webpack_require__(579); +} + +var _workspaceLayout; + +function _load_workspaceLayout() { + return _workspaceLayout = _interopRequireDefault(__webpack_require__(90)); +} + +var _resolutionMap; + +function _load_resolutionMap() { + return _resolutionMap = _interopRequireDefault(__webpack_require__(214)); +} + +var _guessName; + +function _load_guessName() { + return _guessName = _interopRequireDefault(__webpack_require__(169)); +} + +var _audit; + +function _load_audit() { + return _audit = _interopRequireDefault(__webpack_require__(353)); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const deepEqual = __webpack_require__(631); + +const emoji = __webpack_require__(302); +const invariant = __webpack_require__(9); +const path = __webpack_require__(0); +const semver = __webpack_require__(22); +const uuid = __webpack_require__(119); +const ssri = __webpack_require__(65); + +const ONE_DAY = 1000 * 60 * 60 * 24; + +/** + * Try and detect the installation method for Yarn and provide a command to update it with. + */ + +function getUpdateCommand(installationMethod) { + if (installationMethod === 'tar') { + return `curl --compressed -o- -L ${(_constants || _load_constants()).YARN_INSTALLER_SH} | bash`; + } + + if (installationMethod === 'homebrew') { + return 'brew upgrade yarn'; + } + + if (installationMethod === 'deb') { + return 'sudo apt-get update && sudo apt-get install yarn'; + } + + if (installationMethod === 'rpm') { + return 'sudo yum install yarn'; + } + + if (installationMethod === 'npm') { + return 'npm install --global yarn'; + } + + if (installationMethod === 'chocolatey') { + return 'choco upgrade yarn'; + } + + if (installationMethod === 'apk') { + return 'apk update && apk add -u yarn'; + } + + if (installationMethod === 'portage') { + return 'sudo emerge --sync && sudo emerge -au sys-apps/yarn'; + } + + return null; +} + +function getUpdateInstaller(installationMethod) { + // Windows + if (installationMethod === 'msi') { + return (_constants || _load_constants()).YARN_INSTALLER_MSI; + } + + return null; +} + +function normalizeFlags(config, rawFlags) { + const flags = { + // install + har: !!rawFlags.har, + ignorePlatform: !!rawFlags.ignorePlatform, + ignoreEngines: !!rawFlags.ignoreEngines, + ignoreScripts: !!rawFlags.ignoreScripts, + ignoreOptional: !!rawFlags.ignoreOptional, + force: !!rawFlags.force, + flat: !!rawFlags.flat, + lockfile: rawFlags.lockfile !== false, + pureLockfile: !!rawFlags.pureLockfile, + updateChecksums: !!rawFlags.updateChecksums, + skipIntegrityCheck: !!rawFlags.skipIntegrityCheck, + frozenLockfile: !!rawFlags.frozenLockfile, + linkDuplicates: !!rawFlags.linkDuplicates, + checkFiles: !!rawFlags.checkFiles, + audit: !!rawFlags.audit, + + // add + peer: !!rawFlags.peer, + dev: !!rawFlags.dev, + optional: !!rawFlags.optional, + exact: !!rawFlags.exact, + tilde: !!rawFlags.tilde, + ignoreWorkspaceRootCheck: !!rawFlags.ignoreWorkspaceRootCheck, + + // outdated, update-interactive + includeWorkspaceDeps: !!rawFlags.includeWorkspaceDeps, + + // add, remove, update + workspaceRootIsCwd: rawFlags.workspaceRootIsCwd !== false + }; + + if (config.getOption('ignore-scripts')) { + flags.ignoreScripts = true; + } + + if (config.getOption('ignore-platform')) { + flags.ignorePlatform = true; + } + + if (config.getOption('ignore-engines')) { + flags.ignoreEngines = true; + } + + if (config.getOption('ignore-optional')) { + flags.ignoreOptional = true; + } + + if (config.getOption('force')) { + flags.force = true; + } + + return flags; +} + +class Install { + constructor(flags, config, reporter, lockfile) { + this.rootManifestRegistries = []; + this.rootPatternsToOrigin = (0, (_map || _load_map()).default)(); + this.lockfile = lockfile; + this.reporter = reporter; + this.config = config; + this.flags = normalizeFlags(config, flags); + this.resolutions = (0, (_map || _load_map()).default)(); // Legacy resolutions field used for flat install mode + this.resolutionMap = new (_resolutionMap || _load_resolutionMap()).default(config); // Selective resolutions for nested dependencies + this.resolver = new (_packageResolver || _load_packageResolver()).default(config, lockfile, this.resolutionMap); + this.integrityChecker = new (_integrityChecker || _load_integrityChecker()).default(config); + this.linker = new (_packageLinker || _load_packageLinker()).default(config, this.resolver); + this.scripts = new (_packageInstallScripts || _load_packageInstallScripts()).default(config, this.resolver, this.flags.force); + } + + /** + * Create a list of dependency requests from the current directories manifests. + */ + + fetchRequestFromCwd(excludePatterns = [], ignoreUnusedPatterns = false) { + var _this = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const patterns = []; + const deps = []; + let resolutionDeps = []; + const manifest = {}; + + const ignorePatterns = []; + const usedPatterns = []; + let workspaceLayout; + + // some commands should always run in the context of the entire workspace + const cwd = _this.flags.includeWorkspaceDeps || _this.flags.workspaceRootIsCwd ? _this.config.lockfileFolder : _this.config.cwd; + + // non-workspaces are always root, otherwise check for workspace root + const cwdIsRoot = !_this.config.workspaceRootFolder || _this.config.lockfileFolder === cwd; + + // exclude package names that are in install args + const excludeNames = []; + for (var _iterator = excludePatterns, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + const pattern = _ref; + + if ((0, (_index3 || _load_index3()).getExoticResolver)(pattern)) { + excludeNames.push((0, (_guessName || _load_guessName()).default)(pattern)); + } else { + // extract the name + const parts = (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern); + excludeNames.push(parts.name); + } + } + + const stripExcluded = function stripExcluded(manifest) { + for (var _iterator2 = excludeNames, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref2; + + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref2 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref2 = _i2.value; + } + + const exclude = _ref2; + + if (manifest.dependencies && manifest.dependencies[exclude]) { + delete manifest.dependencies[exclude]; + } + if (manifest.devDependencies && manifest.devDependencies[exclude]) { + delete manifest.devDependencies[exclude]; + } + if (manifest.optionalDependencies && manifest.optionalDependencies[exclude]) { + delete manifest.optionalDependencies[exclude]; + } + } + }; + + for (var _iterator3 = Object.keys((_index2 || _load_index2()).registries), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref3; + + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref3 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref3 = _i3.value; + } + + const registry = _ref3; + + const filename = (_index2 || _load_index2()).registries[registry].filename; + + const loc = path.join(cwd, filename); + if (!(yield (_fs || _load_fs()).exists(loc))) { + continue; + } + + _this.rootManifestRegistries.push(registry); + + const projectManifestJson = yield _this.config.readJson(loc); + yield (0, (_index || _load_index()).default)(projectManifestJson, cwd, _this.config, cwdIsRoot); + + Object.assign(_this.resolutions, projectManifestJson.resolutions); + Object.assign(manifest, projectManifestJson); + + _this.resolutionMap.init(_this.resolutions); + for (var _iterator4 = Object.keys(_this.resolutionMap.resolutionsByPackage), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref4; + + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref4 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref4 = _i4.value; + } + + const packageName = _ref4; + + const optional = (_objectPath || _load_objectPath()).default.has(manifest.optionalDependencies, packageName) && _this.flags.ignoreOptional; + for (var _iterator8 = _this.resolutionMap.resolutionsByPackage[packageName], _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { + var _ref9; + + if (_isArray8) { + if (_i8 >= _iterator8.length) break; + _ref9 = _iterator8[_i8++]; + } else { + _i8 = _iterator8.next(); + if (_i8.done) break; + _ref9 = _i8.value; + } + + const _ref8 = _ref9; + const pattern = _ref8.pattern; + + resolutionDeps = [...resolutionDeps, { registry, pattern, optional, hint: 'resolution' }]; + } + } + + const pushDeps = function pushDeps(depType, manifest, { hint, optional }, isUsed) { + if (ignoreUnusedPatterns && !isUsed) { + return; + } + // We only take unused dependencies into consideration to get deterministic hoisting. + // Since flat mode doesn't care about hoisting and everything is top level and specified then we can safely + // leave these out. + if (_this.flags.flat && !isUsed) { + return; + } + const depMap = manifest[depType]; + for (const name in depMap) { + if (excludeNames.indexOf(name) >= 0) { + continue; + } + + let pattern = name; + if (!_this.lockfile.getLocked(pattern)) { + // when we use --save we save the dependency to the lockfile with just the name rather than the + // version combo + pattern += '@' + depMap[name]; + } + + // normalization made sure packages are mentioned only once + if (isUsed) { + usedPatterns.push(pattern); + } else { + ignorePatterns.push(pattern); + } + + _this.rootPatternsToOrigin[pattern] = depType; + patterns.push(pattern); + deps.push({ pattern, registry, hint, optional, workspaceName: manifest.name, workspaceLoc: manifest._loc }); + } + }; + + if (cwdIsRoot) { + pushDeps('dependencies', projectManifestJson, { hint: null, optional: false }, true); + pushDeps('devDependencies', projectManifestJson, { hint: 'dev', optional: false }, !_this.config.production); + pushDeps('optionalDependencies', projectManifestJson, { hint: 'optional', optional: true }, true); + } + + if (_this.config.workspaceRootFolder) { + const workspaceLoc = cwdIsRoot ? loc : path.join(_this.config.lockfileFolder, filename); + const workspacesRoot = path.dirname(workspaceLoc); + + let workspaceManifestJson = projectManifestJson; + if (!cwdIsRoot) { + // the manifest we read before was a child workspace, so get the root + workspaceManifestJson = yield _this.config.readJson(workspaceLoc); + yield (0, (_index || _load_index()).default)(workspaceManifestJson, workspacesRoot, _this.config, true); + } + + const workspaces = yield _this.config.resolveWorkspaces(workspacesRoot, workspaceManifestJson); + workspaceLayout = new (_workspaceLayout || _load_workspaceLayout()).default(workspaces, _this.config); + + // add virtual manifest that depends on all workspaces, this way package hoisters and resolvers will work fine + const workspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.dependencies); + for (var _iterator5 = Object.keys(workspaces), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref5; + + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref5 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref5 = _i5.value; + } + + const workspaceName = _ref5; + + const workspaceManifest = workspaces[workspaceName].manifest; + workspaceDependencies[workspaceName] = workspaceManifest.version; + + // include dependencies from all workspaces + if (_this.flags.includeWorkspaceDeps) { + pushDeps('dependencies', workspaceManifest, { hint: null, optional: false }, true); + pushDeps('devDependencies', workspaceManifest, { hint: 'dev', optional: false }, !_this.config.production); + pushDeps('optionalDependencies', workspaceManifest, { hint: 'optional', optional: true }, true); + } + } + const virtualDependencyManifest = { + _uid: '', + name: `workspace-aggregator-${uuid.v4()}`, + version: '1.0.0', + _registry: 'npm', + _loc: workspacesRoot, + dependencies: workspaceDependencies, + devDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.devDependencies), + optionalDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.optionalDependencies), + private: workspaceManifestJson.private, + workspaces: workspaceManifestJson.workspaces + }; + workspaceLayout.virtualManifestName = virtualDependencyManifest.name; + const virtualDep = {}; + virtualDep[virtualDependencyManifest.name] = virtualDependencyManifest.version; + workspaces[virtualDependencyManifest.name] = { loc: workspacesRoot, manifest: virtualDependencyManifest }; + + // ensure dependencies that should be excluded are stripped from the correct manifest + stripExcluded(cwdIsRoot ? virtualDependencyManifest : workspaces[projectManifestJson.name].manifest); + + pushDeps('workspaces', { workspaces: virtualDep }, { hint: 'workspaces', optional: false }, true); + + const implicitWorkspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceDependencies); + + for (var _iterator6 = (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref6; + + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref6 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref6 = _i6.value; + } + + const type = _ref6; + + for (var _iterator7 = Object.keys(projectManifestJson[type] || {}), _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref7; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref7 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref7 = _i7.value; + } + + const dependencyName = _ref7; + + delete implicitWorkspaceDependencies[dependencyName]; + } + } + + pushDeps('dependencies', { dependencies: implicitWorkspaceDependencies }, { hint: 'workspaces', optional: false }, true); + } + + break; + } + + // inherit root flat flag + if (manifest.flat) { + _this.flags.flat = true; + } + + return { + requests: [...resolutionDeps, ...deps], + patterns, + manifest, + usedPatterns, + ignorePatterns, + workspaceLayout + }; + })(); + } + + /** + * TODO description + */ + + prepareRequests(requests) { + return requests; + } + + preparePatterns(patterns) { + return patterns; + } + preparePatternsForLinking(patterns, cwdManifest, cwdIsRoot) { + return patterns; + } + + prepareManifests() { + var _this2 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const manifests = yield _this2.config.getRootManifests(); + return manifests; + })(); + } + + bailout(patterns, workspaceLayout) { + var _this3 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // We don't want to skip the audit - it could yield important errors + if (_this3.flags.audit) { + return false; + } + // PNP is so fast that the integrity check isn't pertinent + if (_this3.config.plugnplayEnabled) { + return false; + } + if (_this3.flags.skipIntegrityCheck || _this3.flags.force) { + return false; + } + const lockfileCache = _this3.lockfile.cache; + if (!lockfileCache) { + return false; + } + const lockfileClean = _this3.lockfile.parseResultType === 'success'; + const match = yield _this3.integrityChecker.check(patterns, lockfileCache, _this3.flags, workspaceLayout); + if (_this3.flags.frozenLockfile && (!lockfileClean || match.missingPatterns.length > 0)) { + throw new (_errors || _load_errors()).MessageError(_this3.reporter.lang('frozenLockfileError')); + } + + const haveLockfile = yield (_fs || _load_fs()).exists(path.join(_this3.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME)); + + const lockfileIntegrityPresent = !_this3.lockfile.hasEntriesExistWithoutIntegrity(); + const integrityBailout = lockfileIntegrityPresent || !_this3.config.autoAddIntegrity; + + if (match.integrityMatches && haveLockfile && lockfileClean && integrityBailout) { + _this3.reporter.success(_this3.reporter.lang('upToDate')); + return true; + } + + if (match.integrityFileMissing && haveLockfile) { + // Integrity file missing, force script installations + _this3.scripts.setForce(true); + return false; + } + + if (match.hardRefreshRequired) { + // e.g. node version doesn't match, force script installations + _this3.scripts.setForce(true); + return false; + } + + if (!patterns.length && !match.integrityFileMissing) { + _this3.reporter.success(_this3.reporter.lang('nothingToInstall')); + yield _this3.createEmptyManifestFolders(); + yield _this3.saveLockfileAndIntegrity(patterns, workspaceLayout); + return true; + } + + return false; + })(); + } + + /** + * Produce empty folders for all used root manifests. + */ + + createEmptyManifestFolders() { + var _this4 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + if (_this4.config.modulesFolder) { + // already created + return; + } + + for (var _iterator9 = _this4.rootManifestRegistries, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref10; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref10 = _iterator9[_i9++]; + } else { + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref10 = _i9.value; + } + + const registryName = _ref10; + const folder = _this4.config.registries[registryName].folder; + + yield (_fs || _load_fs()).mkdirp(path.join(_this4.config.lockfileFolder, folder)); + } + })(); + } + + /** + * TODO description + */ + + markIgnored(patterns) { + for (var _iterator10 = patterns, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref11; + + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref11 = _iterator10[_i10++]; + } else { + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref11 = _i10.value; + } + + const pattern = _ref11; + + const manifest = this.resolver.getStrictResolvedPattern(pattern); + const ref = manifest._reference; + invariant(ref, 'expected package reference'); + + // just mark the package as ignored. if the package is used by a required package, the hoister + // will take care of that. + ref.ignore = true; + } + } + + /** + * helper method that gets only recent manifests + * used by global.ls command + */ + getFlattenedDeps() { + var _this5 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + var _ref12 = yield _this5.fetchRequestFromCwd(); + + const depRequests = _ref12.requests, + rawPatterns = _ref12.patterns; + + + yield _this5.resolver.init(depRequests, {}); + + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this5.resolver.getManifests(), _this5.config); + _this5.resolver.updateManifests(manifests); + + return _this5.flatten(rawPatterns); + })(); + } + + /** + * TODO description + */ + + init() { + var _this6 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.checkUpdate(); + + // warn if we have a shrinkwrap + if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_SHRINKWRAP_FILENAME))) { + _this6.reporter.warn(_this6.reporter.lang('shrinkwrapWarning')); + } + + // warn if we have an npm lockfile + if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_LOCK_FILENAME))) { + _this6.reporter.warn(_this6.reporter.lang('npmLockfileWarning')); + } + + if (_this6.config.plugnplayEnabled) { + _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L1')); + _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L2')); + } + + let flattenedTopLevelPatterns = []; + const steps = []; + + var _ref13 = yield _this6.fetchRequestFromCwd(); + + const depRequests = _ref13.requests, + rawPatterns = _ref13.patterns, + ignorePatterns = _ref13.ignorePatterns, + workspaceLayout = _ref13.workspaceLayout, + manifest = _ref13.manifest; + + let topLevelPatterns = []; + + const artifacts = yield _this6.integrityChecker.getArtifacts(); + if (artifacts) { + _this6.linker.setArtifacts(artifacts); + _this6.scripts.setArtifacts(artifacts); + } + + if ((_packageCompatibility || _load_packageCompatibility()).shouldCheck(manifest, _this6.flags)) { + steps.push((() => { + var _ref14 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { + _this6.reporter.step(curr, total, _this6.reporter.lang('checkingManifest'), emoji.get('mag')); + yield _this6.checkCompatibility(); + }); + + return function (_x, _x2) { + return _ref14.apply(this, arguments); + }; + })()); + } + + const audit = new (_audit || _load_audit()).default(_this6.config, _this6.reporter, { groups: (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES }); + let auditFoundProblems = false; + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('resolveStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.reporter.step(curr, total, _this6.reporter.lang('resolvingPackages'), emoji.get('mag')); + yield _this6.resolver.init(_this6.prepareRequests(depRequests), { + isFlat: _this6.flags.flat, + isFrozen: _this6.flags.frozenLockfile, + workspaceLayout + }); + topLevelPatterns = _this6.preparePatterns(rawPatterns); + flattenedTopLevelPatterns = yield _this6.flatten(topLevelPatterns); + return { bailout: !_this6.flags.audit && (yield _this6.bailout(topLevelPatterns, workspaceLayout)) }; + })); + }); + + if (_this6.flags.audit) { + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('auditStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.reporter.step(curr, total, _this6.reporter.lang('auditRunning'), emoji.get('mag')); + if (_this6.flags.offline) { + _this6.reporter.warn(_this6.reporter.lang('auditOffline')); + return { bailout: false }; + } + const preparedManifests = yield _this6.prepareManifests(); + // $FlowFixMe - Flow considers `m` in the map operation to be "mixed", so does not recognize `m.object` + const mergedManifest = Object.assign({}, ...Object.values(preparedManifests).map(function (m) { + return m.object; + })); + const auditVulnerabilityCounts = yield audit.performAudit(mergedManifest, _this6.lockfile, _this6.resolver, _this6.linker, topLevelPatterns); + auditFoundProblems = auditVulnerabilityCounts.info || auditVulnerabilityCounts.low || auditVulnerabilityCounts.moderate || auditVulnerabilityCounts.high || auditVulnerabilityCounts.critical; + return { bailout: yield _this6.bailout(topLevelPatterns, workspaceLayout) }; + })); + }); + } + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('fetchStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.markIgnored(ignorePatterns); + _this6.reporter.step(curr, total, _this6.reporter.lang('fetchingPackages'), emoji.get('truck')); + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this6.resolver.getManifests(), _this6.config); + _this6.resolver.updateManifests(manifests); + yield (_packageCompatibility || _load_packageCompatibility()).check(_this6.resolver.getManifests(), _this6.config, _this6.flags.ignoreEngines); + })); + }); + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('linkStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // remove integrity hash to make this operation atomic + yield _this6.integrityChecker.removeIntegrityFile(); + _this6.reporter.step(curr, total, _this6.reporter.lang('linkingDependencies'), emoji.get('link')); + flattenedTopLevelPatterns = _this6.preparePatternsForLinking(flattenedTopLevelPatterns, manifest, _this6.config.lockfileFolder === _this6.config.cwd); + yield _this6.linker.init(flattenedTopLevelPatterns, workspaceLayout, { + linkDuplicates: _this6.flags.linkDuplicates, + ignoreOptional: _this6.flags.ignoreOptional + }); + })); + }); + + if (_this6.config.plugnplayEnabled) { + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('pnpStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const pnpPath = `${_this6.config.lockfileFolder}/${(_constants || _load_constants()).PNP_FILENAME}`; + + const code = yield (0, (_generatePnpMap || _load_generatePnpMap()).generatePnpMap)(_this6.config, flattenedTopLevelPatterns, { + resolver: _this6.resolver, + reporter: _this6.reporter, + targetPath: pnpPath, + workspaceLayout + }); + + try { + const file = yield (_fs || _load_fs()).readFile(pnpPath); + if (file === code) { + return; + } + } catch (error) {} + + yield (_fs || _load_fs()).writeFile(pnpPath, code); + yield (_fs || _load_fs()).chmod(pnpPath, 0o755); + })); + }); + } + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('buildStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.reporter.step(curr, total, _this6.flags.force ? _this6.reporter.lang('rebuildingPackages') : _this6.reporter.lang('buildingFreshPackages'), emoji.get('hammer')); + + if (_this6.config.ignoreScripts) { + _this6.reporter.warn(_this6.reporter.lang('ignoredScripts')); + } else { + yield _this6.scripts.init(flattenedTopLevelPatterns); + } + })); + }); + + if (_this6.flags.har) { + steps.push((() => { + var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { + const formattedDate = new Date().toISOString().replace(/:/g, '-'); + const filename = `yarn-install_${formattedDate}.har`; + _this6.reporter.step(curr, total, _this6.reporter.lang('savingHar', filename), emoji.get('black_circle_for_record')); + yield _this6.config.requestManager.saveHar(filename); + }); + + return function (_x3, _x4) { + return _ref21.apply(this, arguments); + }; + })()); + } + + if (yield _this6.shouldClean()) { + steps.push((() => { + var _ref22 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { + _this6.reporter.step(curr, total, _this6.reporter.lang('cleaningModules'), emoji.get('recycle')); + yield (0, (_autoclean || _load_autoclean()).clean)(_this6.config, _this6.reporter); + }); + + return function (_x5, _x6) { + return _ref22.apply(this, arguments); + }; + })()); + } + + let currentStep = 0; + for (var _iterator11 = steps, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref23; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref23 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref23 = _i11.value; + } + + const step = _ref23; + + const stepResult = yield step(++currentStep, steps.length); + if (stepResult && stepResult.bailout) { + if (_this6.flags.audit) { + audit.summary(); + } + if (auditFoundProblems) { + _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); + } + _this6.maybeOutputUpdate(); + return flattenedTopLevelPatterns; + } + } + + // fin! + if (_this6.flags.audit) { + audit.summary(); + } + if (auditFoundProblems) { + _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); + } + yield _this6.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout); + yield _this6.persistChanges(); + _this6.maybeOutputUpdate(); + _this6.config.requestManager.clearCache(); + return flattenedTopLevelPatterns; + })(); + } + + checkCompatibility() { + var _this7 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + var _ref24 = yield _this7.fetchRequestFromCwd(); + + const manifest = _ref24.manifest; + + yield (_packageCompatibility || _load_packageCompatibility()).checkOne(manifest, _this7.config, _this7.flags.ignoreEngines); + })(); + } + + persistChanges() { + var _this8 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // get all the different registry manifests in this folder + const manifests = yield _this8.config.getRootManifests(); + + if (yield _this8.applyChanges(manifests)) { + yield _this8.config.saveRootManifests(manifests); + } + })(); + } + + applyChanges(manifests) { + let hasChanged = false; + + if (this.config.plugnplayPersist) { + const object = manifests.npm.object; + + + if (typeof object.installConfig !== 'object') { + object.installConfig = {}; + } + + if (this.config.plugnplayEnabled && object.installConfig.pnp !== true) { + object.installConfig.pnp = true; + hasChanged = true; + } else if (!this.config.plugnplayEnabled && typeof object.installConfig.pnp !== 'undefined') { + delete object.installConfig.pnp; + hasChanged = true; + } + + if (Object.keys(object.installConfig).length === 0) { + delete object.installConfig; + } + } + + return Promise.resolve(hasChanged); + } + + /** + * Check if we should run the cleaning step. + */ + + shouldClean() { + return (_fs || _load_fs()).exists(path.join(this.config.lockfileFolder, (_constants || _load_constants()).CLEAN_FILENAME)); + } + + /** + * TODO + */ + + flatten(patterns) { + var _this9 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + if (!_this9.flags.flat) { + return patterns; + } + + const flattenedPatterns = []; + + for (var _iterator12 = _this9.resolver.getAllDependencyNamesByLevelOrder(patterns), _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref25; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref25 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref25 = _i12.value; + } + + const name = _ref25; + + const infos = _this9.resolver.getAllInfoForPackageName(name).filter(function (manifest) { + const ref = manifest._reference; + invariant(ref, 'expected package reference'); + return !ref.ignore; + }); + + if (infos.length === 0) { + continue; + } + + if (infos.length === 1) { + // single version of this package + // take out a single pattern as multiple patterns may have resolved to this package + flattenedPatterns.push(_this9.resolver.patternsByPackage[name][0]); + continue; + } + + const options = infos.map(function (info) { + const ref = info._reference; + invariant(ref, 'expected reference'); + return { + // TODO `and is required by {PARENT}`, + name: _this9.reporter.lang('manualVersionResolutionOption', ref.patterns.join(', '), info.version), + + value: info.version + }; + }); + const versions = infos.map(function (info) { + return info.version; + }); + let version; + + const resolutionVersion = _this9.resolutions[name]; + if (resolutionVersion && versions.indexOf(resolutionVersion) >= 0) { + // use json `resolution` version + version = resolutionVersion; + } else { + version = yield _this9.reporter.select(_this9.reporter.lang('manualVersionResolution', name), _this9.reporter.lang('answer'), options); + _this9.resolutions[name] = version; + } + + flattenedPatterns.push(_this9.resolver.collapseAllVersionsOfPackage(name, version)); + } + + // save resolutions to their appropriate root manifest + if (Object.keys(_this9.resolutions).length) { + const manifests = yield _this9.config.getRootManifests(); + + for (const name in _this9.resolutions) { + const version = _this9.resolutions[name]; + + const patterns = _this9.resolver.patternsByPackage[name]; + if (!patterns) { + continue; + } + + let manifest; + for (var _iterator13 = patterns, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { + var _ref26; + + if (_isArray13) { + if (_i13 >= _iterator13.length) break; + _ref26 = _iterator13[_i13++]; + } else { + _i13 = _iterator13.next(); + if (_i13.done) break; + _ref26 = _i13.value; + } + + const pattern = _ref26; + + manifest = _this9.resolver.getResolvedPattern(pattern); + if (manifest) { + break; + } + } + invariant(manifest, 'expected manifest'); + + const ref = manifest._reference; + invariant(ref, 'expected reference'); + + const object = manifests[ref.registry].object; + object.resolutions = object.resolutions || {}; + object.resolutions[name] = version; + } + + yield _this9.config.saveRootManifests(manifests); + } + + return flattenedPatterns; + })(); + } + + /** + * Remove offline tarballs that are no longer required + */ + + pruneOfflineMirror(lockfile) { + var _this10 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const mirror = _this10.config.getOfflineMirrorPath(); + if (!mirror) { + return; + } + + const requiredTarballs = new Set(); + for (const dependency in lockfile) { + const resolved = lockfile[dependency].resolved; + if (resolved) { + const basename = path.basename(resolved.split('#')[0]); + if (dependency[0] === '@' && basename[0] !== '@') { + requiredTarballs.add(`${dependency.split('/')[0]}-${basename}`); + } + requiredTarballs.add(basename); + } + } + + const mirrorFiles = yield (_fs || _load_fs()).walk(mirror); + for (var _iterator14 = mirrorFiles, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { + var _ref27; + + if (_isArray14) { + if (_i14 >= _iterator14.length) break; + _ref27 = _iterator14[_i14++]; + } else { + _i14 = _iterator14.next(); + if (_i14.done) break; + _ref27 = _i14.value; + } + + const file = _ref27; + + const isTarball = path.extname(file.basename) === '.tgz'; + // if using experimental-pack-script-packages-in-mirror flag, don't unlink prebuilt packages + const hasPrebuiltPackage = file.relative.startsWith('prebuilt/'); + if (isTarball && !hasPrebuiltPackage && !requiredTarballs.has(file.basename)) { + yield (_fs || _load_fs()).unlink(file.absolute); + } + } + })(); + } + + /** + * Save updated integrity and lockfiles. + */ + + saveLockfileAndIntegrity(patterns, workspaceLayout) { + var _this11 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const resolvedPatterns = {}; + Object.keys(_this11.resolver.patterns).forEach(function (pattern) { + if (!workspaceLayout || !workspaceLayout.getManifestByPattern(pattern)) { + resolvedPatterns[pattern] = _this11.resolver.patterns[pattern]; + } + }); + + // TODO this code is duplicated in a few places, need a common way to filter out workspace patterns from lockfile + patterns = patterns.filter(function (p) { + return !workspaceLayout || !workspaceLayout.getManifestByPattern(p); + }); + + const lockfileBasedOnResolver = _this11.lockfile.getLockfile(resolvedPatterns); + + if (_this11.config.pruneOfflineMirror) { + yield _this11.pruneOfflineMirror(lockfileBasedOnResolver); + } + + // write integrity hash + if (!_this11.config.plugnplayEnabled) { + yield _this11.integrityChecker.save(patterns, lockfileBasedOnResolver, _this11.flags, workspaceLayout, _this11.scripts.getArtifacts()); + } + + // --no-lockfile or --pure-lockfile or --frozen-lockfile + if (_this11.flags.lockfile === false || _this11.flags.pureLockfile || _this11.flags.frozenLockfile) { + return; + } + + const lockFileHasAllPatterns = patterns.every(function (p) { + return _this11.lockfile.getLocked(p); + }); + const lockfilePatternsMatch = Object.keys(_this11.lockfile.cache || {}).every(function (p) { + return lockfileBasedOnResolver[p]; + }); + const resolverPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { + const manifest = _this11.lockfile.getLocked(pattern); + return manifest && manifest.resolved === lockfileBasedOnResolver[pattern].resolved && deepEqual(manifest.prebuiltVariants, lockfileBasedOnResolver[pattern].prebuiltVariants); + }); + const integrityPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { + const existingIntegrityInfo = lockfileBasedOnResolver[pattern].integrity; + if (!existingIntegrityInfo) { + // if this entry does not have an integrity, no need to re-write the lockfile because of it + return true; + } + const manifest = _this11.lockfile.getLocked(pattern); + if (manifest && manifest.integrity) { + const manifestIntegrity = ssri.stringify(manifest.integrity); + return manifestIntegrity === existingIntegrityInfo; + } + return false; + }); + + // remove command is followed by install with force, lockfile will be rewritten in any case then + if (!_this11.flags.force && _this11.lockfile.parseResultType === 'success' && lockFileHasAllPatterns && lockfilePatternsMatch && resolverPatternsAreSameAsInLockfile && integrityPatternsAreSameAsInLockfile && patterns.length) { + return; + } + + // build lockfile location + const loc = path.join(_this11.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME); + + // write lockfile + const lockSource = (0, (_lockfile2 || _load_lockfile2()).stringify)(lockfileBasedOnResolver, false, _this11.config.enableLockfileVersions); + yield (_fs || _load_fs()).writeFilePreservingEol(loc, lockSource); + + _this11._logSuccessSaveLockfile(); + })(); + } + + _logSuccessSaveLockfile() { + this.reporter.success(this.reporter.lang('savedLockfile')); + } + + /** + * Load the dependency graph of the current install. Only does package resolving and wont write to the cwd. + */ + hydrate(ignoreUnusedPatterns) { + var _this12 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const request = yield _this12.fetchRequestFromCwd([], ignoreUnusedPatterns); + const depRequests = request.requests, + rawPatterns = request.patterns, + ignorePatterns = request.ignorePatterns, + workspaceLayout = request.workspaceLayout; + + + yield _this12.resolver.init(depRequests, { + isFlat: _this12.flags.flat, + isFrozen: _this12.flags.frozenLockfile, + workspaceLayout + }); + yield _this12.flatten(rawPatterns); + _this12.markIgnored(ignorePatterns); + + // fetch packages, should hit cache most of the time + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this12.resolver.getManifests(), _this12.config); + _this12.resolver.updateManifests(manifests); + yield (_packageCompatibility || _load_packageCompatibility()).check(_this12.resolver.getManifests(), _this12.config, _this12.flags.ignoreEngines); + + // expand minimal manifests + for (var _iterator15 = _this12.resolver.getManifests(), _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { + var _ref28; + + if (_isArray15) { + if (_i15 >= _iterator15.length) break; + _ref28 = _iterator15[_i15++]; + } else { + _i15 = _iterator15.next(); + if (_i15.done) break; + _ref28 = _i15.value; + } + + const manifest = _ref28; + + const ref = manifest._reference; + invariant(ref, 'expected reference'); + const type = ref.remote.type; + // link specifier won't ever hit cache + + let loc = ''; + if (type === 'link') { + continue; + } else if (type === 'workspace') { + if (!ref.remote.reference) { + continue; + } + loc = ref.remote.reference; + } else { + loc = _this12.config.generateModuleCachePath(ref); + } + const newPkg = yield _this12.config.readManifest(loc); + yield _this12.resolver.updateManifest(ref, newPkg); + } + + return request; + })(); + } + + /** + * Check for updates every day and output a nag message if there's a newer version. + */ + + checkUpdate() { + if (this.config.nonInteractive) { + // don't show upgrade dialog on CI or non-TTY terminals + return; + } + + // don't check if disabled + if (this.config.getOption('disable-self-update-check')) { + return; + } + + // only check for updates once a day + const lastUpdateCheck = Number(this.config.getOption('lastUpdateCheck')) || 0; + if (lastUpdateCheck && Date.now() - lastUpdateCheck < ONE_DAY) { + return; + } + + // don't bug for updates on tagged releases + if ((_yarnVersion || _load_yarnVersion()).version.indexOf('-') >= 0) { + return; + } + + this._checkUpdate().catch(() => { + // swallow errors + }); + } + + _checkUpdate() { + var _this13 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + let latestVersion = yield _this13.config.requestManager.request({ + url: (_constants || _load_constants()).SELF_UPDATE_VERSION_URL + }); + invariant(typeof latestVersion === 'string', 'expected string'); + latestVersion = latestVersion.trim(); + if (!semver.valid(latestVersion)) { + return; + } + + // ensure we only check for updates periodically + _this13.config.registries.yarn.saveHomeConfig({ + lastUpdateCheck: Date.now() + }); + + if (semver.gt(latestVersion, (_yarnVersion || _load_yarnVersion()).version)) { + const installationMethod = yield (0, (_yarnVersion || _load_yarnVersion()).getInstallationMethod)(); + _this13.maybeOutputUpdate = function () { + _this13.reporter.warn(_this13.reporter.lang('yarnOutdated', latestVersion, (_yarnVersion || _load_yarnVersion()).version)); + + const command = getUpdateCommand(installationMethod); + if (command) { + _this13.reporter.info(_this13.reporter.lang('yarnOutdatedCommand')); + _this13.reporter.command(command); + } else { + const installer = getUpdateInstaller(installationMethod); + if (installer) { + _this13.reporter.info(_this13.reporter.lang('yarnOutdatedInstaller', installer)); + } + } + }; + } + })(); + } + + /** + * Method to override with a possible upgrade message. + */ + + maybeOutputUpdate() {} +} + +exports.Install = Install; +function hasWrapper(commander, args) { + return true; +} + +function setFlags(commander) { + commander.description('Yarn install is used to install all dependencies for a project.'); + commander.usage('install [flags]'); + commander.option('-A, --audit', 'Run vulnerability audit on installed packages'); + commander.option('-g, --global', 'DEPRECATED'); + commander.option('-S, --save', 'DEPRECATED - save package to your `dependencies`'); + commander.option('-D, --save-dev', 'DEPRECATED - save package to your `devDependencies`'); + commander.option('-P, --save-peer', 'DEPRECATED - save package to your `peerDependencies`'); + commander.option('-O, --save-optional', 'DEPRECATED - save package to your `optionalDependencies`'); + commander.option('-E, --save-exact', 'DEPRECATED'); + commander.option('-T, --save-tilde', 'DEPRECATED'); +} + +/***/ }), +/* 35 */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(52); +module.exports = function (it) { + if (!isObject(it)) throw TypeError(it + ' is not an object!'); + return it; +}; + + +/***/ }), +/* 36 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return SubjectSubscriber; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subject; }); +/* unused harmony export AnonymousSubject */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Observable__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Subscriber__ = __webpack_require__(7); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__ = __webpack_require__(189); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__ = __webpack_require__(422); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__ = __webpack_require__(321); +/** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */ + + + + + + + +var SubjectSubscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SubjectSubscriber, _super); + function SubjectSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + return _this; + } + return SubjectSubscriber; +}(__WEBPACK_IMPORTED_MODULE_2__Subscriber__["a" /* Subscriber */])); + +var Subject = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subject, _super); + function Subject() { + var _this = _super.call(this) || this; + _this.observers = []; + _this.closed = false; + _this.isStopped = false; + _this.hasError = false; + _this.thrownError = null; + return _this; + } + Subject.prototype[__WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { + return new SubjectSubscriber(this); + }; + Subject.prototype.lift = function (operator) { + var subject = new AnonymousSubject(this, this); + subject.operator = operator; + return subject; + }; + Subject.prototype.next = function (value) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + if (!this.isStopped) { + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].next(value); + } + } + }; + Subject.prototype.error = function (err) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + this.hasError = true; + this.thrownError = err; + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].error(err); + } + this.observers.length = 0; + }; + Subject.prototype.complete = function () { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].complete(); + } + this.observers.length = 0; + }; + Subject.prototype.unsubscribe = function () { + this.isStopped = true; + this.closed = true; + this.observers = null; + }; + Subject.prototype._trySubscribe = function (subscriber) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + else { + return _super.prototype._trySubscribe.call(this, subscriber); + } + }; + Subject.prototype._subscribe = function (subscriber) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + else if (this.hasError) { + subscriber.error(this.thrownError); + return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; + } + else if (this.isStopped) { + subscriber.complete(); + return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; + } + else { + this.observers.push(subscriber); + return new __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__["a" /* SubjectSubscription */](this, subscriber); + } + }; + Subject.prototype.asObservable = function () { + var observable = new __WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */](); + observable.source = this; + return observable; + }; + Subject.create = function (destination, source) { + return new AnonymousSubject(destination, source); + }; + return Subject; +}(__WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */])); + +var AnonymousSubject = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](AnonymousSubject, _super); + function AnonymousSubject(destination, source) { + var _this = _super.call(this) || this; + _this.destination = destination; + _this.source = source; + return _this; + } + AnonymousSubject.prototype.next = function (value) { + var destination = this.destination; + if (destination && destination.next) { + destination.next(value); + } + }; + AnonymousSubject.prototype.error = function (err) { + var destination = this.destination; + if (destination && destination.error) { + this.destination.error(err); + } + }; + AnonymousSubject.prototype.complete = function () { + var destination = this.destination; + if (destination && destination.complete) { + this.destination.complete(); + } + }; + AnonymousSubject.prototype._subscribe = function (subscriber) { + var source = this.source; + if (source) { + return this.source.subscribe(subscriber); + } + else { + return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; + } + }; + return AnonymousSubject; +}(Subject)); + +//# sourceMappingURL=Subject.js.map + + +/***/ }), +/* 37 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.normalizePattern = normalizePattern; + +/** + * Explode and normalize a pattern into its name and range. + */ + +function normalizePattern(pattern) { + let hasVersion = false; + let range = 'latest'; + let name = pattern; + + // if we're a scope then remove the @ and add it back later + let isScoped = false; + if (name[0] === '@') { + isScoped = true; + name = name.slice(1); + } + + // take first part as the name + const parts = name.split('@'); + if (parts.length > 1) { + name = parts.shift(); + range = parts.join('@'); + + if (range) { + hasVersion = true; + } else { + range = '*'; + } + } + + // add back @ scope suffix + if (isScoped) { + name = `@${name}`; + } + + return { name, range, hasVersion }; +} + +/***/ }), +/* 38 */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(module) {var __WEBPACK_AMD_DEFINE_RESULT__;/** + * @license + * Lodash + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ +;(function() { + + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the semantic version number. */ + var VERSION = '4.17.10'; + + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + + /** Error message constants. */ + var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', + FUNC_ERROR_TEXT = 'Expected a function'; + + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED = '__lodash_hash_undefined__'; + + /** Used as the maximum memoize cache size. */ + var MAX_MEMOIZE_SIZE = 500; + + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; + + /** Used to compose bitmasks for cloning. */ + var CLONE_DEEP_FLAG = 1, + CLONE_FLAT_FLAG = 2, + CLONE_SYMBOLS_FLAG = 4; + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + + /** Used to compose bitmasks for function metadata. */ + var WRAP_BIND_FLAG = 1, + WRAP_BIND_KEY_FLAG = 2, + WRAP_CURRY_BOUND_FLAG = 4, + WRAP_CURRY_FLAG = 8, + WRAP_CURRY_RIGHT_FLAG = 16, + WRAP_PARTIAL_FLAG = 32, + WRAP_PARTIAL_RIGHT_FLAG = 64, + WRAP_ARY_FLAG = 128, + WRAP_REARG_FLAG = 256, + WRAP_FLIP_FLAG = 512; + + /** Used as default options for `_.truncate`. */ + var DEFAULT_TRUNC_LENGTH = 30, + DEFAULT_TRUNC_OMISSION = '...'; + + /** Used to detect hot functions by number of calls within a span of milliseconds. */ + var HOT_COUNT = 800, + HOT_SPAN = 16; + + /** Used to indicate the type of lazy iteratees. */ + var LAZY_FILTER_FLAG = 1, + LAZY_MAP_FLAG = 2, + LAZY_WHILE_FLAG = 3; + + /** Used as references for various `Number` constants. */ + var INFINITY = 1 / 0, + MAX_SAFE_INTEGER = 9007199254740991, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; + + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = 4294967295, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; + + /** Used to associate wrap methods with their bit flags. */ + var wrapFlags = [ + ['ary', WRAP_ARY_FLAG], + ['bind', WRAP_BIND_FLAG], + ['bindKey', WRAP_BIND_KEY_FLAG], + ['curry', WRAP_CURRY_FLAG], + ['curryRight', WRAP_CURRY_RIGHT_FLAG], + ['flip', WRAP_FLIP_FLAG], + ['partial', WRAP_PARTIAL_FLAG], + ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], + ['rearg', WRAP_REARG_FLAG] + ]; + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + asyncTag = '[object AsyncFunction]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + domExcTag = '[object DOMException]', + errorTag = '[object Error]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + mapTag = '[object Map]', + numberTag = '[object Number]', + nullTag = '[object Null]', + objectTag = '[object Object]', + promiseTag = '[object Promise]', + proxyTag = '[object Proxy]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]', + undefinedTag = '[object Undefined]', + weakMapTag = '[object WeakMap]', + weakSetTag = '[object WeakSet]'; + + var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + + /** Used to match empty string literals in compiled template source. */ + var reEmptyStringLeading = /\b__p \+= '';/g, + reEmptyStringMiddle = /\b(__p \+=) '' \+/g, + reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + + /** Used to match HTML entities and HTML characters. */ + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, + reUnescapedHtml = /[&<>"']/g, + reHasEscapedHtml = RegExp(reEscapedHtml.source), + reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** Used to match template delimiters. */ + var reEscape = /<%-([\s\S]+?)%>/g, + reEvaluate = /<%([\s\S]+?)%>/g, + reInterpolate = /<%=([\s\S]+?)%>/g; + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + + /** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ + var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, + reHasRegExpChar = RegExp(reRegExpChar.source); + + /** Used to match leading and trailing whitespace. */ + var reTrim = /^\s+|\s+$/g, + reTrimStart = /^\s+/, + reTrimEnd = /\s+$/; + + /** Used to match wrap detail comments. */ + var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, + reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, + reSplitDetails = /,? & /; + + /** Used to match words composed of alphanumeric characters. */ + var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; + + /** + * Used to match + * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). + */ + var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + + /** Used to match `RegExp` flags from their coerced string values. */ + var reFlags = /\w*$/; + + /** Used to detect bad signed hexadecimal string values. */ + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + + /** Used to detect binary string values. */ + var reIsBinary = /^0b[01]+$/i; + + /** Used to detect host constructors (Safari). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; + + /** Used to detect octal string values. */ + var reIsOctal = /^0o[0-7]+$/i; + + /** Used to detect unsigned integer values. */ + var reIsUint = /^(?:0|[1-9]\d*)$/; + + /** Used to match Latin Unicode letters (excluding mathematical operators). */ + var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; + + /** Used to ensure capturing order of template delimiters. */ + var reNoMatch = /($^)/; + + /** Used to match unescaped characters in compiled string literals. */ + var reUnescapedString = /['\n\r\u2028\u2029\\]/g; + + /** Used to compose unicode character classes. */ + var rsAstralRange = '\\ud800-\\udfff', + rsComboMarksRange = '\\u0300-\\u036f', + reComboHalfMarksRange = '\\ufe20-\\ufe2f', + rsComboSymbolsRange = '\\u20d0-\\u20ff', + rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, + rsDingbatRange = '\\u2700-\\u27bf', + rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', + rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', + rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', + rsPunctuationRange = '\\u2000-\\u206f', + rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', + rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', + rsVarRange = '\\ufe0e\\ufe0f', + rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; + + /** Used to compose unicode capture groups. */ + var rsApos = "['\u2019]", + rsAstral = '[' + rsAstralRange + ']', + rsBreak = '[' + rsBreakRange + ']', + rsCombo = '[' + rsComboRange + ']', + rsDigits = '\\d+', + rsDingbat = '[' + rsDingbatRange + ']', + rsLower = '[' + rsLowerRange + ']', + rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', + rsFitz = '\\ud83c[\\udffb-\\udfff]', + rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', + rsNonAstral = '[^' + rsAstralRange + ']', + rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', + rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', + rsUpper = '[' + rsUpperRange + ']', + rsZWJ = '\\u200d'; + + /** Used to compose unicode regexes. */ + var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', + rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', + rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', + rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', + reOptMod = rsModifier + '?', + rsOptVar = '[' + rsVarRange + ']?', + rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', + rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])', + rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])', + rsSeq = rsOptVar + reOptMod + rsOptJoin, + rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, + rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; + + /** Used to match apostrophes. */ + var reApos = RegExp(rsApos, 'g'); + + /** + * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and + * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). + */ + var reComboMark = RegExp(rsCombo, 'g'); + + /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ + var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); + + /** Used to match complex or compound words. */ + var reUnicodeWord = RegExp([ + rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', + rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', + rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, + rsUpper + '+' + rsOptContrUpper, + rsOrdUpper, + rsOrdLower, + rsDigits, + rsEmoji + ].join('|'), 'g'); + + /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ + var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); + + /** Used to detect strings that need a more robust regexp to match words. */ + var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; + + /** Used to assign default `context` object properties. */ + var contextProps = [ + 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', + 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', + 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', + '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' + ]; + + /** Used to make template sourceURLs easier to identify. */ + var templateCounter = -1; + + /** Used to identify `toStringTag` values of typed arrays. */ + var typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = + typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = + typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = + typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = + typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag] = typedArrayTags[arrayTag] = + typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = + typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = + typedArrayTags[errorTag] = typedArrayTags[funcTag] = + typedArrayTags[mapTag] = typedArrayTags[numberTag] = + typedArrayTags[objectTag] = typedArrayTags[regexpTag] = + typedArrayTags[setTag] = typedArrayTags[stringTag] = + typedArrayTags[weakMapTag] = false; + + /** Used to identify `toStringTag` values supported by `_.clone`. */ + var cloneableTags = {}; + cloneableTags[argsTag] = cloneableTags[arrayTag] = + cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = + cloneableTags[boolTag] = cloneableTags[dateTag] = + cloneableTags[float32Tag] = cloneableTags[float64Tag] = + cloneableTags[int8Tag] = cloneableTags[int16Tag] = + cloneableTags[int32Tag] = cloneableTags[mapTag] = + cloneableTags[numberTag] = cloneableTags[objectTag] = + cloneableTags[regexpTag] = cloneableTags[setTag] = + cloneableTags[stringTag] = cloneableTags[symbolTag] = + cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = + cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; + cloneableTags[errorTag] = cloneableTags[funcTag] = + cloneableTags[weakMapTag] = false; + + /** Used to map Latin Unicode letters to basic Latin letters. */ + var deburredLetters = { + // Latin-1 Supplement block. + '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', + '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', + '\xc7': 'C', '\xe7': 'c', + '\xd0': 'D', '\xf0': 'd', + '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', + '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', + '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', + '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', + '\xd1': 'N', '\xf1': 'n', + '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', + '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', + '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', + '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', + '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', + '\xc6': 'Ae', '\xe6': 'ae', + '\xde': 'Th', '\xfe': 'th', + '\xdf': 'ss', + // Latin Extended-A block. + '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', + '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', + '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', + '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', + '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', + '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', + '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', + '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', + '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', + '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', + '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', + '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', + '\u0134': 'J', '\u0135': 'j', + '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', + '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', + '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', + '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', + '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', + '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', + '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', + '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', + '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', + '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', + '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', + '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', + '\u0163': 't', '\u0165': 't', '\u0167': 't', + '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', + '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', + '\u0174': 'W', '\u0175': 'w', + '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', + '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', + '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', + '\u0132': 'IJ', '\u0133': 'ij', + '\u0152': 'Oe', '\u0153': 'oe', + '\u0149': "'n", '\u017f': 's' + }; + + /** Used to map characters to HTML entities. */ + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + /** Used to map HTML entities to characters. */ + var htmlUnescapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'" + }; + + /** Used to escape characters for inclusion in compiled string literals. */ + var stringEscapes = { + '\\': '\\', + "'": "'", + '\n': 'n', + '\r': 'r', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + /** Built-in method references without a dependency on `root`. */ + var freeParseFloat = parseFloat, + freeParseInt = parseInt; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + + /** Detect free variable `exports`. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports; + + /** Detect free variable `process` from Node.js. */ + var freeProcess = moduleExports && freeGlobal.process; + + /** Used to access faster Node.js helpers. */ + var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule && freeModule.require && freeModule.require('util').types; + + if (types) { + return types; + } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} + }()); + + /* Node.js helper references. */ + var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, + nodeIsDate = nodeUtil && nodeUtil.isDate, + nodeIsMap = nodeUtil && nodeUtil.isMap, + nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, + nodeIsSet = nodeUtil && nodeUtil.isSet, + nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + + /*--------------------------------------------------------------------------*/ + + /** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ + function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); + } + + /** + * A specialized version of `baseAggregator` for arrays. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function arrayAggregator(array, setter, iteratee, accumulator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + var value = array[index]; + setter(accumulator, value, iteratee(value), array); + } + return accumulator; + } + + /** + * A specialized version of `_.forEach` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.forEachRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEachRight(array, iteratee) { + var length = array == null ? 0 : array.length; + + while (length--) { + if (iteratee(array[length], length, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.every` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + + /** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * A specialized version of `_.includes` for arrays without support for + * specifying an index to search from. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludes(array, value) { + var length = array == null ? 0 : array.length; + return !!length && baseIndexOf(array, value, 0) > -1; + } + + /** + * This function is like `arrayIncludes` except that it accepts a comparator. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @param {Function} comparator The comparator invoked per element. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludesWith(array, value, comparator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (comparator(value, array[index])) { + return true; + } + } + return false; + } + + /** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ + function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; + } + + /** + * A specialized version of `_.reduce` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the first element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initAccum) { + var index = -1, + length = array == null ? 0 : array.length; + + if (initAccum && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; + } + + /** + * A specialized version of `_.reduceRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the last element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduceRight(array, iteratee, accumulator, initAccum) { + var length = array == null ? 0 : array.length; + if (initAccum && length) { + accumulator = array[--length]; + } + while (length--) { + accumulator = iteratee(accumulator, array[length], length, array); + } + return accumulator; + } + + /** + * A specialized version of `_.some` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * Gets the size of an ASCII `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + var asciiSize = baseProperty('length'); + + /** + * Converts an ASCII `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function asciiToArray(string) { + return string.split(''); + } + + /** + * Splits an ASCII `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function asciiWords(string) { + return string.match(reAsciiWord) || []; + } + + /** + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFindKey(collection, predicate, eachFunc) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = key; + return false; + } + }); + return result; + } + + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); + } + + /** + * This function is like `baseIndexOf` except that it accepts a comparator. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @param {Function} comparator The comparator invoked per element. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOfWith(array, value, fromIndex, comparator) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (comparator(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ + function baseIsNaN(value) { + return value !== value; + } + + /** + * The base implementation of `_.mean` and `_.meanBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the mean. + */ + function baseMean(array, iteratee) { + var length = array == null ? 0 : array.length; + return length ? (baseSum(array, iteratee) / length) : NAN; + } + + /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.propertyOf` without support for deep paths. + * + * @private + * @param {Object} object The object to query. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyOf(object) { + return function(key) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.reduce` and `_.reduceRight`, without support + * for iteratee shorthands, which iterates over `collection` using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initAccum Specify using the first or last element of + * `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ + function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initAccum + ? (initAccum = false, value) + : iteratee(accumulator, value, index, collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.sortBy` which uses `comparer` to define the + * sort order of `array` and replaces criteria objects with their corresponding + * values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ + function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; + } + + /** + * The base implementation of `_.sum` and `_.sumBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the sum. + */ + function baseSum(array, iteratee) { + var result, + index = -1, + length = array.length; + + while (++index < length) { + var current = iteratee(array[index]); + if (current !== undefined) { + result = result === undefined ? current : (result + current); + } + } + return result; + } + + /** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ + function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; + } + + /** + * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array + * of key-value pairs for `object` corresponding to the property names of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the key-value pairs. + */ + function baseToPairs(object, props) { + return arrayMap(props, function(key) { + return [key, object[key]]; + }); + } + + /** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ + function baseUnary(func) { + return function(value) { + return func(value); + }; + } + + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + return arrayMap(props, function(key) { + return object[key]; + }); + } + + /** + * Checks if a `cache` value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function cacheHas(cache, key) { + return cache.has(key); + } + + /** + * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the first unmatched string symbol. + */ + function charsStartIndex(strSymbols, chrSymbols) { + var index = -1, + length = strSymbols.length; + + while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the last unmatched string symbol. + */ + function charsEndIndex(strSymbols, chrSymbols) { + var index = strSymbols.length; + + while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Gets the number of `placeholder` occurrences in `array`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} placeholder The placeholder to search for. + * @returns {number} Returns the placeholder count. + */ + function countHolders(array, placeholder) { + var length = array.length, + result = 0; + + while (length--) { + if (array[length] === placeholder) { + ++result; + } + } + return result; + } + + /** + * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A + * letters to basic Latin letters. + * + * @private + * @param {string} letter The matched letter to deburr. + * @returns {string} Returns the deburred letter. + */ + var deburrLetter = basePropertyOf(deburredLetters); + + /** + * Used by `_.escape` to convert characters to HTML entities. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + var escapeHtmlChar = basePropertyOf(htmlEscapes); + + /** + * Used by `_.template` to escape characters for inclusion in compiled string literals. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeStringChar(chr) { + return '\\' + stringEscapes[chr]; + } + + /** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function getValue(object, key) { + return object == null ? undefined : object[key]; + } + + /** + * Checks if `string` contains Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a symbol is found, else `false`. + */ + function hasUnicode(string) { + return reHasUnicode.test(string); + } + + /** + * Checks if `string` contains a word composed of Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a word is found, else `false`. + */ + function hasUnicodeWord(string) { + return reHasUnicodeWord.test(string); + } + + /** + * Converts `iterator` to an array. + * + * @private + * @param {Object} iterator The iterator to convert. + * @returns {Array} Returns the converted array. + */ + function iteratorToArray(iterator) { + var data, + result = []; + + while (!(data = iterator.next()).done) { + result.push(data.value); + } + return result; + } + + /** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ + function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; + } + + /** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ + function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; + } + + /** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ + function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value === placeholder || value === PLACEHOLDER) { + array[index] = PLACEHOLDER; + result[resIndex++] = index; + } + } + return result; + } + + /** + * Gets the value at `key`, unless `key` is "__proto__". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function safeGet(object, key) { + return key == '__proto__' + ? undefined + : object[key]; + } + + /** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ + function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = value; + }); + return result; + } + + /** + * Converts `set` to its value-value pairs. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the value-value pairs. + */ + function setToPairs(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = [value, value]; + }); + return result; + } + + /** + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * A specialized version of `_.lastIndexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictLastIndexOf(array, value, fromIndex) { + var index = fromIndex + 1; + while (index--) { + if (array[index] === value) { + return index; + } + } + return index; + } + + /** + * Gets the number of symbols in `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the string size. + */ + function stringSize(string) { + return hasUnicode(string) + ? unicodeSize(string) + : asciiSize(string); + } + + /** + * Converts `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function stringToArray(string) { + return hasUnicode(string) + ? unicodeToArray(string) + : asciiToArray(string); + } + + /** + * Used by `_.unescape` to convert HTML entities to characters. + * + * @private + * @param {string} chr The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ + var unescapeHtmlChar = basePropertyOf(htmlUnescapes); + + /** + * Gets the size of a Unicode `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + function unicodeSize(string) { + var result = reUnicode.lastIndex = 0; + while (reUnicode.test(string)) { + ++result; + } + return result; + } + + /** + * Converts a Unicode `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function unicodeToArray(string) { + return string.match(reUnicode) || []; + } + + /** + * Splits a Unicode `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function unicodeWords(string) { + return string.match(reUnicodeWord) || []; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Create a new pristine `lodash` function using the `context` object. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Util + * @param {Object} [context=root] The context object. + * @returns {Function} Returns a new `lodash` function. + * @example + * + * _.mixin({ 'foo': _.constant('foo') }); + * + * var lodash = _.runInContext(); + * lodash.mixin({ 'bar': lodash.constant('bar') }); + * + * _.isFunction(_.foo); + * // => true + * _.isFunction(_.bar); + * // => false + * + * lodash.isFunction(lodash.foo); + * // => false + * lodash.isFunction(lodash.bar); + * // => true + * + * // Create a suped-up `defer` in Node.js. + * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; + */ + var runInContext = (function runInContext(context) { + context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps)); + + /** Built-in constructor references. */ + var Array = context.Array, + Date = context.Date, + Error = context.Error, + Function = context.Function, + Math = context.Math, + Object = context.Object, + RegExp = context.RegExp, + String = context.String, + TypeError = context.TypeError; + + /** Used for built-in method references. */ + var arrayProto = Array.prototype, + funcProto = Function.prototype, + objectProto = Object.prototype; + + /** Used to detect overreaching core-js shims. */ + var coreJsData = context['__core-js_shared__']; + + /** Used to resolve the decompiled source of functions. */ + var funcToString = funcProto.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** Used to generate unique IDs. */ + var idCounter = 0; + + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** Used to infer the `Object` constructor. */ + var objectCtorString = funcToString.call(Object); + + /** Used to restore the original `_` reference in `_.noConflict`. */ + var oldDash = root._; + + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + /** Built-in value references. */ + var Buffer = moduleExports ? context.Buffer : undefined, + Symbol = context.Symbol, + Uint8Array = context.Uint8Array, + allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, + getPrototype = overArg(Object.getPrototypeOf, Object), + objectCreate = Object.create, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + splice = arrayProto.splice, + spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, + symIterator = Symbol ? Symbol.iterator : undefined, + symToStringTag = Symbol ? Symbol.toStringTag : undefined; + + var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} + }()); + + /** Mocked built-ins. */ + var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, + ctxNow = Date && Date.now !== root.Date.now && Date.now, + ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeCeil = Math.ceil, + nativeFloor = Math.floor, + nativeGetSymbols = Object.getOwnPropertySymbols, + nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, + nativeIsFinite = context.isFinite, + nativeJoin = arrayProto.join, + nativeKeys = overArg(Object.keys, Object), + nativeMax = Math.max, + nativeMin = Math.min, + nativeNow = Date.now, + nativeParseInt = context.parseInt, + nativeRandom = Math.random, + nativeReverse = arrayProto.reverse; + + /* Built-in method references that are verified to be native. */ + var DataView = getNative(context, 'DataView'), + Map = getNative(context, 'Map'), + Promise = getNative(context, 'Promise'), + Set = getNative(context, 'Set'), + WeakMap = getNative(context, 'WeakMap'), + nativeCreate = getNative(Object, 'create'); + + /** Used to store function metadata. */ + var metaMap = WeakMap && new WeakMap; + + /** Used to lookup unminified function names. */ + var realNames = {}; + + /** Used to detect maps, sets, and weakmaps. */ + var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map), + promiseCtorString = toSource(Promise), + setCtorString = toSource(Set), + weakMapCtorString = toSource(WeakMap); + + /** Used to convert symbols to primitives and strings. */ + var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps `value` to enable implicit method + * chain sequences. Methods that operate on and return arrays, collections, + * and functions can be chained together. Methods that retrieve a single value + * or may return a primitive value will automatically end the chain sequence + * and return the unwrapped value. Otherwise, the value must be unwrapped + * with `_#value`. + * + * Explicit chain sequences, which must be unwrapped with `_#value`, may be + * enabled using `_.chain`. + * + * The execution of chained methods is lazy, that is, it's deferred until + * `_#value` is implicitly or explicitly called. + * + * Lazy evaluation allows several methods to support shortcut fusion. + * Shortcut fusion is an optimization to merge iteratee calls; this avoids + * the creation of intermediate arrays and can greatly reduce the number of + * iteratee executions. Sections of a chain sequence qualify for shortcut + * fusion if the section is applied to an array and iteratees accept only + * one argument. The heuristic for whether a section qualifies for shortcut + * fusion is subject to change. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers have `Array` and `String` methods. + * + * The wrapper `Array` methods are: + * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` + * + * The wrapper `String` methods are: + * `replace` and `split` + * + * The wrapper methods that support shortcut fusion are: + * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, + * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, + * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` + * + * The chainable wrapper methods are: + * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, + * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, + * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, + * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, + * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, + * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, + * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, + * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, + * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, + * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, + * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, + * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, + * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, + * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, + * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, + * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, + * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, + * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, + * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, + * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, + * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, + * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, + * `zipObject`, `zipObjectDeep`, and `zipWith` + * + * The wrapper methods that are **not** chainable by default are: + * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, + * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, + * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, + * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, + * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, + * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, + * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, + * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, + * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, + * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, + * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, + * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, + * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, + * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, + * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, + * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, + * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, + * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, + * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, + * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, + * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, + * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, + * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, + * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, + * `upperFirst`, `value`, and `words` + * + * @name _ + * @constructor + * @category Seq + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2, 3]); + * + * // Returns an unwrapped value. + * wrapped.reduce(_.add); + * // => 6 + * + * // Returns a wrapped value. + * var squares = wrapped.map(square); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash(value) { + if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { + if (value instanceof LodashWrapper) { + return value; + } + if (hasOwnProperty.call(value, '__wrapped__')) { + return wrapperClone(value); + } + } + return new LodashWrapper(value); + } + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; + }()); + + /** + * The function whose prototype chain sequence wrappers inherit from. + * + * @private + */ + function baseLodash() { + // No operation performed. + } + + /** + * The base constructor for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap. + * @param {boolean} [chainAll] Enable explicit method chain sequences. + */ + function LodashWrapper(value, chainAll) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__chain__ = !!chainAll; + this.__index__ = 0; + this.__values__ = undefined; + } + + /** + * By default, the template delimiters used by lodash are like those in + * embedded Ruby (ERB) as well as ES2015 template strings. Change the + * following template settings to use alternative delimiters. + * + * @static + * @memberOf _ + * @type {Object} + */ + lodash.templateSettings = { + + /** + * Used to detect `data` property values to be HTML-escaped. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'escape': reEscape, + + /** + * Used to detect code to be evaluated. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'evaluate': reEvaluate, + + /** + * Used to detect `data` property values to inject. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'interpolate': reInterpolate, + + /** + * Used to reference the data object in the template text. + * + * @memberOf _.templateSettings + * @type {string} + */ + 'variable': '', + + /** + * Used to import variables into the compiled template. + * + * @memberOf _.templateSettings + * @type {Object} + */ + 'imports': { + + /** + * A reference to the `lodash` function. + * + * @memberOf _.templateSettings.imports + * @type {Function} + */ + '_': lodash + } + }; + + // Ensure wrappers are instances of `baseLodash`. + lodash.prototype = baseLodash.prototype; + lodash.prototype.constructor = lodash; + + LodashWrapper.prototype = baseCreate(baseLodash.prototype); + LodashWrapper.prototype.constructor = LodashWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @constructor + * @param {*} value The value to wrap. + */ + function LazyWrapper(value) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__dir__ = 1; + this.__filtered__ = false; + this.__iteratees__ = []; + this.__takeCount__ = MAX_ARRAY_LENGTH; + this.__views__ = []; + } + + /** + * Creates a clone of the lazy wrapper object. + * + * @private + * @name clone + * @memberOf LazyWrapper + * @returns {Object} Returns the cloned `LazyWrapper` object. + */ + function lazyClone() { + var result = new LazyWrapper(this.__wrapped__); + result.__actions__ = copyArray(this.__actions__); + result.__dir__ = this.__dir__; + result.__filtered__ = this.__filtered__; + result.__iteratees__ = copyArray(this.__iteratees__); + result.__takeCount__ = this.__takeCount__; + result.__views__ = copyArray(this.__views__); + return result; + } + + /** + * Reverses the direction of lazy iteration. + * + * @private + * @name reverse + * @memberOf LazyWrapper + * @returns {Object} Returns the new reversed `LazyWrapper` object. + */ + function lazyReverse() { + if (this.__filtered__) { + var result = new LazyWrapper(this); + result.__dir__ = -1; + result.__filtered__ = true; + } else { + result = this.clone(); + result.__dir__ *= -1; + } + return result; + } + + /** + * Extracts the unwrapped value from its lazy wrapper. + * + * @private + * @name value + * @memberOf LazyWrapper + * @returns {*} Returns the unwrapped value. + */ + function lazyValue() { + var array = this.__wrapped__.value(), + dir = this.__dir__, + isArr = isArray(array), + isRight = dir < 0, + arrLength = isArr ? array.length : 0, + view = getView(0, arrLength, this.__views__), + start = view.start, + end = view.end, + length = end - start, + index = isRight ? end : (start - 1), + iteratees = this.__iteratees__, + iterLength = iteratees.length, + resIndex = 0, + takeCount = nativeMin(length, this.__takeCount__); + + if (!isArr || (!isRight && arrLength == length && takeCount == length)) { + return baseWrapperValue(array, this.__actions__); + } + var result = []; + + outer: + while (length-- && resIndex < takeCount) { + index += dir; + + var iterIndex = -1, + value = array[index]; + + while (++iterIndex < iterLength) { + var data = iteratees[iterIndex], + iteratee = data.iteratee, + type = data.type, + computed = iteratee(value); + + if (type == LAZY_MAP_FLAG) { + value = computed; + } else if (!computed) { + if (type == LAZY_FILTER_FLAG) { + continue outer; + } else { + break outer; + } + } + } + result[resIndex++] = value; + } + return result; + } + + // Ensure `LazyWrapper` is an instance of `baseLodash`. + LazyWrapper.prototype = baseCreate(baseLodash.prototype); + LazyWrapper.prototype.constructor = LazyWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ + function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; + } + + /** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; + } + + /** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); + } + + /** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ + function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; + } + + // Add methods to `Hash`. + Hash.prototype.clear = hashClear; + Hash.prototype['delete'] = hashDelete; + Hash.prototype.get = hashGet; + Hash.prototype.has = hashHas; + Hash.prototype.set = hashSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + this.size = 0; + } + + /** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; + } + + /** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; + } + + /** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; + } + + /** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ + function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; + } + + // Add methods to `ListCache`. + ListCache.prototype.clear = listCacheClear; + ListCache.prototype['delete'] = listCacheDelete; + ListCache.prototype.get = listCacheGet; + ListCache.prototype.has = listCacheHas; + ListCache.prototype.set = listCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ + function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; + } + + /** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function mapCacheGet(key) { + return getMapData(this, key).get(key); + } + + /** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapCacheHas(key) { + return getMapData(this, key).has(key); + } + + /** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ + function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; + } + + // Add methods to `MapCache`. + MapCache.prototype.clear = mapCacheClear; + MapCache.prototype['delete'] = mapCacheDelete; + MapCache.prototype.get = mapCacheGet; + MapCache.prototype.has = mapCacheHas; + MapCache.prototype.set = mapCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * + * Creates an array cache object to store unique values. + * + * @private + * @constructor + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } + } + + /** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ + function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; + } + + /** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ + function setCacheHas(value) { + return this.__data__.has(value); + } + + // Add methods to `SetCache`. + SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; + SetCache.prototype.has = setCacheHas; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; + } + + /** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ + function stackClear() { + this.__data__ = new ListCache; + this.size = 0; + } + + /** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; + } + + /** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function stackGet(key) { + return this.__data__.get(key); + } + + /** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function stackHas(key) { + return this.__data__.has(key); + } + + /** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ + function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; + } + + // Add methods to `Stack`. + Stack.prototype.clear = stackClear; + Stack.prototype['delete'] = stackDelete; + Stack.prototype.get = stackGet; + Stack.prototype.has = stackHas; + Stack.prototype.set = stackSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ + function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; + } + + /** + * A specialized version of `_.sample` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @returns {*} Returns the random element. + */ + function arraySample(array) { + var length = array.length; + return length ? array[baseRandom(0, length - 1)] : undefined; + } + + /** + * A specialized version of `_.sampleSize` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function arraySampleSize(array, n) { + return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); + } + + /** + * A specialized version of `_.shuffle` for arrays. + * + * @private + * @param {Array} array The array to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function arrayShuffle(array) { + return shuffleSelf(copyArray(array)); + } + + /** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; + } + + /** + * Aggregates elements of `collection` on `accumulator` with keys transformed + * by `iteratee` and values set by `setter`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function baseAggregator(collection, setter, iteratee, accumulator) { + baseEach(collection, function(value, key, collection) { + setter(accumulator, value, iteratee(value), collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.assign` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssign(object, source) { + return object && copyObject(source, keys(source), object); + } + + /** + * The base implementation of `_.assignIn` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssignIn(object, source) { + return object && copyObject(source, keysIn(source), object); + } + + /** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } + } + + /** + * The base implementation of `_.at` without support for individual paths. + * + * @private + * @param {Object} object The object to iterate over. + * @param {string[]} paths The property paths to pick. + * @returns {Array} Returns the picked elements. + */ + function baseAt(object, paths) { + var index = -1, + length = paths.length, + result = Array(length), + skip = object == null; + + while (++index < length) { + result[index] = skip ? undefined : get(object, paths[index]); + } + return result; + } + + /** + * The base implementation of `_.clamp` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + */ + function baseClamp(number, lower, upper) { + if (number === number) { + if (upper !== undefined) { + number = number <= upper ? number : upper; + } + if (lower !== undefined) { + number = number >= lower ? number : lower; + } + } + return number; + } + + /** + * The base implementation of `_.clone` and `_.cloneDeep` which tracks + * traversed objects. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} bitmask The bitmask flags. + * 1 - Deep clone + * 2 - Flatten inherited properties + * 4 - Clone symbols + * @param {Function} [customizer] The function to customize cloning. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The parent object of `value`. + * @param {Object} [stack] Tracks traversed objects and their clone counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, bitmask, customizer, key, object, stack) { + var result, + isDeep = bitmask & CLONE_DEEP_FLAG, + isFlat = bitmask & CLONE_FLAT_FLAG, + isFull = bitmask & CLONE_SYMBOLS_FLAG; + + if (customizer) { + result = object ? customizer(value, key, object, stack) : customizer(value); + } + if (result !== undefined) { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return copyArray(value, result); + } + } else { + var tag = getTag(value), + isFunc = tag == funcTag || tag == genTag; + + if (isBuffer(value)) { + return cloneBuffer(value, isDeep); + } + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = (isFlat || isFunc) ? {} : initCloneObject(value); + if (!isDeep) { + return isFlat + ? copySymbolsIn(value, baseAssignIn(result, value)) + : copySymbols(value, baseAssign(result, value)); + } + } else { + if (!cloneableTags[tag]) { + return object ? value : {}; + } + result = initCloneByTag(value, tag, isDeep); + } + } + // Check for circular references and return its corresponding clone. + stack || (stack = new Stack); + var stacked = stack.get(value); + if (stacked) { + return stacked; + } + stack.set(value, result); + + if (isSet(value)) { + value.forEach(function(subValue) { + result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); + }); + + return result; + } + + if (isMap(value)) { + value.forEach(function(subValue, key) { + result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + + return result; + } + + var keysFunc = isFull + ? (isFlat ? getAllKeysIn : getAllKeys) + : (isFlat ? keysIn : keys); + + var props = isArr ? undefined : keysFunc(value); + arrayEach(props || value, function(subValue, key) { + if (props) { + key = subValue; + subValue = value[key]; + } + // Recursively populate clone (susceptible to call stack limits). + assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + return result; + } + + /** + * The base implementation of `_.conforms` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property predicates to conform to. + * @returns {Function} Returns the new spec function. + */ + function baseConforms(source) { + var props = keys(source); + return function(object) { + return baseConformsTo(object, source, props); + }; + } + + /** + * The base implementation of `_.conformsTo` which accepts `props` to check. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + */ + function baseConformsTo(object, source, props) { + var length = props.length; + if (object == null) { + return !length; + } + object = Object(object); + while (length--) { + var key = props[length], + predicate = source[key], + value = object[key]; + + if ((value === undefined && !(key in object)) || !predicate(value)) { + return false; + } + } + return true; + } + + /** + * The base implementation of `_.delay` and `_.defer` which accepts `args` + * to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Array} args The arguments to provide to `func`. + * @returns {number|Object} Returns the timer id or timeout object. + */ + function baseDelay(func, wait, args) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function() { func.apply(undefined, args); }, wait); + } + + /** + * The base implementation of methods like `_.difference` without support + * for excluding multiple arrays or iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + */ + function baseDifference(array, values, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + isCommon = true, + length = array.length, + result = [], + valuesLength = values.length; + + if (!length) { + return result; + } + if (iteratee) { + values = arrayMap(values, baseUnary(iteratee)); + } + if (comparator) { + includes = arrayIncludesWith; + isCommon = false; + } + else if (values.length >= LARGE_ARRAY_SIZE) { + includes = cacheHas; + isCommon = false; + values = new SetCache(values); + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee == null ? value : iteratee(value); + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === computed) { + continue outer; + } + } + result.push(value); + } + else if (!includes(values, computed, comparator)) { + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.forEach` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEach = createBaseEach(baseForOwn); + + /** + * The base implementation of `_.forEachRight` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEachRight = createBaseEach(baseForOwnRight, true); + + /** + * The base implementation of `_.every` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ + function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function(value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; + } + + /** + * The base implementation of methods like `_.max` and `_.min` which accepts a + * `comparator` to determine the extremum value. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The iteratee invoked per iteration. + * @param {Function} comparator The comparator used to compare values. + * @returns {*} Returns the extremum value. + */ + function baseExtremum(array, iteratee, comparator) { + var index = -1, + length = array.length; + + while (++index < length) { + var value = array[index], + current = iteratee(value); + + if (current != null && (computed === undefined + ? (current === current && !isSymbol(current)) + : comparator(current, computed) + )) { + var computed = current, + result = value; + } + } + return result; + } + + /** + * The base implementation of `_.fill` without an iteratee call guard. + * + * @private + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + */ + function baseFill(array, value, start, end) { + var length = array.length; + + start = toInteger(start); + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = (end === undefined || end > length) ? length : toInteger(end); + if (end < 0) { + end += length; + } + end = start > end ? 0 : toLength(end); + while (start < end) { + array[start++] = value; + } + return array; + } + + /** + * The base implementation of `_.filter` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function baseFilter(collection, predicate) { + var result = []; + baseEach(collection, function(value, index, collection) { + if (predicate(value, index, collection)) { + result.push(value); + } + }); + return result; + } + + /** + * The base implementation of `_.flatten` with support for restricting flattening. + * + * @private + * @param {Array} array The array to flatten. + * @param {number} depth The maximum recursion depth. + * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. + * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. + * @param {Array} [result=[]] The initial result value. + * @returns {Array} Returns the new flattened array. + */ + function baseFlatten(array, depth, predicate, isStrict, result) { + var index = -1, + length = array.length; + + predicate || (predicate = isFlattenable); + result || (result = []); + + while (++index < length) { + var value = array[index]; + if (depth > 0 && predicate(value)) { + if (depth > 1) { + // Recursively flatten arrays (susceptible to call stack limits). + baseFlatten(value, depth - 1, predicate, isStrict, result); + } else { + arrayPush(result, value); + } + } else if (!isStrict) { + result[result.length] = value; + } + } + return result; + } + + /** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * This function is like `baseFor` except that it iterates over properties + * in the opposite order. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseForRight = createBaseFor(true); + + /** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); + } + + /** + * The base implementation of `_.forOwnRight` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwnRight(object, iteratee) { + return object && baseForRight(object, iteratee, keys); + } + + /** + * The base implementation of `_.functions` which creates an array of + * `object` function property names filtered from `props`. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} props The property names to filter. + * @returns {Array} Returns the function names. + */ + function baseFunctions(object, props) { + return arrayFilter(props, function(key) { + return isFunction(object[key]); + }); + } + + /** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; + } + + /** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ + function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); + } + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); + } + + /** + * The base implementation of `_.gt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + */ + function baseGt(value, other) { + return value > other; + } + + /** + * The base implementation of `_.has` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHas(object, key) { + return object != null && hasOwnProperty.call(object, key); + } + + /** + * The base implementation of `_.hasIn` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHasIn(object, key) { + return object != null && key in Object(object); + } + + /** + * The base implementation of `_.inRange` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to check. + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + */ + function baseInRange(number, start, end) { + return number >= nativeMin(start, end) && number < nativeMax(start, end); + } + + /** + * The base implementation of methods like `_.intersection`, without support + * for iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of shared values. + */ + function baseIntersection(arrays, iteratee, comparator) { + var includes = comparator ? arrayIncludesWith : arrayIncludes, + length = arrays[0].length, + othLength = arrays.length, + othIndex = othLength, + caches = Array(othLength), + maxLength = Infinity, + result = []; + + while (othIndex--) { + var array = arrays[othIndex]; + if (othIndex && iteratee) { + array = arrayMap(array, baseUnary(iteratee)); + } + maxLength = nativeMin(array.length, maxLength); + caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) + ? new SetCache(othIndex && array) + : undefined; + } + array = arrays[0]; + + var index = -1, + seen = caches[0]; + + outer: + while (++index < length && result.length < maxLength) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (!(seen + ? cacheHas(seen, computed) + : includes(result, computed, comparator) + )) { + othIndex = othLength; + while (--othIndex) { + var cache = caches[othIndex]; + if (!(cache + ? cacheHas(cache, computed) + : includes(arrays[othIndex], computed, comparator)) + ) { + continue outer; + } + } + if (seen) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.invert` and `_.invertBy` which inverts + * `object` with values transformed by `iteratee` and set by `setter`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform values. + * @param {Object} accumulator The initial inverted object. + * @returns {Function} Returns `accumulator`. + */ + function baseInverter(object, setter, iteratee, accumulator) { + baseForOwn(object, function(value, key, object) { + setter(accumulator, iteratee(value), key, object); + }); + return accumulator; + } + + /** + * The base implementation of `_.invoke` without support for individual + * method arguments. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {Array} args The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + */ + function baseInvoke(object, path, args) { + path = castPath(path, object); + object = parent(object, path); + var func = object == null ? object : object[toKey(last(path))]; + return func == null ? undefined : apply(func, object, args); + } + + /** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ + function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; + } + + /** + * The base implementation of `_.isArrayBuffer` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + */ + function baseIsArrayBuffer(value) { + return isObjectLike(value) && baseGetTag(value) == arrayBufferTag; + } + + /** + * The base implementation of `_.isDate` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + */ + function baseIsDate(value) { + return isObjectLike(value) && baseGetTag(value) == dateTag; + } + + /** + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {boolean} bitmask The bitmask flags. + * 1 - Unordered comparison + * 2 - Partial comparison + * @param {Function} [customizer] The function to customize comparisons. + * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, bitmask, customizer, stack) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); + } + + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = objIsArr ? arrayTag : getTag(object), + othTag = othIsArr ? arrayTag : getTag(other); + + objTag = objTag == argsTag ? objectTag : objTag; + othTag = othTag == argsTag ? objectTag : othTag; + + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && isBuffer(object)) { + if (!isBuffer(other)) { + return false; + } + objIsArr = true; + objIsObj = false; + } + if (isSameTag && !objIsObj) { + stack || (stack = new Stack); + return (objIsArr || isTypedArray(object)) + ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) + : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + } + if (!(bitmask & COMPARE_PARTIAL_FLAG)) { + var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + var objUnwrapped = objIsWrapped ? object.value() : object, + othUnwrapped = othIsWrapped ? other.value() : other; + + stack || (stack = new Stack); + return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); + } + } + if (!isSameTag) { + return false; + } + stack || (stack = new Stack); + return equalObjects(object, other, bitmask, customizer, equalFunc, stack); + } + + /** + * The base implementation of `_.isMap` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + */ + function baseIsMap(value) { + return isObjectLike(value) && getTag(value) == mapTag; + } + + /** + * The base implementation of `_.isMatch` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Array} matchData The property names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, source, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = Object(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var stack = new Stack; + if (customizer) { + var result = customizer(objValue, srcValue, key, object, source, stack); + } + if (!(result === undefined + ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) + : result + )) { + return false; + } + } + } + return true; + } + + /** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ + function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); + } + + /** + * The base implementation of `_.isRegExp` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + */ + function baseIsRegExp(value) { + return isObjectLike(value) && baseGetTag(value) == regexpTag; + } + + /** + * The base implementation of `_.isSet` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + */ + function baseIsSet(value) { + return isObjectLike(value) && getTag(value) == setTag; + } + + /** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ + function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; + } + + /** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [value=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ + function baseIteratee(value) { + // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. + // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. + if (typeof value == 'function') { + return value; + } + if (value == null) { + return identity; + } + if (typeof value == 'object') { + return isArray(value) + ? baseMatchesProperty(value[0], value[1]) + : baseMatches(value); + } + return property(value); + } + + /** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.lt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + */ + function baseLt(value, other) { + return value < other; + } + + /** + * The base implementation of `_.map` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function baseMap(collection, iteratee) { + var index = -1, + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value, key, collection) { + result[++index] = iteratee(value, key, collection); + }); + return result; + } + + /** + * The base implementation of `_.matches` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + return matchesStrictComparable(matchData[0][0], matchData[0][1]); + } + return function(object) { + return object === source || baseIsMatch(object, source, matchData); + }; + } + + /** + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatchesProperty(path, srcValue) { + if (isKey(path) && isStrictComparable(srcValue)) { + return matchesStrictComparable(toKey(path), srcValue); + } + return function(object) { + var objValue = get(object, path); + return (objValue === undefined && objValue === srcValue) + ? hasIn(object, path) + : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); + }; + } + + /** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + if (isObject(srcValue)) { + stack || (stack = new Stack); + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); + } + + /** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); + } + + /** + * The base implementation of `_.nth` which doesn't coerce arguments. + * + * @private + * @param {Array} array The array to query. + * @param {number} n The index of the element to return. + * @returns {*} Returns the nth element of `array`. + */ + function baseNth(array, n) { + var length = array.length; + if (!length) { + return; + } + n += n < 0 ? length : 0; + return isIndex(n, length) ? array[n] : undefined; + } + + /** + * The base implementation of `_.orderBy` without param guards. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {string[]} orders The sort orders of `iteratees`. + * @returns {Array} Returns the new sorted array. + */ + function baseOrderBy(collection, iteratees, orders) { + var index = -1; + iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); + + var result = baseMap(collection, function(value, key, collection) { + var criteria = arrayMap(iteratees, function(iteratee) { + return iteratee(value); + }); + return { 'criteria': criteria, 'index': ++index, 'value': value }; + }); + + return baseSortBy(result, function(object, other) { + return compareMultiple(object, other, orders); + }); + } + + /** + * The base implementation of `_.pick` without support for individual + * property identifiers. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @returns {Object} Returns the new object. + */ + function basePick(object, paths) { + return basePickBy(object, paths, function(value, path) { + return hasIn(object, path); + }); + } + + /** + * The base implementation of `_.pickBy` without support for iteratee shorthands. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. + */ + function basePickBy(object, paths, predicate) { + var index = -1, + length = paths.length, + result = {}; + + while (++index < length) { + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } + } + return result; + } + + /** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyDeep(path) { + return function(object) { + return baseGet(object, path); + }; + } + + /** + * The base implementation of `_.pullAllBy` without support for iteratee + * shorthands. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + */ + function basePullAll(array, values, iteratee, comparator) { + var indexOf = comparator ? baseIndexOfWith : baseIndexOf, + index = -1, + length = values.length, + seen = array; + + if (array === values) { + values = copyArray(values); + } + if (iteratee) { + seen = arrayMap(array, baseUnary(iteratee)); + } + while (++index < length) { + var fromIndex = 0, + value = values[index], + computed = iteratee ? iteratee(value) : value; + + while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { + if (seen !== array) { + splice.call(seen, fromIndex, 1); + } + splice.call(array, fromIndex, 1); + } + } + return array; + } + + /** + * The base implementation of `_.pullAt` without support for individual + * indexes or capturing the removed elements. + * + * @private + * @param {Array} array The array to modify. + * @param {number[]} indexes The indexes of elements to remove. + * @returns {Array} Returns `array`. + */ + function basePullAt(array, indexes) { + var length = array ? indexes.length : 0, + lastIndex = length - 1; + + while (length--) { + var index = indexes[length]; + if (length == lastIndex || index !== previous) { + var previous = index; + if (isIndex(index)) { + splice.call(array, index, 1); + } else { + baseUnset(array, index); + } + } + } + return array; + } + + /** + * The base implementation of `_.random` without support for returning + * floating-point numbers. + * + * @private + * @param {number} lower The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the random number. + */ + function baseRandom(lower, upper) { + return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); + } + + /** + * The base implementation of `_.range` and `_.rangeRight` which doesn't + * coerce arguments. + * + * @private + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @param {number} step The value to increment or decrement by. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the range of numbers. + */ + function baseRange(start, end, step, fromRight) { + var index = -1, + length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), + result = Array(length); + + while (length--) { + result[fromRight ? length : ++index] = start; + start += step; + } + return result; + } + + /** + * The base implementation of `_.repeat` which doesn't coerce arguments. + * + * @private + * @param {string} string The string to repeat. + * @param {number} n The number of times to repeat the string. + * @returns {string} Returns the repeated string. + */ + function baseRepeat(string, n) { + var result = ''; + if (!string || n < 1 || n > MAX_SAFE_INTEGER) { + return result; + } + // Leverage the exponentiation by squaring algorithm for a faster repeat. + // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. + do { + if (n % 2) { + result += string; + } + n = nativeFloor(n / 2); + if (n) { + string += string; + } + } while (n); + + return result; + } + + /** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ + function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); + } + + /** + * The base implementation of `_.sample`. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + */ + function baseSample(collection) { + return arraySample(values(collection)); + } + + /** + * The base implementation of `_.sampleSize` without param guards. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function baseSampleSize(collection, n) { + var array = values(collection); + return shuffleSelf(array, baseClamp(n, 0, array.length)); + } + + /** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; + } + + /** + * The base implementation of `setData` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var baseSetData = !metaMap ? identity : function(func, data) { + metaMap.set(func, data); + return func; + }; + + /** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); + }; + + /** + * The base implementation of `_.shuffle`. + * + * @private + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function baseShuffle(collection) { + return shuffleSelf(values(collection)); + } + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } + + /** + * The base implementation of `_.some` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function baseSome(collection, predicate) { + var result; + + baseEach(collection, function(value, index, collection) { + result = predicate(value, index, collection); + return !result; + }); + return !!result; + } + + /** + * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which + * performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndex(array, value, retHighest) { + var low = 0, + high = array == null ? low : array.length; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if (computed !== null && !isSymbol(computed) && + (retHighest ? (computed <= value) : (computed < value))) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return baseSortedIndexBy(array, value, identity, retHighest); + } + + /** + * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` + * which invokes `iteratee` for `value` and each element of `array` to compute + * their sort ranking. The iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The iteratee invoked per element. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array == null ? 0 : array.length, + valIsNaN = value !== value, + valIsNull = value === null, + valIsSymbol = isSymbol(value), + valIsUndefined = value === undefined; + + while (low < high) { + var mid = nativeFloor((low + high) / 2), + computed = iteratee(array[mid]), + othIsDefined = computed !== undefined, + othIsNull = computed === null, + othIsReflexive = computed === computed, + othIsSymbol = isSymbol(computed); + + if (valIsNaN) { + var setLow = retHighest || othIsReflexive; + } else if (valIsUndefined) { + setLow = othIsReflexive && (retHighest || othIsDefined); + } else if (valIsNull) { + setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); + } else if (valIsSymbol) { + setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); + } else if (othIsNull || othIsSymbol) { + setLow = false; + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } + + /** + * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseSortedUniq(array, iteratee) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + if (!index || !eq(computed, seen)) { + var seen = computed; + result[resIndex++] = value === 0 ? 0 : value; + } + } + return result; + } + + /** + * The base implementation of `_.toNumber` which doesn't ensure correct + * conversions of binary, hexadecimal, or octal string values. + * + * @private + * @param {*} value The value to process. + * @returns {number} Returns the number. + */ + function baseToNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + return +value; + } + + /** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * The base implementation of `_.uniqBy` without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseUniq(array, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + length = array.length, + isCommon = true, + result = [], + seen = result; + + if (comparator) { + isCommon = false; + includes = arrayIncludesWith; + } + else if (length >= LARGE_ARRAY_SIZE) { + var set = iteratee ? null : createSet(array); + if (set) { + return setToArray(set); + } + isCommon = false; + includes = cacheHas; + seen = new SetCache; + } + else { + seen = iteratee ? [] : result; + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } + else if (!includes(seen, computed, comparator)) { + if (seen !== result) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.unset`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The property path to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + */ + function baseUnset(object, path) { + path = castPath(path, object); + object = parent(object, path); + return object == null || delete object[toKey(last(path))]; + } + + /** + * The base implementation of `_.update`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to update. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseUpdate(object, path, updater, customizer) { + return baseSet(object, path, updater(baseGet(object, path)), customizer); + } + + /** + * The base implementation of methods like `_.dropWhile` and `_.takeWhile` + * without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to query. + * @param {Function} predicate The function invoked per iteration. + * @param {boolean} [isDrop] Specify dropping elements instead of taking them. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the slice of `array`. + */ + function baseWhile(array, predicate, isDrop, fromRight) { + var length = array.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length) && + predicate(array[index], index, array)) {} + + return isDrop + ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) + : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); + } + + /** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to perform to resolve the unwrapped value. + * @returns {*} Returns the resolved value. + */ + function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + return arrayReduce(actions, function(result, action) { + return action.func.apply(action.thisArg, arrayPush([result], action.args)); + }, result); + } + + /** + * The base implementation of methods like `_.xor`, without support for + * iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of values. + */ + function baseXor(arrays, iteratee, comparator) { + var length = arrays.length; + if (length < 2) { + return length ? baseUniq(arrays[0]) : []; + } + var index = -1, + result = Array(length); + + while (++index < length) { + var array = arrays[index], + othIndex = -1; + + while (++othIndex < length) { + if (othIndex != index) { + result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator); + } + } + } + return baseUniq(baseFlatten(result, 1), iteratee, comparator); + } + + /** + * This base implementation of `_.zipObject` which assigns values using `assignFunc`. + * + * @private + * @param {Array} props The property identifiers. + * @param {Array} values The property values. + * @param {Function} assignFunc The function to assign values. + * @returns {Object} Returns the new object. + */ + function baseZipObject(props, values, assignFunc) { + var index = -1, + length = props.length, + valsLength = values.length, + result = {}; + + while (++index < length) { + var value = index < valsLength ? values[index] : undefined; + assignFunc(result, props[index], value); + } + return result; + } + + /** + * Casts `value` to an empty array if it's not an array like object. + * + * @private + * @param {*} value The value to inspect. + * @returns {Array|Object} Returns the cast array-like object. + */ + function castArrayLikeObject(value) { + return isArrayLikeObject(value) ? value : []; + } + + /** + * Casts `value` to `identity` if it's not a function. + * + * @private + * @param {*} value The value to inspect. + * @returns {Function} Returns cast function. + */ + function castFunction(value) { + return typeof value == 'function' ? value : identity; + } + + /** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ + function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); + } + + /** + * A `baseRest` alias which can be replaced with `identity` by module + * replacement plugins. + * + * @private + * @type {Function} + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + var castRest = baseRest; + + /** + * Casts `array` to a slice if it's needed. + * + * @private + * @param {Array} array The array to inspect. + * @param {number} start The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the cast slice. + */ + function castSlice(array, start, end) { + var length = array.length; + end = end === undefined ? length : end; + return (!start && end >= length) ? array : baseSlice(array, start, end); + } + + /** + * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). + * + * @private + * @param {number|Object} id The timer id or timeout object of the timer to clear. + */ + var clearTimeout = ctxClearTimeout || function(id) { + return root.clearTimeout(id); + }; + + /** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ + function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; + } + + /** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; + } + + /** + * Creates a clone of `dataView`. + * + * @private + * @param {Object} dataView The data view to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned data view. + */ + function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); + } + + /** + * Creates a clone of `regexp`. + * + * @private + * @param {Object} regexp The regexp to clone. + * @returns {Object} Returns the cloned regexp. + */ + function cloneRegExp(regexp) { + var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); + result.lastIndex = regexp.lastIndex; + return result; + } + + /** + * Creates a clone of the `symbol` object. + * + * @private + * @param {Object} symbol The symbol object to clone. + * @returns {Object} Returns the cloned symbol object. + */ + function cloneSymbol(symbol) { + return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; + } + + /** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ + function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); + } + + /** + * Compares values to sort them in ascending order. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. + */ + function compareAscending(value, other) { + if (value !== other) { + var valIsDefined = value !== undefined, + valIsNull = value === null, + valIsReflexive = value === value, + valIsSymbol = isSymbol(value); + + var othIsDefined = other !== undefined, + othIsNull = other === null, + othIsReflexive = other === other, + othIsSymbol = isSymbol(other); + + if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || + (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || + (valIsNull && othIsDefined && othIsReflexive) || + (!valIsDefined && othIsReflexive) || + !valIsReflexive) { + return 1; + } + if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || + (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || + (othIsNull && valIsDefined && valIsReflexive) || + (!othIsDefined && valIsReflexive) || + !othIsReflexive) { + return -1; + } + } + return 0; + } + + /** + * Used by `_.orderBy` to compare multiple properties of a value to another + * and stable sort them. + * + * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, + * specify an order of "desc" for descending or "asc" for ascending sort order + * of corresponding values. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {boolean[]|string[]} orders The order to sort by for each property. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareMultiple(object, other, orders) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length, + ordersLength = orders.length; + + while (++index < length) { + var result = compareAscending(objCriteria[index], othCriteria[index]); + if (result) { + if (index >= ordersLength) { + return result; + } + var order = orders[index]; + return result * (order == 'desc' ? -1 : 1); + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; + } + + /** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgs(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersLength = holders.length, + leftIndex = -1, + leftLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(leftLength + rangeLength), + isUncurried = !isCurried; + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + } + while (rangeLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; + } + + /** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgsRight(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersIndex = -1, + holdersLength = holders.length, + rightIndex = -1, + rightLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(rangeLength + rightLength), + isUncurried = !isCurried; + + while (++argsIndex < rangeLength) { + result[argsIndex] = args[argsIndex]; + } + var offset = argsIndex; + while (++rightIndex < rightLength) { + result[offset + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[offset + holders[holdersIndex]] = args[argsIndex++]; + } + } + return result; + } + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ + function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; + } + + /** + * Copies own symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbols(source, object) { + return copyObject(source, getSymbols(source), object); + } + + /** + * Copies own and inherited symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbolsIn(source, object) { + return copyObject(source, getSymbolsIn(source), object); + } + + /** + * Creates a function like `_.groupBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} [initializer] The accumulator object initializer. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter, initializer) { + return function(collection, iteratee) { + var func = isArray(collection) ? arrayAggregator : baseAggregator, + accumulator = initializer ? initializer() : {}; + + return func(collection, setter, getIteratee(iteratee, 2), accumulator); + }; + } + + /** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); + } + + /** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseEach(eachFunc, fromRight) { + return function(collection, iteratee) { + if (collection == null) { + return collection; + } + if (!isArrayLike(collection)) { + return eachFunc(collection, iteratee); + } + var length = collection.length, + index = fromRight ? length : -1, + iterable = Object(collection); + + while ((fromRight ? index-- : ++index < length)) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; + } + + /** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; + } + + /** + * Creates a function that wraps `func` to invoke it with the optional `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createBind(func, bitmask, thisArg) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return fn.apply(isBind ? thisArg : this, arguments); + } + return wrapper; + } + + /** + * Creates a function like `_.lowerFirst`. + * + * @private + * @param {string} methodName The name of the `String` case method to use. + * @returns {Function} Returns the new case function. + */ + function createCaseFirst(methodName) { + return function(string) { + string = toString(string); + + var strSymbols = hasUnicode(string) + ? stringToArray(string) + : undefined; + + var chr = strSymbols + ? strSymbols[0] + : string.charAt(0); + + var trailing = strSymbols + ? castSlice(strSymbols, 1).join('') + : string.slice(1); + + return chr[methodName]() + trailing; + }; + } + + /** + * Creates a function like `_.camelCase`. + * + * @private + * @param {Function} callback The function to combine each word. + * @returns {Function} Returns the new compounder function. + */ + function createCompounder(callback) { + return function(string) { + return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); + }; + } + + /** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ + function createCtor(Ctor) { + return function() { + // Use a `switch` statement to work with class constructors. See + // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist + // for more details. + var args = arguments; + switch (args.length) { + case 0: return new Ctor; + case 1: return new Ctor(args[0]); + case 2: return new Ctor(args[0], args[1]); + case 3: return new Ctor(args[0], args[1], args[2]); + case 4: return new Ctor(args[0], args[1], args[2], args[3]); + case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); + case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + } + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, args); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; + } + + /** + * Creates a function that wraps `func` to enable currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {number} arity The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createCurry(func, bitmask, arity) { + var Ctor = createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length, + placeholder = getHolder(wrapper); + + while (index--) { + args[index] = arguments[index]; + } + var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) + ? [] + : replaceHolders(args, placeholder); + + length -= holders.length; + if (length < arity) { + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, undefined, + args, holders, undefined, undefined, arity - length); + } + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return apply(fn, this, args); + } + return wrapper; + } + + /** + * Creates a `_.find` or `_.findLast` function. + * + * @private + * @param {Function} findIndexFunc The function to find the collection index. + * @returns {Function} Returns the new find function. + */ + function createFind(findIndexFunc) { + return function(collection, predicate, fromIndex) { + var iterable = Object(collection); + if (!isArrayLike(collection)) { + var iteratee = getIteratee(predicate, 3); + collection = keys(collection); + predicate = function(key) { return iteratee(iterable[key], key, iterable); }; + } + var index = findIndexFunc(collection, predicate, fromIndex); + return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; + }; + } + + /** + * Creates a `_.flow` or `_.flowRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new flow function. + */ + function createFlow(fromRight) { + return flatRest(function(funcs) { + var length = funcs.length, + index = length, + prereq = LodashWrapper.prototype.thru; + + if (fromRight) { + funcs.reverse(); + } + while (index--) { + var func = funcs[index]; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (prereq && !wrapper && getFuncName(func) == 'wrapper') { + var wrapper = new LodashWrapper([], true); + } + } + index = wrapper ? index : length; + while (++index < length) { + func = funcs[index]; + + var funcName = getFuncName(func), + data = funcName == 'wrapper' ? getData(func) : undefined; + + if (data && isLaziable(data[0]) && + data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && + !data[4].length && data[9] == 1 + ) { + wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); + } else { + wrapper = (func.length == 1 && isLaziable(func)) + ? wrapper[funcName]() + : wrapper.thru(func); + } + } + return function() { + var args = arguments, + value = args[0]; + + if (wrapper && args.length == 1 && isArray(value)) { + return wrapper.plant(value).value(); + } + var index = 0, + result = length ? funcs[index].apply(this, args) : value; + + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; + }); + } + + /** + * Creates a function that wraps `func` to invoke it with optional `this` + * binding of `thisArg`, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided + * to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + var isAry = bitmask & WRAP_ARY_FLAG, + isBind = bitmask & WRAP_BIND_FLAG, + isBindKey = bitmask & WRAP_BIND_KEY_FLAG, + isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), + isFlip = bitmask & WRAP_FLIP_FLAG, + Ctor = isBindKey ? undefined : createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length; + + while (index--) { + args[index] = arguments[index]; + } + if (isCurried) { + var placeholder = getHolder(wrapper), + holdersCount = countHolders(args, placeholder); + } + if (partials) { + args = composeArgs(args, partials, holders, isCurried); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight, isCurried); + } + length -= holdersCount; + if (isCurried && length < arity) { + var newHolders = replaceHolders(args, placeholder); + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, thisArg, + args, newHolders, argPos, ary, arity - length + ); + } + var thisBinding = isBind ? thisArg : this, + fn = isBindKey ? thisBinding[func] : func; + + length = args.length; + if (argPos) { + args = reorder(args, argPos); + } else if (isFlip && length > 1) { + args.reverse(); + } + if (isAry && ary < length) { + args.length = ary; + } + if (this && this !== root && this instanceof wrapper) { + fn = Ctor || createCtor(fn); + } + return fn.apply(thisBinding, args); + } + return wrapper; + } + + /** + * Creates a function like `_.invertBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} toIteratee The function to resolve iteratees. + * @returns {Function} Returns the new inverter function. + */ + function createInverter(setter, toIteratee) { + return function(object, iteratee) { + return baseInverter(object, setter, toIteratee(iteratee), {}); + }; + } + + /** + * Creates a function that performs a mathematical operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @param {number} [defaultValue] The value used for `undefined` arguments. + * @returns {Function} Returns the new mathematical operation function. + */ + function createMathOperation(operator, defaultValue) { + return function(value, other) { + var result; + if (value === undefined && other === undefined) { + return defaultValue; + } + if (value !== undefined) { + result = value; + } + if (other !== undefined) { + if (result === undefined) { + return other; + } + if (typeof value == 'string' || typeof other == 'string') { + value = baseToString(value); + other = baseToString(other); + } else { + value = baseToNumber(value); + other = baseToNumber(other); + } + result = operator(value, other); + } + return result; + }; + } + + /** + * Creates a function like `_.over`. + * + * @private + * @param {Function} arrayFunc The function to iterate over iteratees. + * @returns {Function} Returns the new over function. + */ + function createOver(arrayFunc) { + return flatRest(function(iteratees) { + iteratees = arrayMap(iteratees, baseUnary(getIteratee())); + return baseRest(function(args) { + var thisArg = this; + return arrayFunc(iteratees, function(iteratee) { + return apply(iteratee, thisArg, args); + }); + }); + }); + } + + /** + * Creates the padding for `string` based on `length`. The `chars` string + * is truncated if the number of characters exceeds `length`. + * + * @private + * @param {number} length The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padding for `string`. + */ + function createPadding(length, chars) { + chars = chars === undefined ? ' ' : baseToString(chars); + + var charsLength = chars.length; + if (charsLength < 2) { + return charsLength ? baseRepeat(chars, length) : chars; + } + var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); + return hasUnicode(chars) + ? castSlice(stringToArray(result), 0, length).join('') + : result.slice(0, length); + } + + /** + * Creates a function that wraps `func` to invoke it with the `this` binding + * of `thisArg` and `partials` prepended to the arguments it receives. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to + * the new function. + * @returns {Function} Returns the new wrapped function. + */ + function createPartial(func, bitmask, thisArg, partials) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(leftLength + argsLength), + fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + return apply(fn, isBind ? thisArg : this, args); + } + return wrapper; + } + + /** + * Creates a `_.range` or `_.rangeRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new range function. + */ + function createRange(fromRight) { + return function(start, end, step) { + if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { + end = step = undefined; + } + // Ensure the sign of `-0` is preserved. + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); + return baseRange(start, end, step, fromRight); + }; + } + + /** + * Creates a function that performs a relational operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @returns {Function} Returns the new relational operation function. + */ + function createRelationalOperation(operator) { + return function(value, other) { + if (!(typeof value == 'string' && typeof other == 'string')) { + value = toNumber(value); + other = toNumber(other); + } + return operator(value, other); + }; + } + + /** + * Creates a function that wraps `func` to continue currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {Function} wrapFunc The function to create the `func` wrapper. + * @param {*} placeholder The placeholder value. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { + var isCurry = bitmask & WRAP_CURRY_FLAG, + newHolders = isCurry ? holders : undefined, + newHoldersRight = isCurry ? undefined : holders, + newPartials = isCurry ? partials : undefined, + newPartialsRight = isCurry ? undefined : partials; + + bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); + + if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { + bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); + } + var newData = [ + func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, + newHoldersRight, argPos, ary, arity + ]; + + var result = wrapFunc.apply(undefined, newData); + if (isLaziable(func)) { + setData(result, newData); + } + result.placeholder = placeholder; + return setWrapToString(result, func, bitmask); + } + + /** + * Creates a function like `_.round`. + * + * @private + * @param {string} methodName The name of the `Math` method to use when rounding. + * @returns {Function} Returns the new round function. + */ + function createRound(methodName) { + var func = Math[methodName]; + return function(number, precision) { + number = toNumber(number); + precision = precision == null ? 0 : nativeMin(toInteger(precision), 292); + if (precision) { + // Shift with exponential notation to avoid floating-point issues. + // See [MDN](https://mdn.io/round#Examples) for more details. + var pair = (toString(number) + 'e').split('e'), + value = func(pair[0] + 'e' + (+pair[1] + precision)); + + pair = (toString(value) + 'e').split('e'); + return +(pair[0] + 'e' + (+pair[1] - precision)); + } + return func(number); + }; + } + + /** + * Creates a set object of `values`. + * + * @private + * @param {Array} values The values to add to the set. + * @returns {Object} Returns the new set. + */ + var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { + return new Set(values); + }; + + /** + * Creates a `_.toPairs` or `_.toPairsIn` function. + * + * @private + * @param {Function} keysFunc The function to get the keys of a given object. + * @returns {Function} Returns the new pairs function. + */ + function createToPairs(keysFunc) { + return function(object) { + var tag = getTag(object); + if (tag == mapTag) { + return mapToArray(object); + } + if (tag == setTag) { + return setToPairs(object); + } + return baseToPairs(object, keysFunc(object)); + }; + } + + /** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * 512 - `_.flip` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; + if (!isBindKey && typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); + partials = holders = undefined; + } + ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); + arity = arity === undefined ? arity : toInteger(arity); + length -= holders ? holders.length : 0; + + if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = undefined; + } + var data = isBindKey ? undefined : getData(func); + + var newData = [ + func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, + argPos, ary, arity + ]; + + if (data) { + mergeData(newData, data); + } + func = newData[0]; + bitmask = newData[1]; + thisArg = newData[2]; + partials = newData[3]; + holders = newData[4]; + arity = newData[9] = newData[9] === undefined + ? (isBindKey ? 0 : func.length) + : nativeMax(newData[9] - length, 0); + + if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { + bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); + } + if (!bitmask || bitmask == WRAP_BIND_FLAG) { + var result = createBind(func, bitmask, thisArg); + } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { + result = createCurry(func, bitmask, arity); + } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { + result = createPartial(func, bitmask, thisArg, partials); + } else { + result = createHybrid.apply(undefined, newData); + } + var setter = data ? baseSetData : setData; + return setWrapToString(setter(result, newData), func, bitmask); + } + + /** + * Used by `_.defaults` to customize its `_.assignIn` use to assign properties + * of source objects to the destination object for all destination properties + * that resolve to `undefined`. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to assign. + * @param {Object} object The parent object of `objValue`. + * @returns {*} Returns the value to assign. + */ + function customDefaultsAssignIn(objValue, srcValue, key, object) { + if (objValue === undefined || + (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { + return srcValue; + } + return objValue; + } + + /** + * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source + * objects into destination objects that are passed thru. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to merge. + * @param {Object} object The parent object of `objValue`. + * @param {Object} source The parent object of `srcValue`. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + * @returns {*} Returns the value to assign. + */ + function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { + if (isObject(objValue) && isObject(srcValue)) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, objValue); + baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); + stack['delete'](srcValue); + } + return objValue; + } + + /** + * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain + * objects. + * + * @private + * @param {*} value The value to inspect. + * @param {string} key The key of the property to inspect. + * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. + */ + function customOmitClone(value) { + return isPlainObject(value) ? undefined : value; + } + + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag: + case dateTag: + case numberTag: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag: + return object.name == other.name && object.message == other.message; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag: + var convert = mapToArray; + + case setTag: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; + } + + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseRest` which flattens the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + function flatRest(func) { + return setToString(overRest(func, undefined, flatten), func + ''); + } + + /** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); + } + + /** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); + } + + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + var getData = !metaMap ? noop : function(func) { + return metaMap.get(func); + }; + + /** + * Gets the name of `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {string} Returns the function name. + */ + function getFuncName(func) { + var result = (func.name + ''), + array = realNames[result], + length = hasOwnProperty.call(realNames, result) ? array.length : 0; + + while (length--) { + var data = array[length], + otherFunc = data.func; + if (otherFunc == null || otherFunc == func) { + return data.name; + } + } + return result; + } + + /** + * Gets the argument placeholder value for `func`. + * + * @private + * @param {Function} func The function to inspect. + * @returns {*} Returns the placeholder value. + */ + function getHolder(func) { + var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; + return object.placeholder; + } + + /** + * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, + * this function returns the custom method, otherwise it returns `baseIteratee`. + * If arguments are provided, the chosen function is invoked with them and + * its result is returned. + * + * @private + * @param {*} [value] The value to convert to an iteratee. + * @param {number} [arity] The arity of the created iteratee. + * @returns {Function} Returns the chosen function or its result. + */ + function getIteratee() { + var result = lodash.iteratee || iteratee; + result = result === iteratee ? baseIteratee : result; + return arguments.length ? result(arguments[0], arguments[1]) : result; + } + + /** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ + function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; + } + + /** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ + function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; + } + + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; + } + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; + } + + /** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable.call(object, symbol); + }); + }; + + /** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; + }; + + /** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + var getTag = baseGetTag; + + // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. + if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || + (Map && getTag(new Map) != mapTag) || + (Promise && getTag(Promise.resolve()) != promiseTag) || + (Set && getTag(new Set) != setTag) || + (WeakMap && getTag(new WeakMap) != weakMapTag)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag; + case mapCtorString: return mapTag; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag; + case weakMapCtorString: return weakMapTag; + } + } + return result; + }; + } + + /** + * Gets the view, applying any `transforms` to the `start` and `end` positions. + * + * @private + * @param {number} start The start of the view. + * @param {number} end The end of the view. + * @param {Array} transforms The transformations to apply to the view. + * @returns {Object} Returns an object containing the `start` and `end` + * positions of the view. + */ + function getView(start, end, transforms) { + var index = -1, + length = transforms.length; + + while (++index < length) { + var data = transforms[index], + size = data.size; + + switch (data.type) { + case 'drop': start += size; break; + case 'dropRight': end -= size; break; + case 'take': end = nativeMin(end, start + size); break; + case 'takeRight': start = nativeMax(start, end - size); break; + } + } + return { 'start': start, 'end': end }; + } + + /** + * Extracts wrapper details from the `source` body comment. + * + * @private + * @param {string} source The source to inspect. + * @returns {Array} Returns the wrapper details. + */ + function getWrapDetails(source) { + var match = source.match(reWrapDetails); + return match ? match[1].split(reSplitDetails) : []; + } + + /** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ + function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); + } + + /** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ + function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; + } + + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; + } + + /** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return cloneArrayBuffer(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case dataViewTag: + return cloneDataView(object, isDeep); + + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + return cloneTypedArray(object, isDeep); + + case mapTag: + return new Ctor; + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + return cloneRegExp(object); + + case setTag: + return new Ctor; + + case symbolTag: + return cloneSymbol(object); + } + } + + /** + * Inserts wrapper `details` in a comment at the top of the `source` body. + * + * @private + * @param {string} source The source to modify. + * @returns {Array} details The details to insert. + * @returns {string} Returns the modified source. + */ + function insertWrapDetails(source, details) { + var length = details.length; + if (!length) { + return source; + } + var lastIndex = length - 1; + details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; + details = details.join(length > 2 ? ', ' : ' '); + return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); + } + + /** + * Checks if `value` is a flattenable `arguments` object or array. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + */ + function isFlattenable(value) { + return isArray(value) || isArguments(value) || + !!(spreadableSymbol && value && value[spreadableSymbol]); + } + + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); + } + + /** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; + } + + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); + } + + /** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ + function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); + } + + /** + * Checks if `func` has a lazy counterpart. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` has a lazy counterpart, + * else `false`. + */ + function isLaziable(func) { + var funcName = getFuncName(func), + other = lodash[funcName]; + + if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { + return false; + } + if (func === other) { + return true; + } + var data = getData(other); + return !!data && func === data[0]; + } + + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } + + /** + * Checks if `func` is capable of being masked. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `func` is maskable, else `false`. + */ + var isMaskable = coreJsData ? isFunction : stubFalse; + + /** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ + function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; + } + + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && !isObject(value); + } + + /** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function matchesStrictComparable(key, srcValue) { + return function(object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; + } + + /** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ + function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; + } + + /** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers used to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and + * `_.rearg` modify function arguments, making the order in which they are + * executed important, preventing the merging of metadata. However, we make + * an exception for a safe combined case where curried functions have `_.ary` + * and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ + function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask, + isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); + + var isCombo = + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || + ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & WRAP_BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : value; + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = value; + } + // Use source `ary` if it's smaller. + if (srcBitmask & WRAP_ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; + } + + /** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; + } + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); + } + + /** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ + function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; + } + + /** + * Gets the parent value at `path` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path to get the parent value of. + * @returns {*} Returns the parent value. + */ + function parent(object, path) { + return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); + } + + /** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ + function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = copyArray(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; + } + + /** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity + * function to avoid garbage collection pauses in V8. See + * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var setData = shortOut(baseSetData); + + /** + * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @returns {number|Object} Returns the timer id or timeout object. + */ + var setTimeout = ctxSetTimeout || function(func, wait) { + return root.setTimeout(func, wait); + }; + + /** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var setToString = shortOut(baseSetToString); + + /** + * Sets the `toString` method of `wrapper` to mimic the source of `reference` + * with wrapper details in a comment at the top of the source body. + * + * @private + * @param {Function} wrapper The function to modify. + * @param {Function} reference The reference function. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Function} Returns `wrapper`. + */ + function setWrapToString(wrapper, reference, bitmask) { + var source = (reference + ''); + return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); + } + + /** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ + function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; + } + + /** + * A specialized version of `_.shuffle` which mutates and sets the size of `array`. + * + * @private + * @param {Array} array The array to shuffle. + * @param {number} [size=array.length] The size of `array`. + * @returns {Array} Returns `array`. + */ + function shuffleSelf(array, size) { + var index = -1, + length = array.length, + lastIndex = length - 1; + + size = size === undefined ? length : size; + while (++index < size) { + var rand = baseRandom(index, lastIndex), + value = array[rand]; + + array[rand] = array[index]; + array[index] = value; + } + array.length = size; + return array; + } + + /** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ + var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + }); + + /** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ + function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ + function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; + } + + /** + * Updates wrapper `details` based on `bitmask` flags. + * + * @private + * @returns {Array} details The details to modify. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Array} Returns `details`. + */ + function updateWrapDetails(details, bitmask) { + arrayEach(wrapFlags, function(pair) { + var value = '_.' + pair[0]; + if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { + details.push(value); + } + }); + return details.sort(); + } + + /** + * Creates a clone of `wrapper`. + * + * @private + * @param {Object} wrapper The wrapper to clone. + * @returns {Object} Returns the cloned wrapper. + */ + function wrapperClone(wrapper) { + if (wrapper instanceof LazyWrapper) { + return wrapper.clone(); + } + var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); + result.__actions__ = copyArray(wrapper.__actions__); + result.__index__ = wrapper.__index__; + result.__values__ = wrapper.__values__; + return result; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements split into groups the length of `size`. + * If `array` can't be split evenly, the final chunk will be the remaining + * elements. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to process. + * @param {number} [size=1] The length of each chunk + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the new array of chunks. + * @example + * + * _.chunk(['a', 'b', 'c', 'd'], 2); + * // => [['a', 'b'], ['c', 'd']] + * + * _.chunk(['a', 'b', 'c', 'd'], 3); + * // => [['a', 'b', 'c'], ['d']] + */ + function chunk(array, size, guard) { + if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { + size = 1; + } else { + size = nativeMax(toInteger(size), 0); + } + var length = array == null ? 0 : array.length; + if (!length || size < 1) { + return []; + } + var index = 0, + resIndex = 0, + result = Array(nativeCeil(length / size)); + + while (index < length) { + result[resIndex++] = baseSlice(array, index, (index += size)); + } + return result; + } + + /** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are falsey. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to compact. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * Creates a new array concatenating `array` with any additional arrays + * and/or values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to concatenate. + * @param {...*} [values] The values to concatenate. + * @returns {Array} Returns the new concatenated array. + * @example + * + * var array = [1]; + * var other = _.concat(array, 2, [3], [[4]]); + * + * console.log(other); + * // => [1, 2, 3, [4]] + * + * console.log(array); + * // => [1] + */ + function concat() { + var length = arguments.length; + if (!length) { + return []; + } + var args = Array(length - 1), + array = arguments[0], + index = length; + + while (index--) { + args[index - 1] = arguments[index]; + } + return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); + } + + /** + * Creates an array of `array` values not included in the other given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * **Note:** Unlike `_.pullAll`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.without, _.xor + * @example + * + * _.difference([2, 1], [2, 3]); + * // => [1] + */ + var difference = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `iteratee` which + * is invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * **Note:** Unlike `_.pullAllBy`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2] + * + * // The `_.property` iteratee shorthand. + * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var differenceBy = baseRest(function(array, values) { + var iteratee = last(values); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `comparator` + * which is invoked to compare elements of `array` to `values`. The order and + * references of result values are determined by the first array. The comparator + * is invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.pullAllWith`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * + * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); + * // => [{ 'x': 2, 'y': 1 }] + */ + var differenceWith = baseRest(function(array, values) { + var comparator = last(values); + if (isArrayLikeObject(comparator)) { + comparator = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) + : []; + }); + + /** + * Creates a slice of `array` with `n` elements dropped from the beginning. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.drop([1, 2, 3]); + * // => [2, 3] + * + * _.drop([1, 2, 3], 2); + * // => [3] + * + * _.drop([1, 2, 3], 5); + * // => [] + * + * _.drop([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function drop(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with `n` elements dropped from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRight([1, 2, 3]); + * // => [1, 2] + * + * _.dropRight([1, 2, 3], 2); + * // => [1] + * + * _.dropRight([1, 2, 3], 5); + * // => [] + * + * _.dropRight([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function dropRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` excluding elements dropped from the end. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.dropRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney'] + * + * // The `_.matches` iteratee shorthand. + * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropRightWhile(users, ['active', false]); + * // => objects for ['barney'] + * + * // The `_.property` iteratee shorthand. + * _.dropRightWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true, true) + : []; + } + + /** + * Creates a slice of `array` excluding elements dropped from the beginning. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.dropWhile(users, function(o) { return !o.active; }); + * // => objects for ['pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.dropWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropWhile(users, ['active', false]); + * // => objects for ['pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.dropWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true) + : []; + } + + /** + * Fills elements of `array` with `value` from `start` up to, but not + * including, `end`. + * + * **Note:** This method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Array + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.fill(array, 'a'); + * console.log(array); + * // => ['a', 'a', 'a'] + * + * _.fill(Array(3), 2); + * // => [2, 2, 2] + * + * _.fill([4, 6, 8, 10], '*', 1, 3); + * // => [4, '*', '*', 10] + */ + function fill(array, value, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { + start = 0; + end = length; + } + return baseFill(array, value, start, end); + } + + /** + * This method is like `_.find` except that it returns the index of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, function(o) { return o.user == 'barney'; }); + * // => 0 + * + * // The `_.matches` iteratee shorthand. + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findIndex(users, ['active', false]); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.findIndex(users, 'active'); + * // => 2 + */ + function findIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseFindIndex(array, getIteratee(predicate, 3), index); + } + + /** + * This method is like `_.findIndex` except that it iterates over elements + * of `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); + * // => 2 + * + * // The `_.matches` iteratee shorthand. + * _.findLastIndex(users, { 'user': 'barney', 'active': true }); + * // => 0 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastIndex(users, ['active', false]); + * // => 2 + * + * // The `_.property` iteratee shorthand. + * _.findLastIndex(users, 'active'); + * // => 0 + */ + function findLastIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length - 1; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = fromIndex < 0 + ? nativeMax(length + index, 0) + : nativeMin(index, length - 1); + } + return baseFindIndex(array, getIteratee(predicate, 3), index, true); + } + + /** + * Flattens `array` a single level deep. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2, [3, [4]], 5]]); + * // => [1, 2, [3, [4]], 5] + */ + function flatten(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, 1) : []; + } + + /** + * Recursively flattens `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2, [3, [4]], 5]]); + * // => [1, 2, 3, 4, 5] + */ + function flattenDeep(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, INFINITY) : []; + } + + /** + * Recursively flatten `array` up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Array + * @param {Array} array The array to flatten. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * var array = [1, [2, [3, [4]], 5]]; + * + * _.flattenDepth(array, 1); + * // => [1, 2, [3, [4]], 5] + * + * _.flattenDepth(array, 2); + * // => [1, 2, 3, [4], 5] + */ + function flattenDepth(array, depth) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(array, depth); + } + + /** + * The inverse of `_.toPairs`; this method returns an object composed + * from key-value `pairs`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} pairs The key-value pairs. + * @returns {Object} Returns the new object. + * @example + * + * _.fromPairs([['a', 1], ['b', 2]]); + * // => { 'a': 1, 'b': 2 } + */ + function fromPairs(pairs) { + var index = -1, + length = pairs == null ? 0 : pairs.length, + result = {}; + + while (++index < length) { + var pair = pairs[index]; + result[pair[0]] = pair[1]; + } + return result; + } + + /** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias first + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.head([1, 2, 3]); + * // => 1 + * + * _.head([]); + * // => undefined + */ + function head(array) { + return (array && array.length) ? array[0] : undefined; + } + + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the + * offset from the end of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // Search from the `fromIndex`. + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + */ + function indexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseIndexOf(array, value, index); + } + + /** + * Gets all but the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + */ + function initial(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 0, -1) : []; + } + + /** + * Creates an array of unique values that are included in all given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersection([2, 1], [2, 3]); + * // => [2] + */ + var intersection = baseRest(function(arrays) { + var mapped = arrayMap(arrays, castArrayLikeObject); + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `iteratee` + * which is invoked for each element of each `arrays` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [2.1] + * + * // The `_.property` iteratee shorthand. + * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }] + */ + var intersectionBy = baseRest(function(arrays) { + var iteratee = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + if (iteratee === last(mapped)) { + iteratee = undefined; + } else { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `comparator` + * which is invoked to compare elements of `arrays`. The order and references + * of result values are determined by the first array. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.intersectionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }] + */ + var intersectionWith = baseRest(function(arrays) { + var comparator = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + comparator = typeof comparator == 'function' ? comparator : undefined; + if (comparator) { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, undefined, comparator) + : []; + }); + + /** + * Converts all elements in `array` into a string separated by `separator`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to convert. + * @param {string} [separator=','] The element separator. + * @returns {string} Returns the joined string. + * @example + * + * _.join(['a', 'b', 'c'], '~'); + * // => 'a~b~c' + */ + function join(array, separator) { + return array == null ? '' : nativeJoin.call(array, separator); + } + + /** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ + function last(array) { + var length = array == null ? 0 : array.length; + return length ? array[length - 1] : undefined; + } + + /** + * This method is like `_.indexOf` except that it iterates over elements of + * `array` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.lastIndexOf([1, 2, 1, 2], 2); + * // => 3 + * + * // Search from the `fromIndex`. + * _.lastIndexOf([1, 2, 1, 2], 2, 2); + * // => 1 + */ + function lastIndexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); + } + return value === value + ? strictLastIndexOf(array, value, index) + : baseFindIndex(array, baseIsNaN, index, true); + } + + /** + * Gets the element at index `n` of `array`. If `n` is negative, the nth + * element from the end is returned. + * + * @static + * @memberOf _ + * @since 4.11.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=0] The index of the element to return. + * @returns {*} Returns the nth element of `array`. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * + * _.nth(array, 1); + * // => 'b' + * + * _.nth(array, -2); + * // => 'c'; + */ + function nth(array, n) { + return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; + } + + /** + * Removes all given values from `array` using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` + * to remove elements from an array by predicate. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...*} [values] The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pull(array, 'a', 'c'); + * console.log(array); + * // => ['b', 'b'] + */ + var pull = baseRest(pullAll); + + /** + * This method is like `_.pull` except that it accepts an array of values to remove. + * + * **Note:** Unlike `_.difference`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pullAll(array, ['a', 'c']); + * console.log(array); + * // => ['b', 'b'] + */ + function pullAll(array, values) { + return (array && array.length && values && values.length) + ? basePullAll(array, values) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `iteratee` which is + * invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The iteratee is invoked with one argument: (value). + * + * **Note:** Unlike `_.differenceBy`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; + * + * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); + * console.log(array); + * // => [{ 'x': 2 }] + */ + function pullAllBy(array, values, iteratee) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, getIteratee(iteratee, 2)) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `comparator` which + * is invoked to compare elements of `array` to `values`. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.differenceWith`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; + * + * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); + * console.log(array); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] + */ + function pullAllWith(array, values, comparator) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, undefined, comparator) + : array; + } + + /** + * Removes elements from `array` corresponding to `indexes` and returns an + * array of removed elements. + * + * **Note:** Unlike `_.at`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...(number|number[])} [indexes] The indexes of elements to remove. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * var pulled = _.pullAt(array, [1, 3]); + * + * console.log(array); + * // => ['a', 'c'] + * + * console.log(pulled); + * // => ['b', 'd'] + */ + var pullAt = flatRest(function(array, indexes) { + var length = array == null ? 0 : array.length, + result = baseAt(array, indexes); + + basePullAt(array, arrayMap(indexes, function(index) { + return isIndex(index, length) ? +index : index; + }).sort(compareAscending)); + + return result; + }); + + /** + * Removes all elements from `array` that `predicate` returns truthy for + * and returns an array of the removed elements. The predicate is invoked + * with three arguments: (value, index, array). + * + * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` + * to pull elements from an array by value. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [1, 2, 3, 4]; + * var evens = _.remove(array, function(n) { + * return n % 2 == 0; + * }); + * + * console.log(array); + * // => [1, 3] + * + * console.log(evens); + * // => [2, 4] + */ + function remove(array, predicate) { + var result = []; + if (!(array && array.length)) { + return result; + } + var index = -1, + indexes = [], + length = array.length; + + predicate = getIteratee(predicate, 3); + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result.push(value); + indexes.push(index); + } + } + basePullAt(array, indexes); + return result; + } + + /** + * Reverses `array` so that the first element becomes the last, the second + * element becomes the second to last, and so on. + * + * **Note:** This method mutates `array` and is based on + * [`Array#reverse`](https://mdn.io/Array/reverse). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.reverse(array); + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function reverse(array) { + return array == null ? array : nativeReverse.call(array); + } + + /** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This method is used instead of + * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are + * returned. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function slice(array, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; + } + else { + start = start == null ? 0 : toInteger(start); + end = end === undefined ? length : toInteger(end); + } + return baseSlice(array, start, end); + } + + /** + * Uses a binary search to determine the lowest index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + */ + function sortedIndex(array, value) { + return baseSortedIndex(array, value); + } + + /** + * This method is like `_.sortedIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); + * // => 0 + */ + function sortedIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); + } + + /** + * This method is like `_.indexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedIndexOf([4, 5, 5, 5, 6], 5); + * // => 1 + */ + function sortedIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value); + if (index < length && eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.sortedIndex` except that it returns the highest + * index at which `value` should be inserted into `array` in order to + * maintain its sort order. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedLastIndex([4, 5, 5, 5, 6], 5); + * // => 4 + */ + function sortedLastIndex(array, value) { + return baseSortedIndex(array, value, true); + } + + /** + * This method is like `_.sortedLastIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 1 + * + * // The `_.property` iteratee shorthand. + * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); + * // => 1 + */ + function sortedLastIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); + } + + /** + * This method is like `_.lastIndexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); + * // => 3 + */ + function sortedLastIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value, true) - 1; + if (eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.uniq` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniq([1, 1, 2]); + * // => [1, 2] + */ + function sortedUniq(array) { + return (array && array.length) + ? baseSortedUniq(array) + : []; + } + + /** + * This method is like `_.uniqBy` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); + * // => [1.1, 2.3] + */ + function sortedUniqBy(array, iteratee) { + return (array && array.length) + ? baseSortedUniq(array, getIteratee(iteratee, 2)) + : []; + } + + /** + * Gets all but the first element of `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.tail([1, 2, 3]); + * // => [2, 3] + */ + function tail(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 1, length) : []; + } + + /** + * Creates a slice of `array` with `n` elements taken from the beginning. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.take([1, 2, 3]); + * // => [1] + * + * _.take([1, 2, 3], 2); + * // => [1, 2] + * + * _.take([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.take([1, 2, 3], 0); + * // => [] + */ + function take(array, n, guard) { + if (!(array && array.length)) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` with `n` elements taken from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRight([1, 2, 3]); + * // => [3] + * + * _.takeRight([1, 2, 3], 2); + * // => [2, 3] + * + * _.takeRight([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.takeRight([1, 2, 3], 0); + * // => [] + */ + function takeRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with elements taken from the end. Elements are + * taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.takeRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeRightWhile(users, ['active', false]); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.takeRightWhile(users, 'active'); + * // => [] + */ + function takeRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), false, true) + : []; + } + + /** + * Creates a slice of `array` with elements taken from the beginning. Elements + * are taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.takeWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matches` iteratee shorthand. + * _.takeWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeWhile(users, ['active', false]); + * // => objects for ['barney', 'fred'] + * + * // The `_.property` iteratee shorthand. + * _.takeWhile(users, 'active'); + * // => [] + */ + function takeWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3)) + : []; + } + + /** + * Creates an array of unique values, in order, from all given arrays using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.union([2], [1, 2]); + * // => [2, 1] + */ + var union = baseRest(function(arrays) { + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); + }); + + /** + * This method is like `_.union` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which uniqueness is computed. Result values are chosen from the first + * array in which the value occurs. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.unionBy([2.1], [1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + var unionBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.union` except that it accepts `comparator` which + * is invoked to compare elements of `arrays`. Result values are chosen from + * the first array in which the value occurs. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.unionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var unionWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); + }); + + /** + * Creates a duplicate-free version of an array, using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons, in which only the first occurrence of each element + * is kept. The order of result values is determined by the order they occur + * in the array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniq([2, 1, 2]); + * // => [2, 1] + */ + function uniq(array) { + return (array && array.length) ? baseUniq(array) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the criterion by which + * uniqueness is computed. The order of result values is determined by the + * order they occur in the array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniqBy([2.1, 1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + function uniqBy(array, iteratee) { + return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `comparator` which + * is invoked to compare elements of `array`. The order of result values is + * determined by the order they occur in the array.The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.uniqWith(objects, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] + */ + function uniqWith(array, comparator) { + comparator = typeof comparator == 'function' ? comparator : undefined; + return (array && array.length) ? baseUniq(array, undefined, comparator) : []; + } + + /** + * This method is like `_.zip` except that it accepts an array of grouped + * elements and creates an array regrouping the elements to their pre-zip + * configuration. + * + * @static + * @memberOf _ + * @since 1.2.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + * + * _.unzip(zipped); + * // => [['a', 'b'], [1, 2], [true, false]] + */ + function unzip(array) { + if (!(array && array.length)) { + return []; + } + var length = 0; + array = arrayFilter(array, function(group) { + if (isArrayLikeObject(group)) { + length = nativeMax(group.length, length); + return true; + } + }); + return baseTimes(length, function(index) { + return arrayMap(array, baseProperty(index)); + }); + } + + /** + * This method is like `_.unzip` except that it accepts `iteratee` to specify + * how regrouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @param {Function} [iteratee=_.identity] The function to combine + * regrouped values. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip([1, 2], [10, 20], [100, 200]); + * // => [[1, 10, 100], [2, 20, 200]] + * + * _.unzipWith(zipped, _.add); + * // => [3, 30, 300] + */ + function unzipWith(array, iteratee) { + if (!(array && array.length)) { + return []; + } + var result = unzip(array); + if (iteratee == null) { + return result; + } + return arrayMap(result, function(group) { + return apply(iteratee, undefined, group); + }); + } + + /** + * Creates an array excluding all given values using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.pull`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...*} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.xor + * @example + * + * _.without([2, 1, 2, 3], 1, 2); + * // => [3] + */ + var without = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, values) + : []; + }); + + /** + * Creates an array of unique values that is the + * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) + * of the given arrays. The order of result values is determined by the order + * they occur in the arrays. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.without + * @example + * + * _.xor([2, 1], [2, 3]); + * // => [1, 3] + */ + var xor = baseRest(function(arrays) { + return baseXor(arrayFilter(arrays, isArrayLikeObject)); + }); + + /** + * This method is like `_.xor` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which by which they're compared. The order of result values is determined + * by the order they occur in the arrays. The iteratee is invoked with one + * argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2, 3.4] + * + * // The `_.property` iteratee shorthand. + * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var xorBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.xor` except that it accepts `comparator` which is + * invoked to compare elements of `arrays`. The order of result values is + * determined by the order they occur in the arrays. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.xorWith(objects, others, _.isEqual); + * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var xorWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); + }); + + /** + * Creates an array of grouped elements, the first of which contains the + * first elements of the given arrays, the second of which contains the + * second elements of the given arrays, and so on. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + */ + var zip = baseRest(unzip); + + /** + * This method is like `_.fromPairs` except that it accepts two arrays, + * one of property identifiers and one of corresponding values. + * + * @static + * @memberOf _ + * @since 0.4.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObject(['a', 'b'], [1, 2]); + * // => { 'a': 1, 'b': 2 } + */ + function zipObject(props, values) { + return baseZipObject(props || [], values || [], assignValue); + } + + /** + * This method is like `_.zipObject` except that it supports property paths. + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); + * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } + */ + function zipObjectDeep(props, values) { + return baseZipObject(props || [], values || [], baseSet); + } + + /** + * This method is like `_.zip` except that it accepts `iteratee` to specify + * how grouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @param {Function} [iteratee=_.identity] The function to combine + * grouped values. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { + * return a + b + c; + * }); + * // => [111, 222] + */ + var zipWith = baseRest(function(arrays) { + var length = arrays.length, + iteratee = length > 1 ? arrays[length - 1] : undefined; + + iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; + return unzipWith(arrays, iteratee); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` wrapper instance that wraps `value` with explicit method + * chain sequences enabled. The result of such sequences must be unwrapped + * with `_#value`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Seq + * @param {*} value The value to wrap. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'pebbles', 'age': 1 } + * ]; + * + * var youngest = _ + * .chain(users) + * .sortBy('age') + * .map(function(o) { + * return o.user + ' is ' + o.age; + * }) + * .head() + * .value(); + * // => 'pebbles is 1' + */ + function chain(value) { + var result = lodash(value); + result.__chain__ = true; + return result; + } + + /** + * This method invokes `interceptor` and returns `value`. The interceptor + * is invoked with one argument; (value). The purpose of this method is to + * "tap into" a method chain sequence in order to modify intermediate results. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns `value`. + * @example + * + * _([1, 2, 3]) + * .tap(function(array) { + * // Mutate input array. + * array.pop(); + * }) + * .reverse() + * .value(); + * // => [2, 1] + */ + function tap(value, interceptor) { + interceptor(value); + return value; + } + + /** + * This method is like `_.tap` except that it returns the result of `interceptor`. + * The purpose of this method is to "pass thru" values replacing intermediate + * results in a method chain sequence. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns the result of `interceptor`. + * @example + * + * _(' abc ') + * .chain() + * .trim() + * .thru(function(value) { + * return [value]; + * }) + * .value(); + * // => ['abc'] + */ + function thru(value, interceptor) { + return interceptor(value); + } + + /** + * This method is the wrapper version of `_.at`. + * + * @name at + * @memberOf _ + * @since 1.0.0 + * @category Seq + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _(object).at(['a[0].b.c', 'a[1]']).value(); + * // => [3, 4] + */ + var wrapperAt = flatRest(function(paths) { + var length = paths.length, + start = length ? paths[0] : 0, + value = this.__wrapped__, + interceptor = function(object) { return baseAt(object, paths); }; + + if (length > 1 || this.__actions__.length || + !(value instanceof LazyWrapper) || !isIndex(start)) { + return this.thru(interceptor); + } + value = value.slice(start, +start + (length ? 1 : 0)); + value.__actions__.push({ + 'func': thru, + 'args': [interceptor], + 'thisArg': undefined + }); + return new LodashWrapper(value, this.__chain__).thru(function(array) { + if (length && !array.length) { + array.push(undefined); + } + return array; + }); + }); + + /** + * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. + * + * @name chain + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // A sequence without explicit chaining. + * _(users).head(); + * // => { 'user': 'barney', 'age': 36 } + * + * // A sequence with explicit chaining. + * _(users) + * .chain() + * .head() + * .pick('user') + * .value(); + * // => { 'user': 'barney' } + */ + function wrapperChain() { + return chain(this); + } + + /** + * Executes the chain sequence and returns the wrapped result. + * + * @name commit + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2]; + * var wrapped = _(array).push(3); + * + * console.log(array); + * // => [1, 2] + * + * wrapped = wrapped.commit(); + * console.log(array); + * // => [1, 2, 3] + * + * wrapped.last(); + * // => 3 + * + * console.log(array); + * // => [1, 2, 3] + */ + function wrapperCommit() { + return new LodashWrapper(this.value(), this.__chain__); + } + + /** + * Gets the next value on a wrapped object following the + * [iterator protocol](https://mdn.io/iteration_protocols#iterator). + * + * @name next + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the next iterator value. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped.next(); + * // => { 'done': false, 'value': 1 } + * + * wrapped.next(); + * // => { 'done': false, 'value': 2 } + * + * wrapped.next(); + * // => { 'done': true, 'value': undefined } + */ + function wrapperNext() { + if (this.__values__ === undefined) { + this.__values__ = toArray(this.value()); + } + var done = this.__index__ >= this.__values__.length, + value = done ? undefined : this.__values__[this.__index__++]; + + return { 'done': done, 'value': value }; + } + + /** + * Enables the wrapper to be iterable. + * + * @name Symbol.iterator + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the wrapper object. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped[Symbol.iterator]() === wrapped; + * // => true + * + * Array.from(wrapped); + * // => [1, 2] + */ + function wrapperToIterator() { + return this; + } + + /** + * Creates a clone of the chain sequence planting `value` as the wrapped value. + * + * @name plant + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @param {*} value The value to plant. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2]).map(square); + * var other = wrapped.plant([3, 4]); + * + * other.value(); + * // => [9, 16] + * + * wrapped.value(); + * // => [1, 4] + */ + function wrapperPlant(value) { + var result, + parent = this; + + while (parent instanceof baseLodash) { + var clone = wrapperClone(parent); + clone.__index__ = 0; + clone.__values__ = undefined; + if (result) { + previous.__wrapped__ = clone; + } else { + result = clone; + } + var previous = clone; + parent = parent.__wrapped__; + } + previous.__wrapped__ = value; + return result; + } + + /** + * This method is the wrapper version of `_.reverse`. + * + * **Note:** This method mutates the wrapped array. + * + * @name reverse + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2, 3]; + * + * _(array).reverse().value() + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function wrapperReverse() { + var value = this.__wrapped__; + if (value instanceof LazyWrapper) { + var wrapped = value; + if (this.__actions__.length) { + wrapped = new LazyWrapper(this); + } + wrapped = wrapped.reverse(); + wrapped.__actions__.push({ + 'func': thru, + 'args': [reverse], + 'thisArg': undefined + }); + return new LodashWrapper(wrapped, this.__chain__); + } + return this.thru(reverse); + } + + /** + * Executes the chain sequence to resolve the unwrapped value. + * + * @name value + * @memberOf _ + * @since 0.1.0 + * @alias toJSON, valueOf + * @category Seq + * @returns {*} Returns the resolved unwrapped value. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function wrapperValue() { + return baseWrapperValue(this.__wrapped__, this.__actions__); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the number of times the key was returned by `iteratee`. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': 1, '6': 2 } + * + * // The `_.property` iteratee shorthand. + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ + var countBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + ++result[key]; + } else { + baseAssignValue(result, key, 1); + } + }); + + /** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * **Note:** This method returns `true` for + * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because + * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of + * elements of empty collections. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * // => false + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.every(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.every(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.every(users, 'active'); + * // => false + */ + function every(collection, predicate, guard) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning an array of all elements + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * **Note:** Unlike `_.remove`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.reject + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * _.filter(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.filter(users, { 'age': 36, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.filter(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.filter(users, 'active'); + * // => objects for ['barney'] + */ + function filter(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': true } + * ]; + * + * _.find(users, function(o) { return o.age < 40; }); + * // => object for 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.find(users, { 'age': 1, 'active': true }); + * // => object for 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.find(users, ['active', false]); + * // => object for 'fred' + * + * // The `_.property` iteratee shorthand. + * _.find(users, 'active'); + * // => object for 'barney' + */ + var find = createFind(findIndex); + + /** + * This method is like `_.find` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=collection.length-1] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * _.findLast([1, 2, 3, 4], function(n) { + * return n % 2 == 1; + * }); + * // => 3 + */ + var findLast = createFind(findLastIndex); + + /** + * Creates a flattened array of values by running each element in `collection` + * thru `iteratee` and flattening the mapped results. The iteratee is invoked + * with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [n, n]; + * } + * + * _.flatMap([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMap(collection, iteratee) { + return baseFlatten(map(collection, iteratee), 1); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDeep([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMapDeep(collection, iteratee) { + return baseFlatten(map(collection, iteratee), INFINITY); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDepth([1, 2], duplicate, 2); + * // => [[1, 1], [2, 2]] + */ + function flatMapDepth(collection, iteratee, depth) { + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(map(collection, iteratee), depth); + } + + /** + * Iterates over elements of `collection` and invokes `iteratee` for each element. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" + * property are iterated like arrays. To avoid this behavior use `_.forIn` + * or `_.forOwn` for object iteration. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias each + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEachRight + * @example + * + * _.forEach([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `1` then `2`. + * + * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forEach(collection, iteratee) { + var func = isArray(collection) ? arrayEach : baseEach; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forEach` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @alias eachRight + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEach + * @example + * + * _.forEachRight([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `2` then `1`. + */ + function forEachRight(collection, iteratee) { + var func = isArray(collection) ? arrayEachRight : baseEachRight; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The order of grouped values + * is determined by the order they occur in `collection`. The corresponding + * value of each key is an array of elements responsible for generating the + * key. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': [4.2], '6': [6.1, 6.3] } + * + * // The `_.property` iteratee shorthand. + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + var groupBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + baseAssignValue(result, key, [value]); + } + }); + + /** + * Checks if `value` is in `collection`. If `collection` is a string, it's + * checked for a substring of `value`, otherwise + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * is used for equality comparisons. If `fromIndex` is negative, it's used as + * the offset from the end of `collection`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes([1, 2, 3], 1, 2); + * // => false + * + * _.includes({ 'a': 1, 'b': 2 }, 1); + * // => true + * + * _.includes('abcd', 'bc'); + * // => true + */ + function includes(collection, value, fromIndex, guard) { + collection = isArrayLike(collection) ? collection : values(collection); + fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; + + var length = collection.length; + if (fromIndex < 0) { + fromIndex = nativeMax(length + fromIndex, 0); + } + return isString(collection) + ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) + : (!!length && baseIndexOf(collection, value, fromIndex) > -1); + } + + /** + * Invokes the method at `path` of each element in `collection`, returning + * an array of the results of each invoked method. Any additional arguments + * are provided to each invoked method. If `path` is a function, it's invoked + * for, and `this` bound to, each element in `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Function|string} path The path of the method to invoke or + * the function invoked per iteration. + * @param {...*} [args] The arguments to invoke each method with. + * @returns {Array} Returns the array of results. + * @example + * + * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invokeMap([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ + var invokeMap = baseRest(function(collection, path, args) { + var index = -1, + isFunc = typeof path == 'function', + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value) { + result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args); + }); + return result; + }); + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the last element responsible for generating the key. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var array = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.keyBy(array, function(o) { + * return String.fromCharCode(o.code); + * }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.keyBy(array, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + */ + var keyBy = createAggregator(function(result, value, key) { + baseAssignValue(result, key, value); + }); + + /** + * Creates an array of values by running each element in `collection` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. + * + * The guarded methods are: + * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, + * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, + * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, + * `template`, `trim`, `trimEnd`, `trimStart`, and `words` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + * @example + * + * function square(n) { + * return n * n; + * } + * + * _.map([4, 8], square); + * // => [16, 64] + * + * _.map({ 'a': 4, 'b': 8 }, square); + * // => [16, 64] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // The `_.property` iteratee shorthand. + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ + function map(collection, iteratee) { + var func = isArray(collection) ? arrayMap : baseMap; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.sortBy` except that it allows specifying the sort + * orders of the iteratees to sort by. If `orders` is unspecified, all values + * are sorted in ascending order. Otherwise, specify an order of "desc" for + * descending or "asc" for ascending sort order of corresponding values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] + * The iteratees to sort by. + * @param {string[]} [orders] The sort orders of `iteratees`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 34 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 36 } + * ]; + * + * // Sort by `user` in ascending order and by `age` in descending order. + * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + */ + function orderBy(collection, iteratees, orders, guard) { + if (collection == null) { + return []; + } + if (!isArray(iteratees)) { + iteratees = iteratees == null ? [] : [iteratees]; + } + orders = guard ? undefined : orders; + if (!isArray(orders)) { + orders = orders == null ? [] : [orders]; + } + return baseOrderBy(collection, iteratees, orders); + } + + /** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, the second of which + * contains elements `predicate` returns falsey for. The predicate is + * invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.partition(users, function(o) { return o.active; }); + * // => objects for [['fred'], ['barney', 'pebbles']] + * + * // The `_.matches` iteratee shorthand. + * _.partition(users, { 'age': 1, 'active': false }); + * // => objects for [['pebbles'], ['barney', 'fred']] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.partition(users, ['active', false]); + * // => objects for [['barney', 'pebbles'], ['fred']] + * + * // The `_.property` iteratee shorthand. + * _.partition(users, 'active'); + * // => objects for [['fred'], ['barney', 'pebbles']] + */ + var partition = createAggregator(function(result, value, key) { + result[key ? 0 : 1].push(value); + }, function() { return [[], []]; }); + + /** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` thru `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not given, the first element of `collection` is used as the initial + * value. The iteratee is invoked with four arguments: + * (accumulator, value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.reduce`, `_.reduceRight`, and `_.transform`. + * + * The guarded methods are: + * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, + * and `sortBy` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduceRight + * @example + * + * _.reduce([1, 2], function(sum, n) { + * return sum + n; + * }, 0); + * // => 3 + * + * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * return result; + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) + */ + function reduce(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduce : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); + } + + /** + * This method is like `_.reduce` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduce + * @example + * + * var array = [[0, 1], [2, 3], [4, 5]]; + * + * _.reduceRight(array, function(flattened, other) { + * return flattened.concat(other); + * }, []); + * // => [4, 5, 2, 3, 0, 1] + */ + function reduceRight(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduceRight : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); + } + + /** + * The opposite of `_.filter`; this method returns the elements of `collection` + * that `predicate` does **not** return truthy for. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.filter + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * _.reject(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.reject(users, { 'age': 40, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.reject(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.reject(users, 'active'); + * // => objects for ['barney'] + */ + function reject(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, negate(getIteratee(predicate, 3))); + } + + /** + * Gets a random element from `collection`. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + */ + function sample(collection) { + var func = isArray(collection) ? arraySample : baseSample; + return func(collection); + } + + /** + * Gets `n` random elements at unique keys from `collection` up to the + * size of `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @param {number} [n=1] The number of elements to sample. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the random elements. + * @example + * + * _.sampleSize([1, 2, 3], 2); + * // => [3, 1] + * + * _.sampleSize([1, 2, 3], 4); + * // => [2, 3, 1] + */ + function sampleSize(collection, n, guard) { + if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + var func = isArray(collection) ? arraySampleSize : baseSampleSize; + return func(collection, n); + } + + /** + * Creates an array of shuffled values, using a version of the + * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + * @example + * + * _.shuffle([1, 2, 3, 4]); + * // => [4, 1, 3, 2] + */ + function shuffle(collection) { + var func = isArray(collection) ? arrayShuffle : baseShuffle; + return func(collection); + } + + /** + * Gets the size of `collection` by returning its length for array-like + * values or the number of own enumerable string keyed properties for objects. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * _.size([1, 2, 3]); + * // => 3 + * + * _.size({ 'a': 1, 'b': 2 }); + * // => 2 + * + * _.size('pebbles'); + * // => 7 + */ + function size(collection) { + if (collection == null) { + return 0; + } + if (isArrayLike(collection)) { + return isString(collection) ? stringSize(collection) : collection.length; + } + var tag = getTag(collection); + if (tag == mapTag || tag == setTag) { + return collection.size; + } + return baseKeys(collection).length; + } + + /** + * Checks if `predicate` returns truthy for **any** element of `collection`. + * Iteration is stopped once `predicate` returns truthy. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.some(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.some(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.some(users, 'active'); + * // => true + */ + function some(collection, predicate, guard) { + var func = isArray(collection) ? arraySome : baseSome; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection thru each iteratee. This method + * performs a stable sort, that is, it preserves the original sort order of + * equal elements. The iteratees are invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {...(Function|Function[])} [iteratees=[_.identity]] + * The iteratees to sort by. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 34 } + * ]; + * + * _.sortBy(users, [function(o) { return o.user; }]); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + * + * _.sortBy(users, ['user', 'age']); + * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] + */ + var sortBy = baseRest(function(collection, iteratees) { + if (collection == null) { + return []; + } + var length = iteratees.length; + if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { + iteratees = []; + } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { + iteratees = [iteratees[0]]; + } + return baseOrderBy(collection, baseFlatten(iteratees, 1), []); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Gets the timestamp of the number of milliseconds that have elapsed since + * the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Date + * @returns {number} Returns the timestamp. + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => Logs the number of milliseconds it took for the deferred invocation. + */ + var now = ctxNow || function() { + return root.Date.now(); + }; + + /*------------------------------------------------------------------------*/ + + /** + * The opposite of `_.before`; this method creates a function that invokes + * `func` once it's called `n` or more times. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {number} n The number of calls before `func` is invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => Logs 'done saving!' after the two async saves have completed. + */ + function after(n, func) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n < 1) { + return func.apply(this, arguments); + } + }; + } + + /** + * Creates a function that invokes `func`, with up to `n` arguments, + * ignoring any additional arguments. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @param {number} [n=func.length] The arity cap. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.ary(parseInt, 1)); + * // => [6, 8, 10] + */ + function ary(func, n, guard) { + n = guard ? undefined : n; + n = (func && n == null) ? func.length : n; + return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n); + } + + /** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it's called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery(element).on('click', _.before(5, addContactToList)); + * // => Allows adding up to 4 contacts to the list. + */ + function before(n, func) { + var result; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n > 0) { + result = func.apply(this, arguments); + } + if (n <= 1) { + func = undefined; + } + return result; + }; + } + + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and `partials` prepended to the arguments it receives. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" + * property of bound functions. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * function greet(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // Bound with placeholders. + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ + var bind = baseRest(function(func, thisArg, partials) { + var bitmask = WRAP_BIND_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bind)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(func, bitmask, thisArg, partials, holders); + }); + + /** + * Creates a function that invokes the method at `object[key]` with `partials` + * prepended to the arguments it receives. + * + * This method differs from `_.bind` by allowing bound functions to reference + * methods that may be redefined or don't yet exist. See + * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) + * for more details. + * + * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Function + * @param {Object} object The object to invoke the method on. + * @param {string} key The key of the method. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var object = { + * 'user': 'fred', + * 'greet': function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * }; + * + * var bound = _.bindKey(object, 'greet', 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * object.greet = function(greeting, punctuation) { + * return greeting + 'ya ' + this.user + punctuation; + * }; + * + * bound('!'); + * // => 'hiya fred!' + * + * // Bound with placeholders. + * var bound = _.bindKey(object, 'greet', _, '!'); + * bound('hi'); + * // => 'hiya fred!' + */ + var bindKey = baseRest(function(object, key, partials) { + var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bindKey)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(key, bitmask, object, partials, holders); + }); + + /** + * Creates a function that accepts arguments of `func` and either invokes + * `func` returning its result, if at least `arity` number of arguments have + * been provided, or returns a function that accepts the remaining `func` + * arguments, and so on. The arity of `func` may be specified if `func.length` + * is not sufficient. + * + * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curry(abc); + * + * curried(1)(2)(3); + * // => [1, 2, 3] + * + * curried(1, 2)(3); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(1)(_, 3)(2); + * // => [1, 2, 3] + */ + function curry(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curry.placeholder; + return result; + } + + /** + * This method is like `_.curry` except that arguments are applied to `func` + * in the manner of `_.partialRight` instead of `_.partial`. + * + * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curryRight(abc); + * + * curried(3)(2)(1); + * // => [1, 2, 3] + * + * curried(2, 3)(1); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(3)(1, _)(2); + * // => [1, 2, 3] + */ + function curryRight(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curryRight.placeholder; + return result; + } + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed `func` invocations and a `flush` method to immediately invoke them. + * Provide `options` to indicate whether `func` should be invoked on the + * leading and/or trailing edge of the `wait` timeout. The `func` is invoked + * with the last arguments provided to the debounced function. Subsequent + * calls to the debounced function return the result of the last `func` + * invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * var source = new EventSource('/stream'); + * jQuery(source).on('message', debounced); + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel); + */ + function debounce(func, wait, options) { + var lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime, + lastInvokeTime = 0, + leading = false, + maxing = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = toNumber(wait) || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function invokeFunc(time) { + var args = lastArgs, + thisArg = lastThis; + + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = setTimeout(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } + + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime, + timeWaiting = wait - timeSinceLastCall; + + return maxing + ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting; + } + + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime; + + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); + } + + function timerExpired() { + var time = now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = setTimeout(timerExpired, remainingWait(time)); + } + + function trailingEdge(time) { + timerId = undefined; + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } + + function cancel() { + if (timerId !== undefined) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } + + function flush() { + return timerId === undefined ? result : trailingEdge(now()); + } + + function debounced() { + var time = now(), + isInvoking = shouldInvoke(time); + + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; + } + + /** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { + * console.log(text); + * }, 'deferred'); + * // => Logs 'deferred' after one millisecond. + */ + var defer = baseRest(function(func, args) { + return baseDelay(func, 1, args); + }); + + /** + * Invokes `func` after `wait` milliseconds. Any additional arguments are + * provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { + * console.log(text); + * }, 1000, 'later'); + * // => Logs 'later' after one second. + */ + var delay = baseRest(function(func, wait, args) { + return baseDelay(func, toNumber(wait) || 0, args); + }); + + /** + * Creates a function that invokes `func` with arguments reversed. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to flip arguments for. + * @returns {Function} Returns the new flipped function. + * @example + * + * var flipped = _.flip(function() { + * return _.toArray(arguments); + * }); + * + * flipped('a', 'b', 'c', 'd'); + * // => ['d', 'c', 'b', 'a'] + */ + function flip(func) { + return createWrap(func, WRAP_FLIP_FLAG); + } + + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; + } + + // Expose `MapCache`. + memoize.Cache = MapCache; + + /** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new negated function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var args = arguments; + switch (args.length) { + case 0: return !predicate.call(this); + case 1: return !predicate.call(this, args[0]); + case 2: return !predicate.call(this, args[0], args[1]); + case 3: return !predicate.call(this, args[0], args[1], args[2]); + } + return !predicate.apply(this, args); + }; + } + + /** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first invocation. The `func` is + * invoked with the `this` binding and arguments of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // => `createApplication` is invoked once + */ + function once(func) { + return before(2, func); + } + + /** + * Creates a function that invokes `func` with its arguments transformed. + * + * @static + * @since 4.0.0 + * @memberOf _ + * @category Function + * @param {Function} func The function to wrap. + * @param {...(Function|Function[])} [transforms=[_.identity]] + * The argument transforms. + * @returns {Function} Returns the new function. + * @example + * + * function doubled(n) { + * return n * 2; + * } + * + * function square(n) { + * return n * n; + * } + * + * var func = _.overArgs(function(x, y) { + * return [x, y]; + * }, [square, doubled]); + * + * func(9, 3); + * // => [81, 6] + * + * func(10, 5); + * // => [100, 10] + */ + var overArgs = castRest(function(func, transforms) { + transforms = (transforms.length == 1 && isArray(transforms[0])) + ? arrayMap(transforms[0], baseUnary(getIteratee())) + : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); + + var funcsLength = transforms.length; + return baseRest(function(args) { + var index = -1, + length = nativeMin(args.length, funcsLength); + + while (++index < length) { + args[index] = transforms[index].call(this, args[index]); + } + return apply(func, this, args); + }); + }); + + /** + * Creates a function that invokes `func` with `partials` prepended to the + * arguments it receives. This method is like `_.bind` except it does **not** + * alter the `this` binding. + * + * The `_.partial.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 0.2.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var sayHelloTo = _.partial(greet, 'hello'); + * sayHelloTo('fred'); + * // => 'hello fred' + * + * // Partially applied with placeholders. + * var greetFred = _.partial(greet, _, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + */ + var partial = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partial)); + return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders); + }); + + /** + * This method is like `_.partial` except that partially applied arguments + * are appended to the arguments it receives. + * + * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var greetFred = _.partialRight(greet, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + * + * // Partially applied with placeholders. + * var sayHelloTo = _.partialRight(greet, 'hello', _); + * sayHelloTo('fred'); + * // => 'hello fred' + */ + var partialRight = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partialRight)); + return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders); + }); + + /** + * Creates a function that invokes `func` with arguments arranged according + * to the specified `indexes` where the argument value at the first index is + * provided as the first argument, the argument value at the second index is + * provided as the second argument, and so on. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to rearrange arguments for. + * @param {...(number|number[])} indexes The arranged argument indexes. + * @returns {Function} Returns the new function. + * @example + * + * var rearged = _.rearg(function(a, b, c) { + * return [a, b, c]; + * }, [2, 0, 1]); + * + * rearged('b', 'c', 'a') + * // => ['a', 'b', 'c'] + */ + var rearg = flatRest(function(func, indexes) { + return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes); + }); + + /** + * Creates a function that invokes `func` with the `this` binding of the + * created function and arguments from `start` and beyond provided as + * an array. + * + * **Note:** This method is based on the + * [rest parameter](https://mdn.io/rest_parameters). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.rest(function(what, names) { + * return what + ' ' + _.initial(names).join(', ') + + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); + * }); + * + * say('hello', 'fred', 'barney', 'pebbles'); + * // => 'hello fred, barney, & pebbles' + */ + function rest(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start === undefined ? start : toInteger(start); + return baseRest(func, start); + } + + /** + * Creates a function that invokes `func` with the `this` binding of the + * create function and an array of arguments much like + * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). + * + * **Note:** This method is based on the + * [spread operator](https://mdn.io/spread_operator). + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Function + * @param {Function} func The function to spread arguments over. + * @param {number} [start=0] The start position of the spread. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.spread(function(who, what) { + * return who + ' says ' + what; + * }); + * + * say(['fred', 'hello']); + * // => 'fred says hello' + * + * var numbers = Promise.all([ + * Promise.resolve(40), + * Promise.resolve(36) + * ]); + * + * numbers.then(_.spread(function(x, y) { + * return x + y; + * })); + * // => a Promise of 76 + */ + function spread(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start == null ? 0 : nativeMax(toInteger(start), 0); + return baseRest(function(args) { + var array = args[start], + otherArgs = castSlice(args, 0, start); + + if (array) { + arrayPush(otherArgs, array); + } + return apply(func, this, otherArgs); + }); + } + + /** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds. The throttled function comes with a `cancel` + * method to cancel delayed `func` invocations and a `flush` method to + * immediately invoke them. Provide `options` to indicate whether `func` + * should be invoked on the leading and/or trailing edge of the `wait` + * timeout. The `func` is invoked with the last arguments provided to the + * throttled function. Subsequent calls to the throttled function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the throttled function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] The number of milliseconds to throttle invocations to. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=true] + * Specify invoking on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // Avoid excessively updating the position while scrolling. + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); + * jQuery(element).on('click', throttled); + * + * // Cancel the trailing throttled invocation. + * jQuery(window).on('popstate', throttled.cancel); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + 'leading': leading, + 'maxWait': wait, + 'trailing': trailing + }); + } + + /** + * Creates a function that accepts up to one argument, ignoring any + * additional arguments. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.unary(parseInt)); + * // => [6, 8, 10] + */ + function unary(func) { + return ary(func, 1); + } + + /** + * Creates a function that provides `value` to `wrapper` as its first + * argument. Any additional arguments provided to the function are appended + * to those provided to the `wrapper`. The wrapper is invoked with the `this` + * binding of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {*} value The value to wrap. + * @param {Function} [wrapper=identity] The wrapper function. + * @returns {Function} Returns the new function. + * @example + * + * var p = _.wrap(_.escape, function(func, text) { + * return '

' + func(text) + '

'; + * }); + * + * p('fred, barney, & pebbles'); + * // => '

fred, barney, & pebbles

' + */ + function wrap(value, wrapper) { + return partial(castFunction(wrapper), value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Casts `value` as an array if it's not one. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Lang + * @param {*} value The value to inspect. + * @returns {Array} Returns the cast array. + * @example + * + * _.castArray(1); + * // => [1] + * + * _.castArray({ 'a': 1 }); + * // => [{ 'a': 1 }] + * + * _.castArray('abc'); + * // => ['abc'] + * + * _.castArray(null); + * // => [null] + * + * _.castArray(undefined); + * // => [undefined] + * + * _.castArray(); + * // => [] + * + * var array = [1, 2, 3]; + * console.log(_.castArray(array) === array); + * // => true + */ + function castArray() { + if (!arguments.length) { + return []; + } + var value = arguments[0]; + return isArray(value) ? value : [value]; + } + + /** + * Creates a shallow clone of `value`. + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) + * and supports cloning arrays, array buffers, booleans, date objects, maps, + * numbers, `Object` objects, regexes, sets, strings, symbols, and typed + * arrays. The own enumerable properties of `arguments` objects are cloned + * as plain objects. An empty object is returned for uncloneable values such + * as error objects, functions, DOM nodes, and WeakMaps. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to clone. + * @returns {*} Returns the cloned value. + * @see _.cloneDeep + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var shallow = _.clone(objects); + * console.log(shallow[0] === objects[0]); + * // => true + */ + function clone(value) { + return baseClone(value, CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.clone` except that it accepts `customizer` which + * is invoked to produce the cloned value. If `customizer` returns `undefined`, + * cloning is handled by the method instead. The `customizer` is invoked with + * up to four arguments; (value [, index|key, object, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the cloned value. + * @see _.cloneDeepWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(false); + * } + * } + * + * var el = _.cloneWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 0 + */ + function cloneWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * This method is like `_.clone` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @returns {*} Returns the deep cloned value. + * @see _.clone + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var deep = _.cloneDeep(objects); + * console.log(deep[0] === objects[0]); + * // => false + */ + function cloneDeep(value) { + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.cloneWith` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the deep cloned value. + * @see _.cloneWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(true); + * } + * } + * + * var el = _.cloneDeepWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 20 + */ + function cloneDeepWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * Checks if `object` conforms to `source` by invoking the predicate + * properties of `source` with the corresponding property values of `object`. + * + * **Note:** This method is equivalent to `_.conforms` when `source` is + * partially applied. + * + * @static + * @memberOf _ + * @since 4.14.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); + * // => true + * + * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); + * // => false + */ + function conformsTo(object, source) { + return source == null || baseConformsTo(object, source, keys(source)); + } + + /** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ + function eq(value, other) { + return value === other || (value !== value && other !== other); + } + + /** + * Checks if `value` is greater than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + * @see _.lt + * @example + * + * _.gt(3, 1); + * // => true + * + * _.gt(3, 3); + * // => false + * + * _.gt(1, 3); + * // => false + */ + var gt = createRelationalOperation(baseGt); + + /** + * Checks if `value` is greater than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than or equal to + * `other`, else `false`. + * @see _.lte + * @example + * + * _.gte(3, 1); + * // => true + * + * _.gte(3, 3); + * // => true + * + * _.gte(1, 3); + * // => false + */ + var gte = createRelationalOperation(function(value, other) { + return value >= other; + }); + + /** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); + }; + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray = Array.isArray; + + /** + * Checks if `value` is classified as an `ArrayBuffer` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + * @example + * + * _.isArrayBuffer(new ArrayBuffer(2)); + * // => true + * + * _.isArrayBuffer(new Array(2)); + * // => false + */ + var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; + + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ + function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); + } + + /** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ + function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); + } + + /** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return value === true || value === false || + (isObjectLike(value) && baseGetTag(value) == boolTag); + } + + /** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ + var isBuffer = nativeIsBuffer || stubFalse; + + /** + * Checks if `value` is classified as a `Date` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + * + * _.isDate('Mon April 23 2012'); + * // => false + */ + var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; + + /** + * Checks if `value` is likely a DOM element. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + * + * _.isElement(''); + * // => false + */ + function isElement(value) { + return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); + } + + /** + * Checks if `value` is an empty object, collection, map, or set. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Array-like values such as `arguments` objects, arrays, buffers, strings, or + * jQuery-like collections are considered empty if they have a `length` of `0`. + * Similarly, maps and sets are considered empty if they have a `size` of `0`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ + function isEmpty(value) { + if (value == null) { + return true; + } + if (isArrayLike(value) && + (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || + isBuffer(value) || isTypedArray(value) || isArguments(value))) { + return !value.length; + } + var tag = getTag(value); + if (tag == mapTag || tag == setTag) { + return !value.size; + } + if (isPrototype(value)) { + return !baseKeys(value).length; + } + for (var key in value) { + if (hasOwnProperty.call(value, key)) { + return false; + } + } + return true; + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are compared by strict equality, i.e. `===`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ + function isEqual(value, other) { + return baseIsEqual(value, other); + } + + /** + * This method is like `_.isEqual` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with up to + * six arguments: (objValue, othValue [, index|key, object, other, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, othValue) { + * if (isGreeting(objValue) && isGreeting(othValue)) { + * return true; + * } + * } + * + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqualWith(array, other, customizer); + * // => true + */ + function isEqualWith(value, other, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + var result = customizer ? customizer(value, other) : undefined; + return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; + } + + /** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an error object, else `false`. + * @example + * + * _.isError(new Error); + * // => true + * + * _.isError(Error); + * // => false + */ + function isError(value) { + if (!isObjectLike(value)) { + return false; + } + var tag = baseGetTag(value); + return tag == errorTag || tag == domExcTag || + (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); + } + + /** + * Checks if `value` is a finite primitive number. + * + * **Note:** This method is based on + * [`Number.isFinite`](https://mdn.io/Number/isFinite). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. + * @example + * + * _.isFinite(3); + * // => true + * + * _.isFinite(Number.MIN_VALUE); + * // => true + * + * _.isFinite(Infinity); + * // => false + * + * _.isFinite('3'); + * // => false + */ + function isFinite(value) { + return typeof value == 'number' && nativeIsFinite(value); + } + + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + } + + /** + * Checks if `value` is an integer. + * + * **Note:** This method is based on + * [`Number.isInteger`](https://mdn.io/Number/isInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an integer, else `false`. + * @example + * + * _.isInteger(3); + * // => true + * + * _.isInteger(Number.MIN_VALUE); + * // => false + * + * _.isInteger(Infinity); + * // => false + * + * _.isInteger('3'); + * // => false + */ + function isInteger(value) { + return typeof value == 'number' && value == toInteger(value); + } + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ + function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ + function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); + } + + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return value != null && typeof value == 'object'; + } + + /** + * Checks if `value` is classified as a `Map` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + * @example + * + * _.isMap(new Map); + * // => true + * + * _.isMap(new WeakMap); + * // => false + */ + var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; + + /** + * Performs a partial deep comparison between `object` and `source` to + * determine if `object` contains equivalent property values. + * + * **Note:** This method is equivalent to `_.matches` when `source` is + * partially applied. + * + * Partial comparisons will match empty array and empty object `source` + * values against any array or object value, respectively. See `_.isEqual` + * for a list of supported value comparisons. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.isMatch(object, { 'b': 2 }); + * // => true + * + * _.isMatch(object, { 'b': 1 }); + * // => false + */ + function isMatch(object, source) { + return object === source || baseIsMatch(object, source, getMatchData(source)); + } + + /** + * This method is like `_.isMatch` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with five + * arguments: (objValue, srcValue, index|key, object, source). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, srcValue) { + * if (isGreeting(objValue) && isGreeting(srcValue)) { + * return true; + * } + * } + * + * var object = { 'greeting': 'hello' }; + * var source = { 'greeting': 'hi' }; + * + * _.isMatchWith(object, source, customizer); + * // => true + */ + function isMatchWith(object, source, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseIsMatch(object, source, getMatchData(source), customizer); + } + + /** + * Checks if `value` is `NaN`. + * + * **Note:** This method is based on + * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as + * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for + * `undefined` and other non-number values. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some + // ActiveX objects in IE. + return isNumber(value) && value != +value; + } + + /** + * Checks if `value` is a pristine native function. + * + * **Note:** This method can't reliably detect native functions in the presence + * of the core-js package because core-js circumvents this kind of detection. + * Despite multiple requests, the core-js maintainer has made it clear: any + * attempt to fix the detection will be obstructed. As a result, we're left + * with little choice but to throw an error. Unfortunately, this also affects + * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), + * which rely on core-js. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ + function isNative(value) { + if (isMaskable(value)) { + throw new Error(CORE_ERROR_TEXT); + } + return baseIsNative(value); + } + + /** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(void 0); + * // => false + */ + function isNull(value) { + return value === null; + } + + /** + * Checks if `value` is `null` or `undefined`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is nullish, else `false`. + * @example + * + * _.isNil(null); + * // => true + * + * _.isNil(void 0); + * // => true + * + * _.isNil(NaN); + * // => false + */ + function isNil(value) { + return value == null; + } + + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are + * classified as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && baseGetTag(value) == numberTag); + } + + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; + } + + /** + * Checks if `value` is classified as a `RegExp` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false + */ + var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; + + /** + * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 + * double precision number which isn't the result of a rounded unsafe integer. + * + * **Note:** This method is based on + * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. + * @example + * + * _.isSafeInteger(3); + * // => true + * + * _.isSafeInteger(Number.MIN_VALUE); + * // => false + * + * _.isSafeInteger(Infinity); + * // => false + * + * _.isSafeInteger('3'); + * // => false + */ + function isSafeInteger(value) { + return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is classified as a `Set` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + * @example + * + * _.isSet(new Set); + * // => true + * + * _.isSet(new WeakSet); + * // => false + */ + var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); + } + + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); + } + + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + + /** + * Checks if `value` is `undefined`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + * + * _.isUndefined(null); + * // => false + */ + function isUndefined(value) { + return value === undefined; + } + + /** + * Checks if `value` is classified as a `WeakMap` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. + * @example + * + * _.isWeakMap(new WeakMap); + * // => true + * + * _.isWeakMap(new Map); + * // => false + */ + function isWeakMap(value) { + return isObjectLike(value) && getTag(value) == weakMapTag; + } + + /** + * Checks if `value` is classified as a `WeakSet` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. + * @example + * + * _.isWeakSet(new WeakSet); + * // => true + * + * _.isWeakSet(new Set); + * // => false + */ + function isWeakSet(value) { + return isObjectLike(value) && baseGetTag(value) == weakSetTag; + } + + /** + * Checks if `value` is less than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + * @see _.gt + * @example + * + * _.lt(1, 3); + * // => true + * + * _.lt(3, 3); + * // => false + * + * _.lt(3, 1); + * // => false + */ + var lt = createRelationalOperation(baseLt); + + /** + * Checks if `value` is less than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than or equal to + * `other`, else `false`. + * @see _.gte + * @example + * + * _.lte(1, 3); + * // => true + * + * _.lte(3, 3); + * // => true + * + * _.lte(3, 1); + * // => false + */ + var lte = createRelationalOperation(function(value, other) { + return value <= other; + }); + + /** + * Converts `value` to an array. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * _.toArray({ 'a': 1, 'b': 2 }); + * // => [1, 2] + * + * _.toArray('abc'); + * // => ['a', 'b', 'c'] + * + * _.toArray(1); + * // => [] + * + * _.toArray(null); + * // => [] + */ + function toArray(value) { + if (!value) { + return []; + } + if (isArrayLike(value)) { + return isString(value) ? stringToArray(value) : copyArray(value); + } + if (symIterator && value[symIterator]) { + return iteratorToArray(value[symIterator]()); + } + var tag = getTag(value), + func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); + + return func(value); + } + + /** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ + function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; + } + + /** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ + function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; + } + + /** + * Converts `value` to an integer suitable for use as the length of an + * array-like object. + * + * **Note:** This method is based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toLength(3.2); + * // => 3 + * + * _.toLength(Number.MIN_VALUE); + * // => 0 + * + * _.toLength(Infinity); + * // => 4294967295 + * + * _.toLength('3.2'); + * // => 3 + */ + function toLength(value) { + return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; + } + + /** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ + function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); + } + + /** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ + function toPlainObject(value) { + return copyObject(value, keysIn(value)); + } + + /** + * Converts `value` to a safe integer. A safe integer can be compared and + * represented correctly. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toSafeInteger(3.2); + * // => 3 + * + * _.toSafeInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toSafeInteger(Infinity); + * // => 9007199254740991 + * + * _.toSafeInteger('3.2'); + * // => 3 + */ + function toSafeInteger(value) { + return value + ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) + : (value === 0 ? value : 0); + } + + /** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ + function toString(value) { + return value == null ? '' : baseToString(value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Assigns own enumerable string keyed properties of source objects to the + * destination object. Source objects are applied from left to right. + * Subsequent sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object` and is loosely based on + * [`Object.assign`](https://mdn.io/Object/assign). + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assignIn + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assign({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'c': 3 } + */ + var assign = createAssigner(function(object, source) { + if (isPrototype(source) || isArrayLike(source)) { + copyObject(source, keys(source), object); + return; + } + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + assignValue(object, key, source[key]); + } + } + }); + + /** + * This method is like `_.assign` except that it iterates over own and + * inherited source properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assign + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assignIn({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } + */ + var assignIn = createAssigner(function(object, source) { + copyObject(source, keysIn(source), object); + }); + + /** + * This method is like `_.assignIn` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extendWith + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignInWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keysIn(source), object, customizer); + }); + + /** + * This method is like `_.assign` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignInWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keys(source), object, customizer); + }); + + /** + * Creates an array of values corresponding to `paths` of `object`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Array} Returns the picked values. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _.at(object, ['a[0].b.c', 'a[1]']); + * // => [3, 4] + */ + var at = flatRest(baseAt); + + /** + * Creates an object that inherits from the `prototype` object. If a + * `properties` object is given, its own enumerable string keyed properties + * are assigned to the created object. + * + * @static + * @memberOf _ + * @since 2.3.0 + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { + * 'constructor': Circle + * }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties) { + var result = baseCreate(prototype); + return properties == null ? result : baseAssign(result, properties); + } + + /** + * Assigns own and inherited enumerable string keyed properties of source + * objects to the destination object for all destination properties that + * resolve to `undefined`. Source objects are applied from left to right. + * Once a property is set, additional values of the same property are ignored. + * + * **Note:** This method mutates `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaultsDeep + * @example + * + * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var defaults = baseRest(function(object, sources) { + object = Object(object); + + var index = -1; + var length = sources.length; + var guard = length > 2 ? sources[2] : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + length = 1; + } + + while (++index < length) { + var source = sources[index]; + var props = keysIn(source); + var propsIndex = -1; + var propsLength = props.length; + + while (++propsIndex < propsLength) { + var key = props[propsIndex]; + var value = object[key]; + + if (value === undefined || + (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) { + object[key] = source[key]; + } + } + } + + return object; + }); + + /** + * This method is like `_.defaults` except that it recursively assigns + * default properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaults + * @example + * + * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); + * // => { 'a': { 'b': 2, 'c': 3 } } + */ + var defaultsDeep = baseRest(function(args) { + args.push(undefined, customDefaultsMerge); + return apply(mergeWith, undefined, args); + }); + + /** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(o) { return o.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // The `_.matches` iteratee shorthand. + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findKey(users, 'active'); + * // => 'barney' + */ + function findKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); + } + + /** + * This method is like `_.findKey` except that it iterates over elements of + * a collection in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findLastKey(users, function(o) { return o.age < 40; }); + * // => returns 'pebbles' assuming `_.findKey` returns 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.findLastKey(users, { 'age': 36, 'active': true }); + * // => 'barney' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findLastKey(users, 'active'); + * // => 'pebbles' + */ + function findLastKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); + } + + /** + * Iterates over own and inherited enumerable string keyed properties of an + * object and invokes `iteratee` for each property. The iteratee is invoked + * with three arguments: (value, key, object). Iteratee functions may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forInRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forIn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). + */ + function forIn(object, iteratee) { + return object == null + ? object + : baseFor(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * This method is like `_.forIn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forIn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forInRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. + */ + function forInRight(object, iteratee) { + return object == null + ? object + : baseForRight(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * Iterates over own enumerable string keyed properties of an object and + * invokes `iteratee` for each property. The iteratee is invoked with three + * arguments: (value, key, object). Iteratee functions may exit iteration + * early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwnRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forOwn(object, iteratee) { + return object && baseForOwn(object, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forOwn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwnRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. + */ + function forOwnRight(object, iteratee) { + return object && baseForOwnRight(object, getIteratee(iteratee, 3)); + } + + /** + * Creates an array of function property names from own enumerable properties + * of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functionsIn + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functions(new Foo); + * // => ['a', 'b'] + */ + function functions(object) { + return object == null ? [] : baseFunctions(object, keys(object)); + } + + /** + * Creates an array of function property names from own and inherited + * enumerable properties of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functions + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functionsIn(new Foo); + * // => ['a', 'b', 'c'] + */ + function functionsIn(object) { + return object == null ? [] : baseFunctions(object, keysIn(object)); + } + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ + function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; + } + + /** + * Checks if `path` is a direct property of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = { 'a': { 'b': 2 } }; + * var other = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.has(object, 'a'); + * // => true + * + * _.has(object, 'a.b'); + * // => true + * + * _.has(object, ['a', 'b']); + * // => true + * + * _.has(other, 'a'); + * // => false + */ + function has(object, path) { + return object != null && hasPath(object, path, baseHas); + } + + /** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ + function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); + } + + /** + * Creates an object composed of the inverted keys and values of `object`. + * If `object` contains duplicate values, subsequent values overwrite + * property assignments of previous values. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Object + * @param {Object} object The object to invert. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invert(object); + * // => { '1': 'c', '2': 'b' } + */ + var invert = createInverter(function(result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + result[value] = key; + }, constant(identity)); + + /** + * This method is like `_.invert` except that the inverted object is generated + * from the results of running each element of `object` thru `iteratee`. The + * corresponding inverted value of each inverted key is an array of keys + * responsible for generating the inverted value. The iteratee is invoked + * with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Object + * @param {Object} object The object to invert. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invertBy(object); + * // => { '1': ['a', 'c'], '2': ['b'] } + * + * _.invertBy(object, function(value) { + * return 'group' + value; + * }); + * // => { 'group1': ['a', 'c'], 'group2': ['b'] } + */ + var invertBy = createInverter(function(result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + }, getIteratee); + + /** + * Invokes the method at `path` of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {...*} [args] The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + * @example + * + * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; + * + * _.invoke(object, 'a[0].b.c.slice', 1, 3); + * // => [2, 3] + */ + var invoke = baseRest(baseInvoke); + + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); + } + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); + } + + /** + * The opposite of `_.mapValues`; this method creates an object with the + * same values as `object` and keys generated by running each own enumerable + * string keyed property of `object` thru `iteratee`. The iteratee is invoked + * with three arguments: (value, key, object). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapValues + * @example + * + * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { + * return key + value; + * }); + * // => { 'a1': 1, 'b2': 2 } + */ + function mapKeys(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, iteratee(value, key, object), value); + }); + return result; + } + + /** + * Creates an object with the same keys as `object` and values generated + * by running each own enumerable string keyed property of `object` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, key, object). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapKeys + * @example + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * _.mapValues(users, function(o) { return o.age; }); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + * + * // The `_.property` iteratee shorthand. + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ + function mapValues(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, key, iteratee(value, key, object)); + }); + return result; + } + + /** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ + var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); + }); + + /** + * This method is like `_.merge` except that it accepts `customizer` which + * is invoked to produce the merged values of the destination and source + * properties. If `customizer` returns `undefined`, merging is handled by the + * method instead. The `customizer` is invoked with six arguments: + * (objValue, srcValue, key, object, source, stack). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * function customizer(objValue, srcValue) { + * if (_.isArray(objValue)) { + * return objValue.concat(srcValue); + * } + * } + * + * var object = { 'a': [1], 'b': [2] }; + * var other = { 'a': [3], 'b': [4] }; + * + * _.mergeWith(object, other, customizer); + * // => { 'a': [1, 3], 'b': [2, 4] } + */ + var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { + baseMerge(object, source, srcIndex, customizer); + }); + + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable property paths of `object` that are not omitted. + * + * **Note:** This method is considerably slower than `_.pick`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to omit. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omit(object, ['a', 'c']); + * // => { 'b': '2' } + */ + var omit = flatRest(function(object, paths) { + var result = {}; + if (object == null) { + return result; + } + var isDeep = false; + paths = arrayMap(paths, function(path) { + path = castPath(path, object); + isDeep || (isDeep = path.length > 1); + return path; + }); + copyObject(object, getAllKeysIn(object), result); + if (isDeep) { + result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); + } + var length = paths.length; + while (length--) { + baseUnset(result, paths[length]); + } + return result; + }); + + /** + * The opposite of `_.pickBy`; this method creates an object composed of + * the own and inherited enumerable string keyed properties of `object` that + * `predicate` doesn't return truthy for. The predicate is invoked with two + * arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ + function omitBy(object, predicate) { + return pickBy(object, negate(getIteratee(predicate))); + } + + /** + * Creates an object composed of the picked `object` properties. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pick(object, ['a', 'c']); + * // => { 'a': 1, 'c': 3 } + */ + var pick = flatRest(function(object, paths) { + return object == null ? {} : basePick(object, paths); + }); + + /** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with two arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ + function pickBy(object, predicate) { + if (object == null) { + return {}; + } + var props = arrayMap(getAllKeysIn(object), function(prop) { + return [prop]; + }); + predicate = getIteratee(predicate); + return basePickBy(object, props, function(value, path) { + return predicate(value, path[0]); + }); + } + + /** + * This method is like `_.get` except that if the resolved value is a + * function it's invoked with the `this` binding of its parent object and + * its result is returned. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to resolve. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; + * + * _.result(object, 'a[0].b.c1'); + * // => 3 + * + * _.result(object, 'a[0].b.c2'); + * // => 4 + * + * _.result(object, 'a[0].b.c3', 'default'); + * // => 'default' + * + * _.result(object, 'a[0].b.c3', _.constant('default')); + * // => 'default' + */ + function result(object, path, defaultValue) { + path = castPath(path, object); + + var index = -1, + length = path.length; + + // Ensure the loop is entered when path is empty. + if (!length) { + length = 1; + object = undefined; + } + while (++index < length) { + var value = object == null ? undefined : object[toKey(path[index])]; + if (value === undefined) { + index = length; + value = defaultValue; + } + object = isFunction(value) ? value.call(object) : value; + } + return object; + } + + /** + * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, + * it's created. Arrays are created for missing index properties while objects + * are created for all other missing properties. Use `_.setWith` to customize + * `path` creation. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.set(object, 'a[0].b.c', 4); + * console.log(object.a[0].b.c); + * // => 4 + * + * _.set(object, ['x', '0', 'y', 'z'], 5); + * console.log(object.x[0].y.z); + * // => 5 + */ + function set(object, path, value) { + return object == null ? object : baseSet(object, path, value); + } + + /** + * This method is like `_.set` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.setWith(object, '[0][1]', 'a', Object); + * // => { '0': { '1': 'a' } } + */ + function setWith(object, path, value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseSet(object, path, value, customizer); + } + + /** + * Creates an array of own enumerable string keyed-value pairs for `object` + * which can be consumed by `_.fromPairs`. If `object` is a map or set, its + * entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entries + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairs(new Foo); + * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) + */ + var toPairs = createToPairs(keys); + + /** + * Creates an array of own and inherited enumerable string keyed-value pairs + * for `object` which can be consumed by `_.fromPairs`. If `object` is a map + * or set, its entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entriesIn + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairsIn(new Foo); + * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) + */ + var toPairsIn = createToPairs(keysIn); + + /** + * An alternative to `_.reduce`; this method transforms `object` to a new + * `accumulator` object which is the result of running each of its own + * enumerable string keyed properties thru `iteratee`, with each invocation + * potentially mutating the `accumulator` object. If `accumulator` is not + * provided, a new object with the same `[[Prototype]]` will be used. The + * iteratee is invoked with four arguments: (accumulator, value, key, object). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The custom accumulator value. + * @returns {*} Returns the accumulated value. + * @example + * + * _.transform([2, 3, 4], function(result, n) { + * result.push(n *= n); + * return n % 2 == 0; + * }, []); + * // => [4, 9] + * + * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } + */ + function transform(object, iteratee, accumulator) { + var isArr = isArray(object), + isArrLike = isArr || isBuffer(object) || isTypedArray(object); + + iteratee = getIteratee(iteratee, 4); + if (accumulator == null) { + var Ctor = object && object.constructor; + if (isArrLike) { + accumulator = isArr ? new Ctor : []; + } + else if (isObject(object)) { + accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; + } + else { + accumulator = {}; + } + } + (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { + return iteratee(accumulator, value, index, object); + }); + return accumulator; + } + + /** + * Removes the property at `path` of `object`. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 7 } }] }; + * _.unset(object, 'a[0].b.c'); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + * + * _.unset(object, ['a', '0', 'b', 'c']); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + */ + function unset(object, path) { + return object == null ? true : baseUnset(object, path); + } + + /** + * This method is like `_.set` except that accepts `updater` to produce the + * value to set. Use `_.updateWith` to customize `path` creation. The `updater` + * is invoked with one argument: (value). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.update(object, 'a[0].b.c', function(n) { return n * n; }); + * console.log(object.a[0].b.c); + * // => 9 + * + * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); + * console.log(object.x[0].y.z); + * // => 0 + */ + function update(object, path, updater) { + return object == null ? object : baseUpdate(object, path, castFunction(updater)); + } + + /** + * This method is like `_.update` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.updateWith(object, '[0][1]', _.constant('a'), Object); + * // => { '0': { '1': 'a' } } + */ + function updateWith(object, path, updater, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); + } + + /** + * Creates an array of the own enumerable string keyed property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ + function values(object) { + return object == null ? [] : baseValues(object, keys(object)); + } + + /** + * Creates an array of the own and inherited enumerable string keyed property + * values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.valuesIn(new Foo); + * // => [1, 2, 3] (iteration order is not guaranteed) + */ + function valuesIn(object) { + return object == null ? [] : baseValues(object, keysIn(object)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Clamps `number` within the inclusive `lower` and `upper` bounds. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Number + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + * @example + * + * _.clamp(-10, -5, 5); + * // => -5 + * + * _.clamp(10, -5, 5); + * // => 5 + */ + function clamp(number, lower, upper) { + if (upper === undefined) { + upper = lower; + lower = undefined; + } + if (upper !== undefined) { + upper = toNumber(upper); + upper = upper === upper ? upper : 0; + } + if (lower !== undefined) { + lower = toNumber(lower); + lower = lower === lower ? lower : 0; + } + return baseClamp(toNumber(number), lower, upper); + } + + /** + * Checks if `n` is between `start` and up to, but not including, `end`. If + * `end` is not specified, it's set to `start` with `start` then set to `0`. + * If `start` is greater than `end` the params are swapped to support + * negative ranges. + * + * @static + * @memberOf _ + * @since 3.3.0 + * @category Number + * @param {number} number The number to check. + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + * @see _.range, _.rangeRight + * @example + * + * _.inRange(3, 2, 4); + * // => true + * + * _.inRange(4, 8); + * // => true + * + * _.inRange(4, 2); + * // => false + * + * _.inRange(2, 2); + * // => false + * + * _.inRange(1.2, 2); + * // => true + * + * _.inRange(5.2, 4); + * // => false + * + * _.inRange(-3, -2, -6); + * // => true + */ + function inRange(number, start, end) { + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + number = toNumber(number); + return baseInRange(number, start, end); + } + + /** + * Produces a random number between the inclusive `lower` and `upper` bounds. + * If only one argument is provided a number between `0` and the given number + * is returned. If `floating` is `true`, or either `lower` or `upper` are + * floats, a floating-point number is returned instead of an integer. + * + * **Note:** JavaScript follows the IEEE-754 standard for resolving + * floating-point values which can produce unexpected results. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Number + * @param {number} [lower=0] The lower bound. + * @param {number} [upper=1] The upper bound. + * @param {boolean} [floating] Specify returning a floating-point number. + * @returns {number} Returns the random number. + * @example + * + * _.random(0, 5); + * // => an integer between 0 and 5 + * + * _.random(5); + * // => also an integer between 0 and 5 + * + * _.random(5, true); + * // => a floating-point number between 0 and 5 + * + * _.random(1.2, 5.2); + * // => a floating-point number between 1.2 and 5.2 + */ + function random(lower, upper, floating) { + if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { + upper = floating = undefined; + } + if (floating === undefined) { + if (typeof upper == 'boolean') { + floating = upper; + upper = undefined; + } + else if (typeof lower == 'boolean') { + floating = lower; + lower = undefined; + } + } + if (lower === undefined && upper === undefined) { + lower = 0; + upper = 1; + } + else { + lower = toFinite(lower); + if (upper === undefined) { + upper = lower; + lower = 0; + } else { + upper = toFinite(upper); + } + } + if (lower > upper) { + var temp = lower; + lower = upper; + upper = temp; + } + if (floating || lower % 1 || upper % 1) { + var rand = nativeRandom(); + return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); + } + return baseRandom(lower, upper); + } + + /*------------------------------------------------------------------------*/ + + /** + * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the camel cased string. + * @example + * + * _.camelCase('Foo Bar'); + * // => 'fooBar' + * + * _.camelCase('--foo-bar--'); + * // => 'fooBar' + * + * _.camelCase('__FOO_BAR__'); + * // => 'fooBar' + */ + var camelCase = createCompounder(function(result, word, index) { + word = word.toLowerCase(); + return result + (index ? capitalize(word) : word); + }); + + /** + * Converts the first character of `string` to upper case and the remaining + * to lower case. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * _.capitalize('FRED'); + * // => 'Fred' + */ + function capitalize(string) { + return upperFirst(toString(string).toLowerCase()); + } + + /** + * Deburrs `string` by converting + * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) + * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) + * letters to basic Latin letters and removing + * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to deburr. + * @returns {string} Returns the deburred string. + * @example + * + * _.deburr('déjà vu'); + * // => 'deja vu' + */ + function deburr(string) { + string = toString(string); + return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); + } + + /** + * Checks if `string` ends with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=string.length] The position to search up to. + * @returns {boolean} Returns `true` if `string` ends with `target`, + * else `false`. + * @example + * + * _.endsWith('abc', 'c'); + * // => true + * + * _.endsWith('abc', 'b'); + * // => false + * + * _.endsWith('abc', 'b', 2); + * // => true + */ + function endsWith(string, target, position) { + string = toString(string); + target = baseToString(target); + + var length = string.length; + position = position === undefined + ? length + : baseClamp(toInteger(position), 0, length); + + var end = position; + position -= target.length; + return position >= 0 && string.slice(position, end) == target; + } + + /** + * Converts the characters "&", "<", ">", '"', and "'" in `string` to their + * corresponding HTML entities. + * + * **Note:** No other characters are escaped. To escape additional + * characters use a third-party library like [_he_](https://mths.be/he). + * + * Though the ">" character is escaped for symmetry, characters like + * ">" and "/" don't need escaping in HTML and have no special meaning + * unless they're part of a tag or unquoted attribute value. See + * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) + * (under "semi-related fun fact") for more details. + * + * When working with HTML you should always + * [quote attribute values](http://wonko.com/post/html-escaping) to reduce + * XSS vectors. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escape('fred, barney, & pebbles'); + * // => 'fred, barney, & pebbles' + */ + function escape(string) { + string = toString(string); + return (string && reHasUnescapedHtml.test(string)) + ? string.replace(reUnescapedHtml, escapeHtmlChar) + : string; + } + + /** + * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", + * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https://lodash\.com/\)' + */ + function escapeRegExp(string) { + string = toString(string); + return (string && reHasRegExpChar.test(string)) + ? string.replace(reRegExpChar, '\\$&') + : string; + } + + /** + * Converts `string` to + * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the kebab cased string. + * @example + * + * _.kebabCase('Foo Bar'); + * // => 'foo-bar' + * + * _.kebabCase('fooBar'); + * // => 'foo-bar' + * + * _.kebabCase('__FOO_BAR__'); + * // => 'foo-bar' + */ + var kebabCase = createCompounder(function(result, word, index) { + return result + (index ? '-' : '') + word.toLowerCase(); + }); + + /** + * Converts `string`, as space separated words, to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the lower cased string. + * @example + * + * _.lowerCase('--Foo-Bar--'); + * // => 'foo bar' + * + * _.lowerCase('fooBar'); + * // => 'foo bar' + * + * _.lowerCase('__FOO_BAR__'); + * // => 'foo bar' + */ + var lowerCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + word.toLowerCase(); + }); + + /** + * Converts the first character of `string` to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.lowerFirst('Fred'); + * // => 'fred' + * + * _.lowerFirst('FRED'); + * // => 'fRED' + */ + var lowerFirst = createCaseFirst('toLowerCase'); + + /** + * Pads `string` on the left and right sides if it's shorter than `length`. + * Padding characters are truncated if they can't be evenly divided by `length`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.pad('abc', 8); + * // => ' abc ' + * + * _.pad('abc', 8, '_-'); + * // => '_-abc_-_' + * + * _.pad('abc', 3); + * // => 'abc' + */ + function pad(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + if (!length || strLength >= length) { + return string; + } + var mid = (length - strLength) / 2; + return ( + createPadding(nativeFloor(mid), chars) + + string + + createPadding(nativeCeil(mid), chars) + ); + } + + /** + * Pads `string` on the right side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padEnd('abc', 6); + * // => 'abc ' + * + * _.padEnd('abc', 6, '_-'); + * // => 'abc_-_' + * + * _.padEnd('abc', 3); + * // => 'abc' + */ + function padEnd(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (string + createPadding(length - strLength, chars)) + : string; + } + + /** + * Pads `string` on the left side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padStart('abc', 6); + * // => ' abc' + * + * _.padStart('abc', 6, '_-'); + * // => '_-_abc' + * + * _.padStart('abc', 3); + * // => 'abc' + */ + function padStart(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (createPadding(length - strLength, chars) + string) + : string; + } + + /** + * Converts `string` to an integer of the specified radix. If `radix` is + * `undefined` or `0`, a `radix` of `10` is used unless `value` is a + * hexadecimal, in which case a `radix` of `16` is used. + * + * **Note:** This method aligns with the + * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category String + * @param {string} string The string to convert. + * @param {number} [radix=10] The radix to interpret `value` by. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {number} Returns the converted integer. + * @example + * + * _.parseInt('08'); + * // => 8 + * + * _.map(['6', '08', '10'], _.parseInt); + * // => [6, 8, 10] + */ + function parseInt(string, radix, guard) { + if (guard || radix == null) { + radix = 0; + } else if (radix) { + radix = +radix; + } + return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0); + } + + /** + * Repeats the given string `n` times. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to repeat. + * @param {number} [n=1] The number of times to repeat the string. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {string} Returns the repeated string. + * @example + * + * _.repeat('*', 3); + * // => '***' + * + * _.repeat('abc', 2); + * // => 'abcabc' + * + * _.repeat('abc', 0); + * // => '' + */ + function repeat(string, n, guard) { + if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + return baseRepeat(toString(string), n); + } + + /** + * Replaces matches for `pattern` in `string` with `replacement`. + * + * **Note:** This method is based on + * [`String#replace`](https://mdn.io/String/replace). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to modify. + * @param {RegExp|string} pattern The pattern to replace. + * @param {Function|string} replacement The match replacement. + * @returns {string} Returns the modified string. + * @example + * + * _.replace('Hi Fred', 'Fred', 'Barney'); + * // => 'Hi Barney' + */ + function replace() { + var args = arguments, + string = toString(args[0]); + + return args.length < 3 ? string : string.replace(args[1], args[2]); + } + + /** + * Converts `string` to + * [snake case](https://en.wikipedia.org/wiki/Snake_case). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the snake cased string. + * @example + * + * _.snakeCase('Foo Bar'); + * // => 'foo_bar' + * + * _.snakeCase('fooBar'); + * // => 'foo_bar' + * + * _.snakeCase('--FOO-BAR--'); + * // => 'foo_bar' + */ + var snakeCase = createCompounder(function(result, word, index) { + return result + (index ? '_' : '') + word.toLowerCase(); + }); + + /** + * Splits `string` by `separator`. + * + * **Note:** This method is based on + * [`String#split`](https://mdn.io/String/split). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to split. + * @param {RegExp|string} separator The separator pattern to split by. + * @param {number} [limit] The length to truncate results to. + * @returns {Array} Returns the string segments. + * @example + * + * _.split('a-b-c', '-', 2); + * // => ['a', 'b'] + */ + function split(string, separator, limit) { + if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { + separator = limit = undefined; + } + limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; + if (!limit) { + return []; + } + string = toString(string); + if (string && ( + typeof separator == 'string' || + (separator != null && !isRegExp(separator)) + )) { + separator = baseToString(separator); + if (!separator && hasUnicode(string)) { + return castSlice(stringToArray(string), 0, limit); + } + } + return string.split(separator, limit); + } + + /** + * Converts `string` to + * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). + * + * @static + * @memberOf _ + * @since 3.1.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the start cased string. + * @example + * + * _.startCase('--foo-bar--'); + * // => 'Foo Bar' + * + * _.startCase('fooBar'); + * // => 'Foo Bar' + * + * _.startCase('__FOO_BAR__'); + * // => 'FOO BAR' + */ + var startCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + upperFirst(word); + }); + + /** + * Checks if `string` starts with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=0] The position to search from. + * @returns {boolean} Returns `true` if `string` starts with `target`, + * else `false`. + * @example + * + * _.startsWith('abc', 'a'); + * // => true + * + * _.startsWith('abc', 'b'); + * // => false + * + * _.startsWith('abc', 'b', 1); + * // => true + */ + function startsWith(string, target, position) { + string = toString(string); + position = position == null + ? 0 + : baseClamp(toInteger(position), 0, string.length); + + target = baseToString(target); + return string.slice(position, position + target.length) == target; + } + + /** + * Creates a compiled template function that can interpolate data properties + * in "interpolate" delimiters, HTML-escape interpolated data properties in + * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data + * properties may be accessed as free variables in the template. If a setting + * object is given, it takes precedence over `_.templateSettings` values. + * + * **Note:** In the development build `_.template` utilizes + * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) + * for easier debugging. + * + * For more information on precompiling templates see + * [lodash's custom builds documentation](https://lodash.com/custom-builds). + * + * For more information on Chrome extension sandboxes see + * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The template string. + * @param {Object} [options={}] The options object. + * @param {RegExp} [options.escape=_.templateSettings.escape] + * The HTML "escape" delimiter. + * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] + * The "evaluate" delimiter. + * @param {Object} [options.imports=_.templateSettings.imports] + * An object to import into the template as free variables. + * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] + * The "interpolate" delimiter. + * @param {string} [options.sourceURL='lodash.templateSources[n]'] + * The sourceURL of the compiled template. + * @param {string} [options.variable='obj'] + * The data object variable name. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the compiled template function. + * @example + * + * // Use the "interpolate" delimiter to create a compiled template. + * var compiled = _.template('hello <%= user %>!'); + * compiled({ 'user': 'fred' }); + * // => 'hello fred!' + * + * // Use the HTML "escape" delimiter to escape data property values. + * var compiled = _.template('<%- value %>'); + * compiled({ 'value': ' + + + + +
+ +
+ + + +
+
+

+
+

+ + + + +

+
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/runcode/web/nui.html b/resources/[cfx-default]/[system]/runcode/web/nui.html new file mode 100644 index 0000000..6f65d71 --- /dev/null +++ b/resources/[cfx-default]/[system]/runcode/web/nui.html @@ -0,0 +1,60 @@ + + +runcode nui + + + +
+ +
+ + \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/sessionmanager-rdr3/.gitignore b/resources/[cfx-default]/[system]/sessionmanager-rdr3/.gitignore new file mode 100644 index 0000000..5699291 --- /dev/null +++ b/resources/[cfx-default]/[system]/sessionmanager-rdr3/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +.yarn.installed \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/sessionmanager-rdr3/fxmanifest.lua b/resources/[cfx-default]/[system]/sessionmanager-rdr3/fxmanifest.lua new file mode 100644 index 0000000..5e44544 --- /dev/null +++ b/resources/[cfx-default]/[system]/sessionmanager-rdr3/fxmanifest.lua @@ -0,0 +1,17 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'Handles Social Club conductor session API for RedM. Do not disable.' +repository 'https://github.com/citizenfx/cfx-server-data' + +fx_version 'adamant' +game 'rdr3' +rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.' + +dependencies { + 'yarn' +} + +server_script 'sm_server.js' diff --git a/resources/[cfx-default]/[system]/sessionmanager-rdr3/package.json b/resources/[cfx-default]/[system]/sessionmanager-rdr3/package.json new file mode 100644 index 0000000..e00b6dc --- /dev/null +++ b/resources/[cfx-default]/[system]/sessionmanager-rdr3/package.json @@ -0,0 +1,6 @@ +{ + "private": true, + "dependencies": { + "@citizenfx/protobufjs": "6.8.8" + } +} \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/sessionmanager-rdr3/rline.proto b/resources/[cfx-default]/[system]/sessionmanager-rdr3/rline.proto new file mode 100644 index 0000000..9084181 --- /dev/null +++ b/resources/[cfx-default]/[system]/sessionmanager-rdr3/rline.proto @@ -0,0 +1,192 @@ +syntax = "proto3"; +package rline; + +message RpcErrorData { + string ErrorCodeString = 1; + int32 ErrorCode = 2; + string DomainString = 3; + int32 DomainCode = 4; + bytes DataEx = 5; +}; + +message RpcError { + int32 ErrorCode = 1; + string ErrorMessage = 2; + RpcErrorData Data = 3; +}; + +message RpcHeader { + string RequestId = 1; + string MethodName = 2; + RpcError Error = 3; + string srcTid = 4; +}; + +message RpcMessage { + RpcHeader Header = 1; + bytes Content = 2; +}; + +message RpcResponseContainer { + bytes Content = 1; +}; + +message RpcResponseMessage { + RpcHeader Header = 1; + RpcResponseContainer Container = 2; +}; + +message TokenStuff { + string tkn = 1; +}; + +message InitSessionResponse { + bytes sesid = 1; + TokenStuff token = 2; +}; + +message MpGamerHandleDto { + string gh = 1; +}; + +message MpPeerAddressDto { + string addr = 1; +}; + +message InitPlayer2_Parameters { + MpGamerHandleDto gh = 1; + MpPeerAddressDto peerAddress = 2; + int32 discriminator = 3; + int32 seamlessType = 4; + uint32 connectionReason = 5; +}; + +message InitPlayerResult { + uint32 code = 1; +}; + +message Restriction { + int32 u1 = 1; + int32 u2 = 2; + int32 u3 = 3; +} + +message GetRestrictionsData { + repeated Restriction restriction = 1; + repeated string unk2 = 2; +}; + +message GetRestrictionsResult { + GetRestrictionsData data = 1; +}; + +message PlayerIdSto { + int32 acctId = 1; + int32 platId = 2; +}; + +message MpSessionRequestIdDto { + PlayerIdSto requestor = 1; + int32 index = 2; + int32 hash = 3; +}; + +message QueueForSession_Seamless_Parameters { + MpSessionRequestIdDto requestId = 1; + uint32 optionFlags = 2; + int32 x = 3; + int32 y = 4; +}; + +message QueueForSessionResult { + uint32 code = 1; +}; + +message QueueEntered_Parameters { + uint32 queueGroup = 1; + MpSessionRequestIdDto requestId = 2; + uint32 optionFlags = 3; +}; + +message GuidDto { + fixed64 a = 1; + fixed64 b = 2; +}; + +message MpTransitionIdDto { + GuidDto value = 1; +}; + +message MpSessionIdDto { + GuidDto value = 1; +}; + +message SessionSubcommandEnterSession { + int32 index = 1; + int32 hindex = 2; + uint32 sessionFlags = 3; + uint32 mode = 4; + int32 size = 5; + int32 teamIndex = 6; + MpTransitionIdDto transitionId = 7; + uint32 sessionManagerType = 8; + int32 slotCount = 9; +}; + +message SessionSubcommandLeaveSession { + uint32 reason = 1; +}; + +message SessionSubcommandAddPlayer { + PlayerIdSto id = 1; + MpGamerHandleDto gh = 2; + MpPeerAddressDto addr = 3; + int32 index = 4; +}; + +message SessionSubcommandRemovePlayer { + PlayerIdSto id = 1; +}; + +message SessionSubcommandHostChanged { + int32 index = 1; +}; + +message SessionCommand { + uint32 cmd = 1; + string cmdname = 2; + SessionSubcommandEnterSession EnterSession = 3; + SessionSubcommandLeaveSession LeaveSession = 4; + SessionSubcommandAddPlayer AddPlayer = 5; + SessionSubcommandRemovePlayer RemovePlayer = 6; + SessionSubcommandHostChanged HostChanged = 7; +}; + +message scmds_Parameters { + MpSessionIdDto sid = 1; + int32 ncmds = 2; + repeated SessionCommand cmds = 3; +}; + +message UriType { + string url = 1; +}; + +message TransitionReady_PlayerQueue_Parameters { + UriType serverUri = 1; + uint32 serverSandbox = 2; + MpTransitionIdDto id = 3; + uint32 sessionType = 4; + MpSessionRequestIdDto requestId = 5; + MpSessionIdDto transferId = 6; +}; + +message TransitionToSession_Parameters { + MpTransitionIdDto id = 1; + float x = 2; + float y = 3; +}; + +message TransitionToSessionResult { + uint32 code = 1; +}; \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/sessionmanager-rdr3/sm_server.js b/resources/[cfx-default]/[system]/sessionmanager-rdr3/sm_server.js new file mode 100644 index 0000000..2c70324 --- /dev/null +++ b/resources/[cfx-default]/[system]/sessionmanager-rdr3/sm_server.js @@ -0,0 +1,328 @@ +const protobuf = require("@citizenfx/protobufjs"); + +const playerDatas = {}; +let slotsUsed = 0; + +function assignSlotId() { + for (let i = 0; i < 32; i++) { + if (!(slotsUsed & (1 << i))) { + slotsUsed |= (1 << i); + return i; + } + } + + return -1; +} + +let hostIndex = -1; +const isOneSync = GetConvar("onesync", "off") !== "off"; + +protobuf.load(GetResourcePath(GetCurrentResourceName()) + "/rline.proto", function(err, root) { + if (err) { + console.log(err); + return; + } + + const RpcMessage = root.lookupType("rline.RpcMessage"); + const RpcResponseMessage = root.lookupType("rline.RpcResponseMessage"); + const InitSessionResponse = root.lookupType("rline.InitSessionResponse"); + const InitPlayer2_Parameters = root.lookupType("rline.InitPlayer2_Parameters"); + const InitPlayerResult = root.lookupType("rline.InitPlayerResult"); + const GetRestrictionsResult = root.lookupType("rline.GetRestrictionsResult"); + const QueueForSession_Seamless_Parameters = root.lookupType("rline.QueueForSession_Seamless_Parameters"); + const QueueForSessionResult = root.lookupType("rline.QueueForSessionResult"); + const QueueEntered_Parameters = root.lookupType("rline.QueueEntered_Parameters"); + const TransitionReady_PlayerQueue_Parameters = root.lookupType("rline.TransitionReady_PlayerQueue_Parameters"); + const TransitionToSession_Parameters = root.lookupType("rline.TransitionToSession_Parameters"); + const TransitionToSessionResult = root.lookupType("rline.TransitionToSessionResult"); + const scmds_Parameters = root.lookupType("rline.scmds_Parameters"); + + function toArrayBuffer(buf) { + var ab = new ArrayBuffer(buf.length); + var view = new Uint8Array(ab); + for (var i = 0; i < buf.length; ++i) { + view[i] = buf[i]; + } + return ab; + } + + function emitMsg(target, data) { + emitNet('__cfx_internal:pbRlScSession', target, toArrayBuffer(data)); + } + + function emitSessionCmds(target, cmd, cmdname, msg) { + const stuff = {}; + stuff[cmdname] = msg; + + emitMsg(target, RpcMessage.encode({ + Header: { + MethodName: 'scmds' + }, + Content: scmds_Parameters.encode({ + sid: { + value: { + a: 2, + b: 2 + } + }, + ncmds: 1, + cmds: [ + { + cmd, + cmdname, + ...stuff + } + ] + }).finish() + }).finish()); + } + + function emitAddPlayer(target, msg) { + emitSessionCmds(target, 2, 'AddPlayer', msg); + } + + function emitRemovePlayer(target, msg) { + emitSessionCmds(target, 3, 'RemovePlayer', msg); + } + + function emitHostChanged(target, msg) { + emitSessionCmds(target, 5, 'HostChanged', msg); + } + + onNet('playerDropped', () => { + if (isOneSync) { + return; + } + + try { + const oData = playerDatas[source]; + delete playerDatas[source]; + + if (oData && hostIndex === oData.slot) { + const pda = Object.entries(playerDatas); + + if (pda.length > 0) { + hostIndex = pda[0][1].slot | 0; // TODO: actually use <=31 slot index *and* check for id + + for (const [ id, data ] of Object.entries(playerDatas)) { + emitHostChanged(id, { + index: hostIndex + }); + } + } else { + hostIndex = -1; + } + } + + if (!oData) { + return; + } + + if (oData.slot > -1) { + slotsUsed &= ~(1 << oData.slot); + } + + for (const [ id, data ] of Object.entries(playerDatas)) { + emitRemovePlayer(id, { + id: oData.id + }); + } + } catch (e) { + console.log(e); + console.log(e.stack); + } + }); + + function makeResponse(type, data) { + return { + Header: { + }, + Container: { + Content: type.encode(data).finish() + } + }; + } + + const handlers = { + async InitSession(source, data) { + return makeResponse(InitSessionResponse, { + sesid: Buffer.alloc(16), + /*token: { + tkn: 'ACSTOKEN token="meow",signature="meow"' + }*/ + }); + }, + + async InitPlayer2(source, data) { + const req = InitPlayer2_Parameters.decode(data); + + if (!isOneSync) { + playerDatas[source] = { + gh: req.gh, + peerAddress: req.peerAddress, + discriminator: req.discriminator, + slot: -1 + }; + } + + return makeResponse(InitPlayerResult, { + code: 0 + }); + }, + + async GetRestrictions(source, data) { + return makeResponse(GetRestrictionsResult, { + data: { + + } + }); + }, + + async ConfirmSessionEntered(source, data) { + return {}; + }, + + async TransitionToSession(source, data) { + const req = TransitionToSession_Parameters.decode(data); + + return makeResponse(TransitionToSessionResult, { + code: 1 // in this message, 1 is success + }); + }, + + async QueueForSession_Seamless(source, data) { + const req = QueueForSession_Seamless_Parameters.decode(data); + + if (!isOneSync) { + playerDatas[source].req = req.requestId; + playerDatas[source].id = req.requestId.requestor; + playerDatas[source].slot = assignSlotId(); + } + + setTimeout(() => { + emitMsg(source, RpcMessage.encode({ + Header: { + MethodName: 'QueueEntered' + }, + Content: QueueEntered_Parameters.encode({ + queueGroup: 69, + requestId: req.requestId, + optionFlags: req.optionFlags + }).finish() + }).finish()); + + if (isOneSync) { + hostIndex = 16 + } else if (hostIndex === -1) { + hostIndex = playerDatas[source].slot | 0; + } + + emitMsg(source, RpcMessage.encode({ + Header: { + MethodName: 'TransitionReady_PlayerQueue' + }, + Content: TransitionReady_PlayerQueue_Parameters.encode({ + serverUri: { + url: '' + }, + requestId: req.requestId, + id: { + value: { + a: 2, + b: 0 + } + }, + serverSandbox: 0xD656C677, + sessionType: 3, + transferId: { + value: { + a: 2, + b: 2 + } + }, + }).finish() + }).finish()); + + setTimeout(() => { + emitSessionCmds(source, 0, 'EnterSession', { + index: (isOneSync) ? 16 : playerDatas[source].slot | 0, + hindex: hostIndex, + sessionFlags: 0, + mode: 0, + size: (isOneSync) ? 0 : Object.entries(playerDatas).filter(a => a[1].id).length, + //size: 2, + //size: Object.entries(playerDatas).length, + teamIndex: 0, + transitionId: { + value: { + a: 2, + b: 0 + } + }, + sessionManagerType: 0, + slotCount: 32 + }); + }, 50); + + if (!isOneSync) { + setTimeout(() => { + // tell player about everyone, and everyone about player + const meData = playerDatas[source]; + + const aboutMe = { + id: meData.id, + gh: meData.gh, + addr: meData.peerAddress, + index: playerDatas[source].slot | 0 + }; + + for (const [ id, data ] of Object.entries(playerDatas)) { + if (id == source || !data.id) continue; + + emitAddPlayer(source, { + id: data.id, + gh: data.gh, + addr: data.peerAddress, + index: data.slot | 0 + }); + + emitAddPlayer(id, aboutMe); + } + }, 150); + } + }, 250); + + return makeResponse(QueueForSessionResult, { + code: 1 + }); + }, + }; + + async function handleMessage(source, method, data) { + if (handlers[method]) { + return await handlers[method](source, data); + } + + return {}; + } + + onNet('__cfx_internal:pbRlScSession', async (data) => { + const s = source; + + try { + const message = RpcMessage.decode(new Uint8Array(data)); + const response = await handleMessage(s, message.Header.MethodName, message.Content); + + if (!response || !response.Header) { + return; + } + + response.Header.RequestId = message.Header.RequestId; + + emitMsg(s, RpcResponseMessage.encode(response).finish()); + } catch (e) { + console.log(e); + console.log(e.stack); + } + }); +}); \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/sessionmanager/client/empty.lua b/resources/[cfx-default]/[system]/sessionmanager/client/empty.lua new file mode 100644 index 0000000..00825ac --- /dev/null +++ b/resources/[cfx-default]/[system]/sessionmanager/client/empty.lua @@ -0,0 +1,3 @@ +--This empty file causes the scheduler.lua to load clientside +--scheduler.lua when loaded inside the sessionmanager resource currently manages remote callbacks. +--Without this, callbacks will only work server->client and not client->server. \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/sessionmanager/fxmanifest.lua b/resources/[cfx-default]/[system]/sessionmanager/fxmanifest.lua new file mode 100644 index 0000000..83ddebd --- /dev/null +++ b/resources/[cfx-default]/[system]/sessionmanager/fxmanifest.lua @@ -0,0 +1,13 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'Handles the "host lock" for non-OneSync servers. Do not disable.' +repository 'https://github.com/citizenfx/cfx-server-data' + +fx_version 'cerulean' +games { 'gta4', 'gta5' } + +server_script 'server/host_lock.lua' +client_script 'client/empty.lua' \ No newline at end of file diff --git a/resources/[cfx-default]/[system]/sessionmanager/server/host_lock.lua b/resources/[cfx-default]/[system]/sessionmanager/server/host_lock.lua new file mode 100644 index 0000000..5121404 --- /dev/null +++ b/resources/[cfx-default]/[system]/sessionmanager/server/host_lock.lua @@ -0,0 +1,69 @@ +-- whitelist c2s events +RegisterServerEvent('hostingSession') +RegisterServerEvent('hostedSession') + +-- event handler for pre-session 'acquire' +local currentHosting +local hostReleaseCallbacks = {} + +-- TODO: add a timeout for the hosting lock to be held +-- TODO: add checks for 'fraudulent' conflict cases of hosting attempts (typically whenever the host can not be reached) +AddEventHandler('hostingSession', function() + -- if the lock is currently held, tell the client to await further instruction + if currentHosting then + TriggerClientEvent('sessionHostResult', source, 'wait') + + -- register a callback for when the lock is freed + table.insert(hostReleaseCallbacks, function() + TriggerClientEvent('sessionHostResult', source, 'free') + end) + + return + end + + -- if the current host was last contacted less than a second ago + if GetHostId() then + if GetPlayerLastMsg(GetHostId()) < 1000 then + TriggerClientEvent('sessionHostResult', source, 'conflict') + + return + end + end + + hostReleaseCallbacks = {} + + currentHosting = source + + TriggerClientEvent('sessionHostResult', source, 'go') + + -- set a timeout of 5 seconds + SetTimeout(5000, function() + if not currentHosting then + return + end + + currentHosting = nil + + for _, cb in ipairs(hostReleaseCallbacks) do + cb() + end + end) +end) + +AddEventHandler('hostedSession', function() + -- check if the client is the original locker + if currentHosting ~= source then + -- TODO: drop client as they're clearly lying + print(currentHosting, '~=', source) + return + end + + -- free the host lock (call callbacks and remove the lock value) + for _, cb in ipairs(hostReleaseCallbacks) do + cb() + end + + currentHosting = nil +end) + +EnableEnhancedHostSupport(true) \ No newline at end of file diff --git a/resources/[cfx-default]/[test]/example-loadscreen/bankgothic.ttf b/resources/[cfx-default]/[test]/example-loadscreen/bankgothic.ttf new file mode 100644 index 0000000..f3d8049 Binary files /dev/null and b/resources/[cfx-default]/[test]/example-loadscreen/bankgothic.ttf differ diff --git a/resources/[cfx-default]/[test]/example-loadscreen/fxmanifest.lua b/resources/[cfx-default]/[test]/example-loadscreen/fxmanifest.lua new file mode 100644 index 0000000..8b1d115 --- /dev/null +++ b/resources/[cfx-default]/[test]/example-loadscreen/fxmanifest.lua @@ -0,0 +1,19 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'Example loading screen.' +repository 'https://github.com/citizenfx/cfx-server-data' + +files { + 'index.html', + 'keks.css', + 'bankgothic.ttf', + 'loadscreen.jpg' +} + +loadscreen 'index.html' + +fx_version 'bodacious' +game 'gta5' \ No newline at end of file diff --git a/resources/[cfx-default]/[test]/example-loadscreen/index.html b/resources/[cfx-default]/[test]/example-loadscreen/index.html new file mode 100644 index 0000000..c3f8446 --- /dev/null +++ b/resources/[cfx-default]/[test]/example-loadscreen/index.html @@ -0,0 +1,77 @@ + + + + + +
+
+

Free Mode

+

Not Algonquin

+
+ +
+

Intel

+

+
+

The Statue of Happiness has no heart. You do.

+
+
+
+
+
+
+ + + + diff --git a/resources/[cfx-default]/[test]/example-loadscreen/keks.css b/resources/[cfx-default]/[test]/example-loadscreen/keks.css new file mode 100644 index 0000000..0026bc9 --- /dev/null +++ b/resources/[cfx-default]/[test]/example-loadscreen/keks.css @@ -0,0 +1,151 @@ +body +{ + margin: 0px; + padding: 0px; +} + +.backdrop +{ + position: relative; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + + background-image: url(loadscreen.jpg); + background-size: 100% 100%; +} + +.bottom +{ + position: absolute; + bottom: 0px; + width: 100%; + height: 100%; +} + +#gradient +{ + position: absolute; + bottom: 0px; + width: 100%; + + height: 25%; + + background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%); +} + +@font-face { + font-family: 'BankGothic'; + src: url('bankgothic.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +h1, h2 { + position: relative; + background: transparent; + z-index: 0; +} +/* add a single stroke */ +h1:before, h2:before { + content: attr(title); + position: absolute; + -webkit-text-stroke: 0.1em #000; + left: 0; + z-index: -1; +} + + +.letni +{ + position: absolute; + left: 5%; + right: 5%; + bottom: 10%; + + z-index: 5; + + color: #fff; + + font-family: "Segoe UI"; +} + +.letni p +{ + font-size: 22px; + + margin-left: 3px; + + margin-top: 0px; +} + +.letni h2, .letni h3 +{ + font-family: BankGothic; + + text-transform: uppercase; + + font-size: 50px; + + margin: 0px; + + display: inline-block; +} + +.top +{ + color: #fff; + + position: absolute; + top: 7%; + left: 5%; + right: 5%; +} + +.top h1 +{ + font-family: BankGothic; + font-size: 60px; + + margin: 0px; +} + +.top h2 +{ + font-family: BankGothic; + font-size: 40px; + + margin: 0px; + + color: #ddd; +} + +.loadbar +{ + width: 100%; + background-color: rgba(140, 140, 140, .9); + height: 20px; + + margin-left: 2px; + margin-right: 3px; + + margin-top: 5px; + margin-bottom: 5px; + + overflow: hidden; + + position: relative; + + display: block; +} + +.thingy +{ + width: 10%; + background-color: #eee; + height: 20px; + + position: absolute; + left: 10%; +} \ No newline at end of file diff --git a/resources/[cfx-default]/[test]/example-loadscreen/loadscreen.jpg b/resources/[cfx-default]/[test]/example-loadscreen/loadscreen.jpg new file mode 100644 index 0000000..a87caee Binary files /dev/null and b/resources/[cfx-default]/[test]/example-loadscreen/loadscreen.jpg differ diff --git a/resources/[cfx-default]/[test]/fivem/fxmanifest.lua b/resources/[cfx-default]/[test]/fivem/fxmanifest.lua new file mode 100644 index 0000000..74201da --- /dev/null +++ b/resources/[cfx-default]/[test]/fivem/fxmanifest.lua @@ -0,0 +1,13 @@ +-- This resource is part of the default Cfx.re asset pack (cfx-server-data) +-- Altering or recreating for local use only is strongly discouraged. + +version '1.0.0' +author 'Cfx.re ' +description 'A compatibility resource to load basic-gamemode.' +repository 'https://github.com/citizenfx/cfx-server-data' + +-- compatibility wrapper +fx_version 'adamant' +game 'common' + +dependency 'basic-gamemode' diff --git a/resources/[core]/cron/LICENSE b/resources/[core]/cron/LICENSE new file mode 100644 index 0000000..9ef14b9 --- /dev/null +++ b/resources/[core]/cron/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + cron + Copyright (C) 2015-2024 Jérémie N'gadi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + cron Copyright (C) 2015-2024 Jérémie N'gadi + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[core]/cron/README.md b/resources/[core]/cron/README.md new file mode 100644 index 0000000..1147f88 --- /dev/null +++ b/resources/[core]/cron/README.md @@ -0,0 +1,37 @@ +

[ESX] Cron

Discord - Website - Documentation + +A simple, but vital, resource that allows resources to Run tasks at specific intervals. + +# Example Usage + +```lua + +-- Execute task 5:10, every day +function CronTask(d, h, m) + print('Task done') +end + +TriggerEvent('cron:runAt', 5, 10, CronTask) + +-- Execute task every monday at 18:30 +function CronTask(d, h, m) + if d == 1 then + print('Task done') + end +end + +TriggerEvent('cron:runAt', 18, 30, CronTask) + +``` + +# Legal + +cron - run tasks at specific intervals! + +Copyright (C) 2015-2024 Jérémie N'gadi + +This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version. + +This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details. + +You should have received a copy Of the GNU General Public License along with this program. If Not, see http://www.gnu.org/licenses/. diff --git a/resources/[core]/cron/fxmanifest.lua b/resources/[core]/cron/fxmanifest.lua new file mode 100644 index 0000000..57b05a2 --- /dev/null +++ b/resources/[core]/cron/fxmanifest.lua @@ -0,0 +1,9 @@ +fx_version 'adamant' + +game 'gta5' +author 'ESX-Framework' +description 'Allows resources to Run tasks at specific intervals.' +lua54 'yes' +version '1.13.5' + +server_script 'server/main.lua' diff --git a/resources/[core]/cron/server/main.lua b/resources/[core]/cron/server/main.lua new file mode 100644 index 0000000..51da085 --- /dev/null +++ b/resources/[core]/cron/server/main.lua @@ -0,0 +1,75 @@ +---@class CronJob +---@field h number +---@field m number +---@field cb function|table + +---@type CronJob[] +local cronJobs = {} +---@type number|false +local lastTimestamp = false + +---@param h number +---@param m number +---@param cb function|table +function RunAt(h, m, cb) + cronJobs[#cronJobs + 1] = { + h = h, + m = m, + cb = cb, + } +end + +---@return number +function GetUnixTimestamp() + return os.time() +end + +---@param timestamp number +function OnTime(timestamp) + for i = 1, #cronJobs, 1 do + local scheduledTimestamp = os.time({ + hour = cronJobs[i].h, + min = cronJobs[i].m, + sec = 0, -- Assuming tasks run at the start of the minute + day = os.date("%d", timestamp), + month = os.date("%m", timestamp), + year = os.date("%Y", timestamp), + }) + + if timestamp >= scheduledTimestamp and (not lastTimestamp or lastTimestamp < scheduledTimestamp) then + local d = os.date('*t', scheduledTimestamp).wday + cronJobs[i].cb(d, cronJobs[i].h, cronJobs[i].m) + end + end +end + +---@return nil +function Tick() + local timestamp = GetUnixTimestamp() + + if not lastTimestamp or os.date("%M", timestamp) ~= os.date("%M", lastTimestamp) then + OnTime(timestamp) + lastTimestamp = timestamp + end + + SetTimeout(60000, Tick) +end + +lastTimestamp = GetUnixTimestamp() +Tick() + +---@param h number +---@param m number +---@param cb function|table +AddEventHandler("cron:runAt", function(h, m, cb) + local invokingResource = GetInvokingResource() or "Unknown" + local typeH = type(h) + local typeM = type(m) + local typeCb = type(cb) + + assert(typeH == "number", ("Expected number for h, got %s. Invoking Resource: '%s'"):format(typeH, invokingResource)) + assert(typeM == "number", ("Expected number for m, got %s. Invoking Resource: '%s'"):format(typeM, invokingResource)) + assert(typeCb == "function" or (typeCb == "table" and type(getmetatable(cb)?.__call) == "function"), ("Expected function for cb, got %s. Invoking Resource: '%s'"):format(typeCb, invokingResource)) + + RunAt(h, m, cb) +end) diff --git a/resources/[core]/es_extended/LICENSE b/resources/[core]/es_extended/LICENSE new file mode 100644 index 0000000..5f5e070 --- /dev/null +++ b/resources/[core]/es_extended/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + es_extended + Copyright (C) 2015-2024 Jérémie N'gadi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + es_extended Copyright (C) 2015-2024 Jérémie N'gadi + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[core]/es_extended/README.md b/resources/[core]/es_extended/README.md new file mode 100644 index 0000000..99c6d06 --- /dev/null +++ b/resources/[core]/es_extended/README.md @@ -0,0 +1,13 @@ +

es_extended

Discord - Documentation + +## Legal + +es_extended + +Copyright (C) 2015-2024 Jérémie N'gadi + +This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version. + +This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details. + +You should have received a copy Of the GNU General Public License along with this program. If Not, see . diff --git a/resources/[core]/es_extended/client/functions.lua b/resources/[core]/es_extended/client/functions.lua new file mode 100644 index 0000000..b665f34 --- /dev/null +++ b/resources/[core]/es_extended/client/functions.lua @@ -0,0 +1,1367 @@ +---@return boolean +---@diagnostic disable-next-line: duplicate-set-field +function ESX.IsPlayerLoaded() + return ESX.PlayerLoaded +end + +---@return table +function ESX.GetPlayerData() + return ESX.PlayerData +end + +---@param name string +---@param func function +---@return nil +function ESX.SecureNetEvent(name, func) + local invoker = GetInvokingResource() + local invokingResource = invoker and invoker ~= 'unknown' and invoker or 'es_extended' + if not invokingResource then + return + end + + if not Core.Events[invokingResource] then + Core.Events[invokingResource] = {} + end + + local event = RegisterNetEvent(name, function(...) + if source == '' then + return + end + + local success, result = pcall(func, ...) + if not success then + error(("%s"):format(result)) + end + end) + local eventIndex = #Core.Events[invokingResource] + 1 + Core.Events[invokingResource][eventIndex] = event +end + +local addonResourcesState = { + ['esx_progressbar'] = GetResourceState('esx_progressbar') ~= 'missing', + ['esx_notify'] = GetResourceState('esx_notify') ~= 'missing', + ['esx_textui'] = GetResourceState('esx_textui') ~= 'missing', + ['esx_context'] = GetResourceState('esx_context') ~= 'missing', +} + +local function IsResourceFound(resource) + return addonResourcesState[resource] or error(('Resource [^5%s^1] is Missing!'):format(resource)) +end + +function ESX.DisableSpawnManager() + if GetResourceState("spawnmanager") == "started" then + exports.spawnmanager:setAutoSpawn(false) + end +end + +---@param items string | table The item(s) to search for +---@param count? boolean Whether to return the count of the item as well +---@return table | number +function ESX.SearchInventory(items, count) + local item + if type(items) == 'string' then + item, items = items, {items} + end + + local data = {} + for i = 1, #ESX.PlayerData.inventory do + local e = ESX.PlayerData.inventory[i] + for ii = 1, #items do + if e.name == items[ii] then + data[table.remove(items, ii)] = count and e.count or e + break + end + end + if #items == 0 then + break + end + end + + return not item and data or data[item] +end + +---@param key string Table key to set +---@param val any Value to set +---@return nil +function ESX.SetPlayerData(key, val) + local current = ESX.PlayerData[key] + ESX.PlayerData[key] = val + if key ~= "loadout" then + if type(val) == "table" or val ~= current then + TriggerEvent("esx:setPlayerData", key, val, current) + end + end +end + +---@param freeze boolean Whether to freeze the player +---@return nil +function Core.FreezePlayer(freeze) + local ped = PlayerPedId() + SetPlayerControl(ESX.playerId, not freeze, 0) + + if freeze then + SetEntityCollision(ped, false, false) + FreezeEntityPosition(ped, true) + else + SetEntityCollision(ped, true, true) + FreezeEntityPosition(ped, false) + end +end + +---@param skin table Skin data to set +---@param coords table Coords to spawn the player at +---@param cb function Callback function +---@return nil +function ESX.SpawnPlayer(skin, coords, cb) + local p = promise.new() + TriggerEvent("skinchanger:loadSkin", skin, function() + p:resolve() + end) + Citizen.Await(p) + + RequestCollisionAtCoord(coords.x, coords.y, coords.z) + + local playerPed = PlayerPedId() + local timer = GetGameTimer() + + Core.FreezePlayer(true) + SetEntityCoordsNoOffset(playerPed, coords.x, coords.y, coords.z, false, false, true) + SetEntityHeading(playerPed, coords.heading) + + RequestCollisionAtCoord(coords.x, coords.y, coords.z) + while not HasCollisionLoadedAroundEntity(playerPed) and (GetGameTimer() - timer) < 5000 do + Wait(0) + end + + NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, coords.heading, 0, true) + TriggerEvent('playerSpawned', coords) + cb() +end + +---@param message string +---@param length? number Timeout in milliseconds +---@param options? ProgressBarOptions +---@return boolean Success Whether the progress bar was successfully created or not +function ESX.Progressbar(message, length, options) + return IsResourceFound('esx_progressbar') and exports['esx_progressbar']:Progressbar(message, length, options) +end + +function ESX.CancelProgressbar() + return IsResourceFound('esx_progressbar') and exports['esx_progressbar']:CancelProgressbar() +end + +---@param message string The message to show +---@param notifyType? string The type of notification to show +---@param length? number The length of the notification +---@param title? string The title of the notification +---@param position? string The position of the notification +---@return nil +function ESX.ShowNotification(message, notifyType, length, title, position) + return IsResourceFound('esx_notify') and exports['esx_notify']:Notify(notifyType or "info", length or 5000, message, title, position) +end + +function ESX.TextUI(...) + return IsResourceFound('esx_textui') and exports['esx_textui']:TextUI(...) +end + +---@return nil +function ESX.HideUI() + return IsResourceFound('esx_textui') and exports['esx_textui']:HideUI() +end + +---@param sender string +---@param subject string +---@param msg string +---@param textureDict string +---@param iconType integer +---@param flash boolean +---@param saveToBrief? boolean +---@param hudColorIndex? integer +---@return nil +function ESX.ShowAdvancedNotification(sender, subject, msg, textureDict, iconType, flash, saveToBrief, hudColorIndex) + AddTextEntry("esxAdvancedNotification", msg) + BeginTextCommandThefeedPost("esxAdvancedNotification") + if hudColorIndex then + ThefeedSetNextPostBackgroundColor(hudColorIndex) + end + EndTextCommandThefeedPostMessagetext(textureDict, textureDict, false, iconType, sender, subject) + EndTextCommandThefeedPostTicker(flash, saveToBrief == nil or saveToBrief) +end + +---@param msg string The message to show +---@param thisFrame? boolean Whether to show the message this frame +---@param beep? boolean Whether to beep +---@param duration? number The duration of the message +---@return nil +function ESX.ShowHelpNotification(msg, thisFrame, beep, duration) + AddTextEntry("esxHelpNotification", msg) + if thisFrame then + DisplayHelpTextThisFrame("esxHelpNotification", false) + else + BeginTextCommandDisplayHelp("esxHelpNotification") + EndTextCommandDisplayHelp(0, false, beep == nil or beep, duration or -1) + end +end + +---@param msg string The message to show +---@param coords table The coords to show the message at +---@return nil +function ESX.ShowFloatingHelpNotification(msg, coords) + AddTextEntry("esxFloatingHelpNotification", msg) + SetFloatingHelpTextWorldPosition(1, coords.x, coords.y, coords.z) + SetFloatingHelpTextStyle(1, 1, 2, -1, 3, 0) + BeginTextCommandDisplayHelp("esxFloatingHelpNotification") + EndTextCommandDisplayHelp(2, false, false, -1) +end + +---@param msg string The message to show +---@param time number The duration of the message +---@return nil +function ESX.DrawMissionText(msg, time) + ClearPrints() + BeginTextCommandPrint('STRING') + AddTextComponentSubstringPlayerName(msg) + EndTextCommandPrint(time, true) +end + +---@param str string The string to hash +---@return string The hashed string +function ESX.HashString(str) + return ('~INPUT_%s~'):format(('%x'):format(joaat(str) & 0x7fffffff + 2 ^ 31):upper()) +end + +function ESX.OpenContext(...) + return IsResourceFound('esx_context') and exports['esx_context']:Open(...) +end + +function ESX.PreviewContext(...) + return IsResourceFound('esx_context') and exports['esx_context']:Preview(...) +end + +function ESX.CloseContext(...) + return IsResourceFound('esx_context') and exports['esx_context']:Close(...) +end + +function ESX.RefreshContext(...) + return IsResourceFound('esx_context') and exports['esx_context']:Refresh(...) +end + +---@param command_name string The command name +---@param label string The label to show +---@param input_group string The input group +---@param key string The key to bind +---@param on_press function The function to call on press +---@param on_release? function The function to call on release +function ESX.RegisterInput(command_name, label, input_group, key, on_press, on_release) + local command = on_release and '+' .. command_name or command_name + RegisterCommand(command, on_press, false) + Core.Input[command_name] = ESX.HashString(command) + if on_release then + RegisterCommand('-' .. command_name, on_release, false) + end + RegisterKeyMapping(command, label or '', input_group or 'keyboard', key or '') +end + +---@param menuType string +---@param open function The function to call on open +---@param close function The function to call on close +function ESX.UI.Menu.RegisterType(menuType, open, close) + ESX.UI.Menu.RegisteredTypes[menuType] = { + open = open, + close = close, + } +end + +---@class ESXMenu +---@field type string +---@field namespace string +---@field resourceName string +---@field name string +---@field data table +---@field submit? function +---@field cancel? function +---@field change? function +---@field close function +---@field update function +---@field refresh function +---@field setElement function +---@field setElements function +---@field setTitle function +---@field removeElement function + +---@param menuType string +---@param namespace string +---@param name string +---@param data table +---@param submit? function +---@param cancel? function +---@param change? function +---@param close? function +---@return ESXMenu +function ESX.UI.Menu.Open(menuType, namespace, name, data, submit, cancel, change, close) + ---@class ESXMenu + local menu = {} + + menu.type = menuType + menu.namespace = namespace + menu.resourceName = (GetInvokingResource() or "Unknown") + menu.name = name + menu.data = data + menu.submit = submit + menu.cancel = cancel + menu.change = change + + menu.close = function() + ESX.UI.Menu.RegisteredTypes[menuType].close(namespace, name) + + for i = 1, #ESX.UI.Menu.Opened, 1 do + if ESX.UI.Menu.Opened[i] then + if ESX.UI.Menu.Opened[i].type == menuType and ESX.UI.Menu.Opened[i].namespace == namespace and ESX.UI.Menu.Opened[i].name == name then + ESX.UI.Menu.Opened[i] = nil + end + end + end + + if close then + close() + end + end + + menu.update = function(query, newData) + for i = 1, #menu.data.elements, 1 do + local match = true + + for k, v in pairs(query) do + if menu.data.elements[i][k] ~= v then + match = false + end + end + + if match then + for k, v in pairs(newData) do + menu.data.elements[i][k] = v + end + end + end + end + + menu.refresh = function() + ESX.UI.Menu.RegisteredTypes[menuType].open(namespace, name, menu.data) + end + + menu.setElement = function(i, key, val) + menu.data.elements[i][key] = val + end + + menu.setElements = function(newElements) + menu.data.elements = newElements + end + + menu.setTitle = function(val) + menu.data.title = val + end + + menu.removeElement = function(query) + for i = 1, #menu.data.elements, 1 do + for k, v in pairs(query) do + if menu.data.elements[i] then + if menu.data.elements[i][k] == v then + table.remove(menu.data.elements, i) + break + end + end + end + end + end + + ESX.UI.Menu.Opened[#ESX.UI.Menu.Opened + 1] = menu + ESX.UI.Menu.RegisteredTypes[menuType].open(namespace, name, data) + + return menu +end + +---@param menuType string +---@param namespace string +---@param name string +---@param cancel? boolean Should the close be classified as a cancel +---@return nil +function ESX.UI.Menu.Close(menuType, namespace, name, cancel) + for i = 1, #ESX.UI.Menu.Opened, 1 do + if ESX.UI.Menu.Opened[i] then + if ESX.UI.Menu.Opened[i].type == menuType and ESX.UI.Menu.Opened[i].namespace == namespace and ESX.UI.Menu.Opened[i].name == name then + if not cancel then + ESX.UI.Menu.Opened[i].close() + else + local menu = ESX.UI.Menu.Opened[i] + ESX.UI.Menu.RegisteredTypes[menu.type].close(menu.namespace, menu.name) + + if type(menu.cancel) ~= "nil" then + menu.cancel(menu.data, menu) + end + end + ESX.UI.Menu.Opened[i] = nil + end + end + end +end + +---@param cancel? boolean Should the close be classified as a cancel +---@return nil +function ESX.UI.Menu.CloseAll(cancel) + for i = 1, #ESX.UI.Menu.Opened, 1 do + if ESX.UI.Menu.Opened[i] then + if not cancel then + ESX.UI.Menu.Opened[i].close() + else + local menu = ESX.UI.Menu.Opened[i] + ESX.UI.Menu.RegisteredTypes[menu.type].close(menu.namespace, menu.name) + + if type(menu.cancel) ~= "nil" then + menu.cancel(menu.data, menu) + end + end + ESX.UI.Menu.Opened[i] = nil + end + end +end + +---@param menuType string +---@param namespace string +---@param name string +---@return ESXMenu | nil +function ESX.UI.Menu.GetOpened(menuType, namespace, name) + for i = 1, #ESX.UI.Menu.Opened, 1 do + if ESX.UI.Menu.Opened[i] then + if ESX.UI.Menu.Opened[i].type == menuType and ESX.UI.Menu.Opened[i].namespace == namespace and ESX.UI.Menu.Opened[i].name == name then + return ESX.UI.Menu.Opened[i] + end + end + end +end + +---@return ESXMenu[] +function ESX.UI.Menu.GetOpenedMenus() + return ESX.UI.Menu.Opened +end + +ESX.UI.Menu.IsOpen = ESX.UI.Menu.GetOpened + +---@param add boolean Whether the item is being added or removed +---@param item string The item to show +---@param count number How many of the item to show +---@return nil +function ESX.UI.ShowInventoryItemNotification(add, item, count) + SendNUIMessage({ + action = "inventoryNotification", + add = add, + item = item, + count = count, + }) +end + +---@param ped integer The ped to get the mugshot of +---@param transparent? boolean Whether the mugshot should be transparent +function ESX.Game.GetPedMugshot(ped, transparent) + if not DoesEntityExist(ped) then + return + end + local mugshot = transparent and RegisterPedheadshotTransparent(ped) or RegisterPedheadshot(ped) + + while not IsPedheadshotReady(mugshot) do + Wait(0) + end + + return mugshot, GetPedheadshotTxdString(mugshot) +end + +---@param entity integer The entity to get the coords of +---@param coords table | vector3 | vector4 The coords to teleport the entity to +---@param cb? function The callback function +function ESX.Game.Teleport(entity, coords, cb) + + if DoesEntityExist(entity) then + RequestCollisionAtCoord(coords.x, coords.y, coords.z) + while not HasCollisionLoadedAroundEntity(entity) do + Wait(0) + end + + SetEntityCoords(entity, coords.x, coords.y, coords.z, false, false, false, false) + SetEntityHeading(entity, coords.w or coords.heading or 0.0) + end + + if cb then + cb() + end +end + +---@param object integer | string The object to spawn +---@param coords table | vector3 The coords to spawn the object at +---@param cb? function The callback function +---@param networked? boolean Whether the object should be networked +---@return integer | nil +function ESX.Game.SpawnObject(object, coords, cb, networked) + local model = type(object) == "number" and object or joaat(object) + + ESX.Streaming.RequestModel(model) + + local obj = CreateObject(model, coords.x, coords.y, coords.z, networked == nil or networked, false, true) + return cb and cb(obj) or obj +end + +---@param object integer | string The object to spawn +---@param coords table | vector3 The coords to spawn the object at +---@param cb? function The callback function +---@return nil +function ESX.Game.SpawnLocalObject(object, coords, cb) + ESX.Game.SpawnObject(object, coords, cb, false) +end + +---@param vehicle integer The vehicle to delete +---@return nil +function ESX.Game.DeleteVehicle(vehicle) + SetEntityAsMissionEntity(vehicle, true, true) + DeleteVehicle(vehicle) +end + +---@param object integer The object to delete +---@return nil +function ESX.Game.DeleteObject(object) + SetEntityAsMissionEntity(object, false, true) + DeleteObject(object) +end + +---@param vehicleModel integer | string The vehicle to spawn +---@param coords table | vector3 The coords to spawn the vehicle at +---@param heading number The heading of the vehicle +---@param cb? fun(vehicle: number) The callback function +---@param networked? boolean Whether the vehicle should be networked +---@return number? vehicle +function ESX.Game.SpawnVehicle(vehicleModel, coords, heading, cb, networked) + if cb and not ESX.IsFunctionReference(cb) then + error("Invalid callback function") + end + + local model = type(vehicleModel) == "number" and vehicleModel or joaat(vehicleModel) + local vector = type(coords) == "vector3" and coords or vec(coords.x, coords.y, coords.z) + local isNetworked = networked == nil or networked + + local playerCoords = GetEntityCoords(ESX.PlayerData.ped) + if not vector or not playerCoords then + return + end + + local dist = #(playerCoords - vector) + if dist > 424 then -- Onesync infinity Range (https://docs.fivem.net/docs/scripting-reference/onesync/) + local executingResource = GetInvokingResource() or "Unknown" + return error(("Resource ^5%s^1 Tried to spawn vehicle on the client but the position is too far away (Out of onesync range)."):format(executingResource)) + end + + local promise = not cb and promise.new() + CreateThread(function() + local modelHash = ESX.Streaming.RequestModel(model) + if not modelHash then + if promise then + promise:reject(("Tried to spawn invalid vehicle - ^5%s^7!"):format(model)) + return + end + error(("Tried to spawn invalid vehicle - ^5%s^7!"):format(model)) + end + + local vehicle = CreateVehicle(model, vector.x, vector.y, vector.z, heading, isNetworked, true) + + if networked then + local id = NetworkGetNetworkIdFromEntity(vehicle) + SetNetworkIdCanMigrate(id, true) + SetEntityAsMissionEntity(vehicle, true, true) + end + SetVehicleHasBeenOwnedByPlayer(vehicle, true) + SetVehicleNeedsToBeHotwired(vehicle, false) + SetModelAsNoLongerNeeded(model) + SetVehRadioStation(vehicle, "OFF") + + RequestCollisionAtCoord(vector.x, vector.y, vector.z) + while not HasCollisionLoadedAroundEntity(vehicle) do + Wait(0) + end + + if promise then + promise:resolve(vehicle) + elseif cb then + cb(vehicle) + end + end) + + if promise then + return Citizen.Await(promise) + end +end + +---@param vehicle integer The vehicle to spawn +---@param coords table | vector3 The coords to spawn the vehicle at +---@param heading number The heading of the vehicle +---@param cb? function The callback function +---@return nil +function ESX.Game.SpawnLocalVehicle(vehicle, coords, heading, cb) + ESX.Game.SpawnVehicle(vehicle, coords, heading, cb, false) +end + +---@param vehicle integer The vehicle to check +---@return boolean +function ESX.Game.IsVehicleEmpty(vehicle) + return GetVehicleNumberOfPassengers(vehicle) == 0 and IsVehicleSeatFree(vehicle, -1) +end + +---@return table +function ESX.Game.GetObjects() -- Leave the function for compatibility + return GetGamePool("CObject") +end + +---@param onlyOtherPeds? boolean Whether to exlude the player ped +---@return table +function ESX.Game.GetPeds(onlyOtherPeds) + local pool = GetGamePool("CPed") + + if onlyOtherPeds then + local myPed = ESX.PlayerData.ped + for i = 1, #pool do + if pool[i] == myPed then + table.remove(pool, i) + break + end + end + end + + return pool +end + +---@return table +function ESX.Game.GetVehicles() -- Leave the function for compatibility + return GetGamePool("CVehicle") +end + +---@param onlyOtherPlayers? boolean Whether to exclude the player +---@param returnKeyValue? boolean Whether to return the key value pair +---@param returnPeds? boolean Whether to return the peds +---@return table +function ESX.Game.GetPlayers(onlyOtherPlayers, returnKeyValue, returnPeds) + local players = {} + local active = GetActivePlayers() + + for i = 1, #active do + local currentPlayer = active[i] + local ped = GetPlayerPed(currentPlayer) + + if DoesEntityExist(ped) and ((onlyOtherPlayers and currentPlayer ~= ESX.playerId) or not onlyOtherPlayers) then + if returnKeyValue then + players[currentPlayer] = ped + else + players[#players + 1] = returnPeds and ped or currentPlayer + end + end + end + + return players +end + +---@param coords? table | vector3 The coords to get the closest object to +---@param modelFilter? table The model filter +---@return integer, integer +function ESX.Game.GetClosestObject(coords, modelFilter) + return ESX.Game.GetClosestEntity(ESX.Game.GetObjects(), false, coords, modelFilter) +end + +---@param coords? table | vector3 The coords to get the closest ped to +---@param modelFilter? table The model filter +---@return integer, integer +function ESX.Game.GetClosestPed(coords, modelFilter) + return ESX.Game.GetClosestEntity(ESX.Game.GetPeds(true), false, coords, modelFilter) +end + +---@param coords? table | vector3 The coords to get the closest player to +---@return integer, integer +function ESX.Game.GetClosestPlayer(coords) + return ESX.Game.GetClosestEntity(ESX.Game.GetPlayers(true, true), true, coords, nil) +end + +---@param coords? table | vector3 The coords to get the closest vehicle to +---@param modelFilter? table The model filter +---@return integer, integer +function ESX.Game.GetClosestVehicle(coords, modelFilter) + return ESX.Game.GetClosestEntity(ESX.Game.GetVehicles(), false, coords, modelFilter) +end + +---@param entities table The entities to search through +---@param isPlayerEntities boolean Whether the entities are players +---@param coords table | vector3 The coords to search from +---@param maxDistance number The max distance to search within +---@return table +local function EnumerateEntitiesWithinDistance(entities, isPlayerEntities, coords, maxDistance) + local nearbyEntities = {} + + if coords then + coords = vector3(coords.x, coords.y, coords.z) + else + local playerPed = ESX.PlayerData.ped + coords = GetEntityCoords(playerPed) + end + + for k, entity in pairs(entities) do + local distance = #(coords - GetEntityCoords(entity)) + + if distance <= maxDistance then + nearbyEntities[#nearbyEntities + 1] = isPlayerEntities and k or entity + end + end + + return nearbyEntities +end + +---@param coords table | vector3 The coords to search from +---@param maxDistance number The max distance to search within +---@return table +function ESX.Game.GetPlayersInArea(coords, maxDistance) + return EnumerateEntitiesWithinDistance(ESX.Game.GetPlayers(true, true), true, coords, maxDistance) +end + +---@param coords table | vector3 The coords to search from +---@param maxDistance number The max distance to search within +---@return table +function ESX.Game.GetVehiclesInArea(coords, maxDistance) + return EnumerateEntitiesWithinDistance(ESX.Game.GetVehicles(), false, coords, maxDistance) +end + +---@param coords table | vector3 The coords to search from +---@param maxDistance number The max distance to search within +---@return boolean +function ESX.Game.IsSpawnPointClear(coords, maxDistance) + return #ESX.Game.GetVehiclesInArea(coords, maxDistance) == 0 +end + +---@param shape integer The shape to get the test result from +---@return boolean, table, table, integer, integer +function ESX.Game.GetShapeTestResultSync(shape) + local handle, hit, coords, normal, material, entity + repeat + handle, hit, coords, normal, material, entity = GetShapeTestResultIncludingMaterial(shape) + Wait(0) + until handle ~= 1 + return hit, coords, normal, material, entity +end + +---@param depth number The depth to raycast +---@vararg any The arguments to pass to the shape test +---@return table, boolean, table, table, integer, integer +function ESX.Game.RaycastScreen(depth, ...) + local world, normal = GetWorldCoordFromScreenCoord(.5, .5) + local origin = world + normal + local target = world + normal * depth + return target, ESX.Game.GetShapeTestResultSync(StartShapeTestLosProbe(origin.x, origin.y, origin.z, target.x, target.y, target.z, ...)) +end + +---@param entities table The entities to search through +---@param isPlayerEntities boolean Whether the entities are players +---@param coords? table | vector3 The coords to search from +---@param modelFilter? table The model filter +---@return integer, integer +function ESX.Game.GetClosestEntity(entities, isPlayerEntities, coords, modelFilter) + local closestEntity, closestEntityDistance, filteredEntities = -1, -1, nil + + if coords then + coords = vector3(coords.x, coords.y, coords.z) + else + local playerPed = ESX.PlayerData.ped + coords = GetEntityCoords(playerPed) + end + + if modelFilter then + filteredEntities = {} + + for currentEntityIndex = 1, #entities do + if modelFilter[GetEntityModel(entities[currentEntityIndex])] then + filteredEntities[#filteredEntities + 1] = entities[currentEntityIndex] + end + end + end + + for k, entity in pairs(filteredEntities or entities) do + local distance = #(coords - GetEntityCoords(entity)) + + if closestEntityDistance == -1 or distance < closestEntityDistance then + closestEntity, closestEntityDistance = isPlayerEntities and k or entity, distance + end + end + + return closestEntity, closestEntityDistance +end + +---@return integer | nil, vector3 | nil +function ESX.Game.GetVehicleInDirection() + local _, hit, coords, _, _, entity = ESX.Game.RaycastScreen(5, 10, ESX.PlayerData.ped) + if hit and IsEntityAVehicle(entity) then + return entity, coords + end +end + +---@param vehicle integer The vehicle to get the properties of +---@return table | nil +function ESX.Game.GetVehicleProperties(vehicle) + if not DoesEntityExist(vehicle) then + return + end + + ---@type number | number[], number | number[] + local colorPrimary, colorSecondary = GetVehicleColours(vehicle) + local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) + local dashboardColor = GetVehicleDashboardColor(vehicle) + local interiorColor = GetVehicleInteriorColour(vehicle) + + if GetIsVehiclePrimaryColourCustom(vehicle) then + colorPrimary = { GetVehicleCustomPrimaryColour(vehicle) } + end + + if GetIsVehicleSecondaryColourCustom(vehicle) then + colorSecondary = { GetVehicleCustomSecondaryColour(vehicle) } + end + + local hasCustomXenonColor, customXenonColorR, customXenonColorG, customXenonColorB = GetVehicleXenonLightsCustomColor(vehicle) + local customXenonColor = nil + if hasCustomXenonColor then + customXenonColor = { customXenonColorR, customXenonColorG, customXenonColorB } + end + + local extras = {} + for extraId = 0, 20 do + if DoesExtraExist(vehicle, extraId) then + extras[tostring(extraId)] = IsVehicleExtraTurnedOn(vehicle, extraId) + end + end + + local doorsBroken, windowsBroken, tyreBurst = {}, {}, {} + local numWheels = tostring(GetVehicleNumberOfWheels(vehicle)) + + local TyresIndex = { -- Wheel index list according to the number of vehicle wheels. + ["2"] = { 0, 4 }, -- Bike and cycle. + ["3"] = { 0, 1, 4, 5 }, -- Vehicle with 3 wheels (get for wheels because some 3 wheels vehicles have 2 wheels on front and one rear or the reverse). + ["4"] = { 0, 1, 4, 5 }, -- Vehicle with 4 wheels. + ["6"] = { 0, 1, 2, 3, 4, 5 }, -- Vehicle with 6 wheels. + } + + if TyresIndex[numWheels] then + for _, idx in pairs(TyresIndex[numWheels]) do + tyreBurst[tostring(idx)] = IsVehicleTyreBurst(vehicle, idx, false) + end + end + + for windowId = 0, 7 do -- 13 + RollUpWindow(vehicle, windowId) --fix when you put the car away with the window down + windowsBroken[tostring(windowId)] = not IsVehicleWindowIntact(vehicle, windowId) + end + + local numDoors = GetNumberOfVehicleDoors(vehicle) + if numDoors and numDoors > 0 then + for doorsId = 0, numDoors do + doorsBroken[tostring(doorsId)] = IsVehicleDoorDamaged(vehicle, doorsId) + end + end + + return { + model = GetEntityModel(vehicle), + doorsBroken = doorsBroken, + windowsBroken = windowsBroken, + tyreBurst = tyreBurst, + tyresCanBurst = GetVehicleTyresCanBurst(vehicle), + plate = ESX.Math.Trim(GetVehicleNumberPlateText(vehicle)), + plateIndex = GetVehicleNumberPlateTextIndex(vehicle), + + bodyHealth = ESX.Math.Round(GetVehicleBodyHealth(vehicle), 1), + engineHealth = ESX.Math.Round(GetVehicleEngineHealth(vehicle), 1), + tankHealth = ESX.Math.Round(GetVehiclePetrolTankHealth(vehicle), 1), + + fuelLevel = ESX.Math.Round(GetVehicleFuelLevel(vehicle), 1), + dirtLevel = ESX.Math.Round(GetVehicleDirtLevel(vehicle), 1), + color1 = colorPrimary, + color2 = colorSecondary, + + pearlescentColor = pearlescentColor, + wheelColor = wheelColor, + + dashboardColor = dashboardColor, + interiorColor = interiorColor, + + wheels = GetVehicleWheelType(vehicle), + windowTint = GetVehicleWindowTint(vehicle), + xenonColor = GetVehicleXenonLightsColor(vehicle), + customXenonColor = customXenonColor, + + neonEnabled = { IsVehicleNeonLightEnabled(vehicle, 0), IsVehicleNeonLightEnabled(vehicle, 1), IsVehicleNeonLightEnabled(vehicle, 2), IsVehicleNeonLightEnabled(vehicle, 3) }, + + neonColor = table.pack(GetVehicleNeonLightsColour(vehicle)), + extras = extras, + tyreSmokeColor = table.pack(GetVehicleTyreSmokeColor(vehicle)), + + modSpoilers = GetVehicleMod(vehicle, 0), + modFrontBumper = GetVehicleMod(vehicle, 1), + modRearBumper = GetVehicleMod(vehicle, 2), + modSideSkirt = GetVehicleMod(vehicle, 3), + modExhaust = GetVehicleMod(vehicle, 4), + modFrame = GetVehicleMod(vehicle, 5), + modGrille = GetVehicleMod(vehicle, 6), + modHood = GetVehicleMod(vehicle, 7), + modFender = GetVehicleMod(vehicle, 8), + modRightFender = GetVehicleMod(vehicle, 9), + modRoof = GetVehicleMod(vehicle, 10), + modRoofLivery = GetVehicleRoofLivery(vehicle), + + modEngine = GetVehicleMod(vehicle, 11), + modBrakes = GetVehicleMod(vehicle, 12), + modTransmission = GetVehicleMod(vehicle, 13), + modHorns = GetVehicleMod(vehicle, 14), + modSuspension = GetVehicleMod(vehicle, 15), + modArmor = GetVehicleMod(vehicle, 16), + + modTurbo = IsToggleModOn(vehicle, 18), + modSmokeEnabled = IsToggleModOn(vehicle, 20), + modXenon = IsToggleModOn(vehicle, 22), + + modFrontWheels = GetVehicleMod(vehicle, 23), + modCustomFrontWheels = GetVehicleModVariation(vehicle, 23), + modBackWheels = GetVehicleMod(vehicle, 24), + modCustomBackWheels = GetVehicleModVariation(vehicle, 24), + + modPlateHolder = GetVehicleMod(vehicle, 25), + modVanityPlate = GetVehicleMod(vehicle, 26), + modTrimA = GetVehicleMod(vehicle, 27), + modOrnaments = GetVehicleMod(vehicle, 28), + modDashboard = GetVehicleMod(vehicle, 29), + modDial = GetVehicleMod(vehicle, 30), + modDoorSpeaker = GetVehicleMod(vehicle, 31), + modSeats = GetVehicleMod(vehicle, 32), + modSteeringWheel = GetVehicleMod(vehicle, 33), + modShifterLeavers = GetVehicleMod(vehicle, 34), + modAPlate = GetVehicleMod(vehicle, 35), + modSpeakers = GetVehicleMod(vehicle, 36), + modTrunk = GetVehicleMod(vehicle, 37), + modHydrolic = GetVehicleMod(vehicle, 38), + modEngineBlock = GetVehicleMod(vehicle, 39), + modAirFilter = GetVehicleMod(vehicle, 40), + modStruts = GetVehicleMod(vehicle, 41), + modArchCover = GetVehicleMod(vehicle, 42), + modAerials = GetVehicleMod(vehicle, 43), + modTrimB = GetVehicleMod(vehicle, 44), + modTank = GetVehicleMod(vehicle, 45), + modWindows = GetVehicleMod(vehicle, 46), + modLivery = GetVehicleMod(vehicle, 48) == -1 and GetVehicleLivery(vehicle) or GetVehicleMod(vehicle, 48), + modLightbar = GetVehicleMod(vehicle, 49), + } +end + +---@param vehicle integer The vehicle to set the properties of +---@param props table The properties to set +---@return nil +function ESX.Game.SetVehicleProperties(vehicle, props) + if not DoesEntityExist(vehicle) then + return + end + local colorPrimary, colorSecondary = GetVehicleColours(vehicle) + local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) + SetVehicleModKit(vehicle, 0) + + if props.tyresCanBurst ~= nil then + SetVehicleTyresCanBurst(vehicle, props.tyresCanBurst) + end + + if props.plate ~= nil then + SetVehicleNumberPlateText(vehicle, props.plate) + end + if props.plateIndex ~= nil then + SetVehicleNumberPlateTextIndex(vehicle, props.plateIndex) + end + if props.bodyHealth ~= nil then + SetVehicleBodyHealth(vehicle, props.bodyHealth + 0.0) + end + if props.engineHealth ~= nil then + SetVehicleEngineHealth(vehicle, props.engineHealth + 0.0) + end + if props.tankHealth ~= nil then + SetVehiclePetrolTankHealth(vehicle, props.tankHealth + 0.0) + end + if props.fuelLevel ~= nil then + SetVehicleFuelLevel(vehicle, props.fuelLevel + 0.0) + end + if props.dirtLevel ~= nil then + SetVehicleDirtLevel(vehicle, props.dirtLevel + 0.0) + end + if props.color1 ~= nil then + if type(props.color1) == "table" then + SetVehicleCustomPrimaryColour(vehicle, props.color1[1], props.color1[2], props.color1[3]) + else + SetVehicleColours(vehicle, props.color1, colorSecondary) + end + end + if props.color2 ~= nil then + if type(props.color2) == "table" then + SetVehicleCustomSecondaryColour(vehicle, props.color2[1], props.color2[2], props.color2[3]) + else + SetVehicleColours(vehicle, props.color1 or colorPrimary, props.color2) + end + end + if props.pearlescentColor ~= nil then + SetVehicleExtraColours(vehicle, props.pearlescentColor, wheelColor) + end + + if props.interiorColor ~= nil then + SetVehicleInteriorColor(vehicle, props.interiorColor) + end + + if props.dashboardColor ~= nil then + SetVehicleDashboardColor(vehicle, props.dashboardColor) + end + + if props.wheelColor ~= nil then + SetVehicleExtraColours(vehicle, props.pearlescentColor or pearlescentColor, props.wheelColor) + end + if props.wheels ~= nil then + SetVehicleWheelType(vehicle, props.wheels) + end + if props.windowTint ~= nil then + SetVehicleWindowTint(vehicle, props.windowTint) + end + + if props.neonEnabled ~= nil then + SetVehicleNeonLightEnabled(vehicle, 0, props.neonEnabled[1]) + SetVehicleNeonLightEnabled(vehicle, 1, props.neonEnabled[2]) + SetVehicleNeonLightEnabled(vehicle, 2, props.neonEnabled[3]) + SetVehicleNeonLightEnabled(vehicle, 3, props.neonEnabled[4]) + end + + if props.extras ~= nil then + for extraId, enabled in pairs(props.extras) do + extraId = tonumber(extraId) + if extraId then + SetVehicleExtra(vehicle, extraId, not enabled) + end + end + end + + if props.neonColor ~= nil then + SetVehicleNeonLightsColour(vehicle, props.neonColor[1], props.neonColor[2], props.neonColor[3]) + end + if props.xenonColor ~= nil then + SetVehicleXenonLightsColor(vehicle, props.xenonColor) + end + if props.customXenonColor ~= nil then + SetVehicleXenonLightsCustomColor(vehicle, props.customXenonColor[1], props.customXenonColor[2], props.customXenonColor[3]) + end + if props.modSmokeEnabled ~= nil then + ToggleVehicleMod(vehicle, 20, true) + end + if props.tyreSmokeColor ~= nil then + SetVehicleTyreSmokeColor(vehicle, props.tyreSmokeColor[1], props.tyreSmokeColor[2], props.tyreSmokeColor[3]) + end + if props.modSpoilers ~= nil then + SetVehicleMod(vehicle, 0, props.modSpoilers, false) + end + if props.modFrontBumper ~= nil then + SetVehicleMod(vehicle, 1, props.modFrontBumper, false) + end + if props.modRearBumper ~= nil then + SetVehicleMod(vehicle, 2, props.modRearBumper, false) + end + if props.modSideSkirt ~= nil then + SetVehicleMod(vehicle, 3, props.modSideSkirt, false) + end + if props.modExhaust ~= nil then + SetVehicleMod(vehicle, 4, props.modExhaust, false) + end + if props.modFrame ~= nil then + SetVehicleMod(vehicle, 5, props.modFrame, false) + end + if props.modGrille ~= nil then + SetVehicleMod(vehicle, 6, props.modGrille, false) + end + if props.modHood ~= nil then + SetVehicleMod(vehicle, 7, props.modHood, false) + end + if props.modFender ~= nil then + SetVehicleMod(vehicle, 8, props.modFender, false) + end + if props.modRightFender ~= nil then + SetVehicleMod(vehicle, 9, props.modRightFender, false) + end + if props.modRoof ~= nil then + SetVehicleMod(vehicle, 10, props.modRoof, false) + end + + if props.modRoofLivery ~= nil then + SetVehicleRoofLivery(vehicle, props.modRoofLivery) + end + + if props.modEngine ~= nil then + SetVehicleMod(vehicle, 11, props.modEngine, false) + end + if props.modBrakes ~= nil then + SetVehicleMod(vehicle, 12, props.modBrakes, false) + end + if props.modTransmission ~= nil then + SetVehicleMod(vehicle, 13, props.modTransmission, false) + end + if props.modHorns ~= nil then + SetVehicleMod(vehicle, 14, props.modHorns, false) + end + if props.modSuspension ~= nil then + SetVehicleMod(vehicle, 15, props.modSuspension, false) + end + if props.modArmor ~= nil then + SetVehicleMod(vehicle, 16, props.modArmor, false) + end + if props.modTurbo ~= nil then + ToggleVehicleMod(vehicle, 18, props.modTurbo) + end + if props.modXenon ~= nil then + ToggleVehicleMod(vehicle, 22, props.modXenon) + end + if props.modFrontWheels ~= nil then + SetVehicleMod(vehicle, 23, props.modFrontWheels, props.modCustomFrontWheels) + end + if props.modBackWheels ~= nil then + SetVehicleMod(vehicle, 24, props.modBackWheels, props.modCustomBackWheels) + end + if props.modPlateHolder ~= nil then + SetVehicleMod(vehicle, 25, props.modPlateHolder, false) + end + if props.modVanityPlate ~= nil then + SetVehicleMod(vehicle, 26, props.modVanityPlate, false) + end + if props.modTrimA ~= nil then + SetVehicleMod(vehicle, 27, props.modTrimA, false) + end + if props.modOrnaments ~= nil then + SetVehicleMod(vehicle, 28, props.modOrnaments, false) + end + if props.modDashboard ~= nil then + SetVehicleMod(vehicle, 29, props.modDashboard, false) + end + if props.modDial ~= nil then + SetVehicleMod(vehicle, 30, props.modDial, false) + end + if props.modDoorSpeaker ~= nil then + SetVehicleMod(vehicle, 31, props.modDoorSpeaker, false) + end + if props.modSeats ~= nil then + SetVehicleMod(vehicle, 32, props.modSeats, false) + end + if props.modSteeringWheel ~= nil then + SetVehicleMod(vehicle, 33, props.modSteeringWheel, false) + end + if props.modShifterLeavers ~= nil then + SetVehicleMod(vehicle, 34, props.modShifterLeavers, false) + end + if props.modAPlate ~= nil then + SetVehicleMod(vehicle, 35, props.modAPlate, false) + end + if props.modSpeakers ~= nil then + SetVehicleMod(vehicle, 36, props.modSpeakers, false) + end + if props.modTrunk ~= nil then + SetVehicleMod(vehicle, 37, props.modTrunk, false) + end + if props.modHydrolic ~= nil then + SetVehicleMod(vehicle, 38, props.modHydrolic, false) + end + if props.modEngineBlock ~= nil then + SetVehicleMod(vehicle, 39, props.modEngineBlock, false) + end + if props.modAirFilter ~= nil then + SetVehicleMod(vehicle, 40, props.modAirFilter, false) + end + if props.modStruts ~= nil then + SetVehicleMod(vehicle, 41, props.modStruts, false) + end + if props.modArchCover ~= nil then + SetVehicleMod(vehicle, 42, props.modArchCover, false) + end + if props.modAerials ~= nil then + SetVehicleMod(vehicle, 43, props.modAerials, false) + end + if props.modTrimB ~= nil then + SetVehicleMod(vehicle, 44, props.modTrimB, false) + end + if props.modTank ~= nil then + SetVehicleMod(vehicle, 45, props.modTank, false) + end + if props.modWindows ~= nil then + SetVehicleMod(vehicle, 46, props.modWindows, false) + end + + if props.modLivery ~= nil then + SetVehicleMod(vehicle, 48, props.modLivery, false) + SetVehicleLivery(vehicle, props.modLivery) + end + + if props.windowsBroken ~= nil then + for k, v in pairs(props.windowsBroken) do + if v then + k = tonumber(k) + if k then + RemoveVehicleWindow(vehicle, k) + end + end + end + end + + if props.doorsBroken ~= nil then + for k, v in pairs(props.doorsBroken) do + if v then + k = tonumber(k) + if k then + SetVehicleDoorBroken(vehicle, k, true) + end + end + end + end + + if props.tyreBurst ~= nil then + for k, v in pairs(props.tyreBurst) do + if v then + k = tonumber(k) + if k then + SetVehicleTyreBurst(vehicle, k, true, 1000.0) + end + end + end + end +end + +---@param coords vector3 | table coords to get the closest pickup to +---@param text string The text to display +---@param size? number The size of the text +---@param font? number The font of the text +---@return nil +function ESX.Game.Utils.DrawText3D(coords, text, size, font) + local vector = type(coords) == "vector3" and coords or vec(coords.x, coords.y, coords.z) + + local camCoords = GetFinalRenderedCamCoord() + local distance = #(vector - camCoords) + + size = size or 1 + font = font or 0 + + local scale = (size / distance) * 2 + local fov = (1 / GetGameplayCamFov()) * 100 + scale = scale * fov + + SetTextScale(0.0, 0.55 * scale) + SetTextFont(font) + SetTextProportional(true) + SetTextColour(255, 255, 255, 215) + BeginTextCommandDisplayText("STRING") + SetTextCentre(true) + AddTextComponentSubstringPlayerName(text) + SetDrawOrigin(vector.x, vector.y, vector.z, 0) + EndTextCommandDisplayText(0.0, 0.0) + ClearDrawOrigin() +end + +---@param account string Account name (money/bank/black_money) +---@return table|nil +function ESX.GetAccount(account) + for i = 1, #ESX.PlayerData.accounts, 1 do + if ESX.PlayerData.accounts[i].name == account then + return ESX.PlayerData.accounts[i] + end + end + return nil +end + +function ESX.ShowInventory() + if not Config.EnableDefaultInventory then + return + end + + exports.esx_inventory:ShowInventory() +end + +RegisterNetEvent('esx:showNotification', ESX.ShowNotification) + +RegisterNetEvent('esx:showAdvancedNotification', ESX.ShowAdvancedNotification) + +RegisterNetEvent('esx:showHelpNotification', ESX.ShowHelpNotification) + +AddEventHandler("onResourceStop", function(resourceName) + for i = 1, #ESX.UI.Menu.Opened, 1 do + if ESX.UI.Menu.Opened[i] then + if ESX.UI.Menu.Opened[i].resourceName == resourceName or ESX.UI.Menu.Opened[i].namespace == resourceName then + ESX.UI.Menu.Opened[i].close() + ESX.UI.Menu.Opened[i] = nil + end + end + end +end) +-- Credits to txAdmin for the list. +local mismatchedTypes = { + [`airtug`] = "automobile", -- trailer + [`avisa`] = "submarine", -- boat + [`blimp`] = "heli", -- plane + [`blimp2`] = "heli", -- plane + [`blimp3`] = "heli", -- plane + [`caddy`] = "automobile", -- trailer + [`caddy2`] = "automobile", -- trailer + [`caddy3`] = "automobile", -- trailer + [`chimera`] = "automobile", -- bike + [`docktug`] = "automobile", -- trailer + [`forklift`] = "automobile", -- trailer + [`kosatka`] = "submarine", -- boat + [`mower`] = "automobile", -- trailer + [`policeb`] = "bike", -- automobile + [`ripley`] = "automobile", -- trailer + [`rrocket`] = "automobile", -- bike + [`sadler`] = "automobile", -- trailer + [`sadler2`] = "automobile", -- trailer + [`scrap`] = "automobile", -- trailer + [`slamtruck`] = "automobile", -- trailer + [`Stryder`] = "automobile", -- bike + [`submersible`] = "submarine", -- boat + [`submersible2`] = "submarine", -- boat + [`thruster`] = "heli", -- automobile + [`towtruck`] = "automobile", -- trailer + [`towtruck2`] = "automobile", -- trailer + [`tractor`] = "automobile", -- trailer + [`tractor2`] = "automobile", -- trailer + [`tractor3`] = "automobile", -- trailer + [`trailersmall2`] = "trailer", -- automobile + [`utillitruck`] = "automobile", -- trailer + [`utillitruck2`] = "automobile", -- trailer + [`utillitruck3`] = "automobile", -- trailer +} + +---@param model number|string +---@return string | boolean +function ESX.GetVehicleTypeClient(model) + model = type(model) == "string" and joaat(model) or model + if not IsModelInCdimage(model) then + return false + end + + if not IsModelAVehicle(model) then + return false + end + + if mismatchedTypes[model] then + return mismatchedTypes[model] + end + + local vehicleType = GetVehicleClassFromName(model) + local types = { + [8] = "bike", + [11] = "trailer", + [13] = "bike", + [14] = "boat", + [15] = "heli", + [16] = "plane", + [21] = "train", + } + + return types[vehicleType] or "automobile" +end + +ESX.GetVehicleType = ESX.GetVehicleTypeClient diff --git a/resources/[core]/es_extended/client/imports/class.lua b/resources/[core]/es_extended/client/imports/class.lua new file mode 100644 index 0000000..0b21d99 --- /dev/null +++ b/resources/[core]/es_extended/client/imports/class.lua @@ -0,0 +1,21 @@ +local class = {} +class.__index = class + +function class:new(...) + local instance = setmetatable({}, self) + if instance.constructor then + local ret = instance:constructor(...) + if type(ret) == 'table' then + return ret + end + end + return instance +end + +function Class(body, heritage) + local prototype = body or {} + prototype.__index = prototype + return setmetatable(prototype, heritage or class) +end + +return Class \ No newline at end of file diff --git a/resources/[core]/es_extended/client/imports/point.lua b/resources/[core]/es_extended/client/imports/point.lua new file mode 100644 index 0000000..dc2ab06 --- /dev/null +++ b/resources/[core]/es_extended/client/imports/point.lua @@ -0,0 +1,53 @@ +local Point = ESX.Class() + +local nearby, loop = {}, nil + +function Point:constructor(properties) + self.coords = properties.coords + self.hidden = properties.hidden + self.enter = properties.enter + self.leave = properties.leave + self.inside = properties.inside + self.handle = ESX.CreatePointInternal(properties.coords, properties.distance, properties.hidden, function() + nearby[self.handle] = self + if self.enter then + self:enter() + end + if not loop then + loop = true + CreateThread(function() + while loop do + local coords = GetEntityCoords(ESX.PlayerData.ped) + for _, point in pairs(nearby) do + if point.inside then + point:inside(#(coords - point.coords)) + end + end + Wait(0) + end + end) + end + end, function() + nearby[self.handle] = nil + if self.leave then + self:leave() + end + if #nearby == 0 then + loop = false + end + end) +end + +function Point:delete() + ESX.RemovePointInternal(self.handle) +end + +function Point:toggle(hidden) + if hidden == nil then + hidden = not self.hidden + end + self.hidden = hidden + ESX.HidePointInternal(self.handle, hidden) +end + +return Point \ No newline at end of file diff --git a/resources/[core]/es_extended/client/main.lua b/resources/[core]/es_extended/client/main.lua new file mode 100644 index 0000000..441af76 --- /dev/null +++ b/resources/[core]/es_extended/client/main.lua @@ -0,0 +1,30 @@ +Core = {} +Core.Input = {} +Core.Events = {} + +ESX.PlayerData = {} +ESX.PlayerLoaded = false +ESX.playerId = PlayerId() +ESX.serverId = GetPlayerServerId(ESX.playerId) + +ESX.UI = {} +ESX.UI.Menu = {} +ESX.UI.Menu.RegisteredTypes = {} +ESX.UI.Menu.Opened = {} + +ESX.Game = {} +ESX.Game.Utils = {} + +CreateThread(function() + while not Config.Multichar do + Wait(100) + + if NetworkIsPlayerActive(ESX.playerId) then + ESX.DisableSpawnManager() + DoScreenFadeOut(0) + Wait(500) + TriggerServerEvent("esx:onPlayerJoined") + break + end + end +end) diff --git a/resources/[core]/es_extended/client/modules/actions.lua b/resources/[core]/es_extended/client/modules/actions.lua new file mode 100644 index 0000000..de17491 --- /dev/null +++ b/resources/[core]/es_extended/client/modules/actions.lua @@ -0,0 +1,234 @@ +Actions = {} +Actions._index = Actions + +Actions.inVehicle = false +Actions.enteringVehicle = false +Actions.inPauseMenu = false +Actions.currentWeapon = false + +function Actions:GetSeatPedIsIn() + for i = -1, 16 do + if GetPedInVehicleSeat(self.vehicle, i) == ESX.PlayerData.ped then + return i + end + end + return -1 +end + +function Actions:GetVehicleData() + if not DoesEntityExist(self.vehicle) then + return + end + + local vehicleModel = GetEntityModel(self.vehicle) + local displayName = GetDisplayNameFromVehicleModel(vehicleModel) + local netId = NetworkGetEntityIsNetworked(self.vehicle) and VehToNet(self.vehicle) or self.vehicle + local plate = GetVehicleNumberPlateText(self.vehicle) + + return displayName, netId, plate +end + +function Actions:SetVehicleStatus() + ESX.SetPlayerData("vehicle", self.vehicle) + ESX.SetPlayerData("seat", self.seat) +end + +function Actions:TrackPedCoordsOnce() + CreateThread(function() + while not ESX.IsPlayerLoaded() do + Wait(250) + end + + ESX.PlayerData.coords = nil + + setmetatable(ESX.PlayerData, { + __index = function(_, key) + if key ~= "coords" then + return + end + + local coords = GetEntityCoords(ESX.PlayerData.ped) + + return coords + end + }) + end) +end + +function Actions:TrackPed() + local playerPed = ESX.PlayerData.ped + local newPed = PlayerPedId() + + if playerPed ~= newPed then + ESX.SetPlayerData("ped", newPed) + + TriggerEvent("esx:playerPedChanged", newPed) + + if Config.EnableDebug then + print("[DEBUG] Player ped changed:", newPed) + end + end +end + +function Actions:TrackPauseMenu() + local isActive = IsPauseMenuActive() + + if isActive ~= self.inPauseMenu then + self.inPauseMenu = isActive + TriggerEvent("esx:pauseMenuActive", isActive) + + if Config.EnableDebug then + print("[DEBUG] Pause menu active:", isActive) + end + end +end + +function Actions:EnterVehicle() + self.seat = GetSeatPedIsTryingToEnter(ESX.PlayerData.ped) + + local _, netId, plate = self:GetVehicleData() + + self.enteringVehicle = true + TriggerEvent("esx:enteringVehicle", self.vehicle, plate, self.seat, netId) + TriggerServerEvent("esx:enteringVehicle", plate, self.seat, netId) + + self:SetVehicleStatus() + + if Config.EnableDebug then + print("[DEBUG] Entering vehicle:", self.vehicle, plate, self.seat, netId) + end +end + +function Actions:ResetVehicleData() + self.enteringVehicle = false + self.vehicle = false + self.seat = false + self.inVehicle = false + + self:SetVehicleStatus() +end + +function Actions:EnterAborted() + self:ResetVehicleData() + + TriggerEvent("esx:enteringVehicleAborted") + TriggerServerEvent("esx:enteringVehicleAborted") + + if Config.EnableDebug then + print("[DEBUG] Entering vehicle aborted") + end +end + +function Actions:WarpEnter() + self.enteringVehicle = false + self.inVehicle = true + + self.seat = self:GetSeatPedIsIn() + + local displayName, netId, plate = self:GetVehicleData() + + self:SetVehicleStatus() + TriggerEvent("esx:enteredVehicle", self.vehicle, plate, self.seat, displayName, netId) + TriggerServerEvent("esx:enteredVehicle", plate, self.seat, displayName, netId) + + if Config.EnableDebug then + print("[DEBUG] Entered vehicle:", self.vehicle, plate, self.seat, displayName, netId) + end +end + +function Actions:ExitVehicle() + local currentVehicle = GetVehiclePedIsIn(ESX.PlayerData.ped, false) + + if currentVehicle ~= self.vehicle or ESX.PlayerData.dead then + local displayName, netId, plate = self:GetVehicleData() + + TriggerEvent("esx:exitedVehicle", self.vehicle, plate, self.seat, displayName, netId) + TriggerServerEvent("esx:exitedVehicle", plate, self.seat, displayName, netId) + + if Config.EnableDebug then + print("[DEBUG] Exited vehicle:", self.vehicle, plate, self.seat, displayName, netId) + end + + self:ResetVehicleData() + end +end + +function Actions:TrackVehicle() + if not self.inVehicle and not ESX.PlayerData.dead then + local tempVehicle = GetVehiclePedIsTryingToEnter(ESX.PlayerData.ped) + + if DoesEntityExist(tempVehicle) and not self.enteringVehicle then + self.vehicle = tempVehicle + self:EnterVehicle() + elseif not DoesEntityExist(tempVehicle) and not IsPedInAnyVehicle(ESX.PlayerData.ped, true) and self.enteringVehicle then + self:EnterAborted() + elseif IsPedInAnyVehicle(ESX.PlayerData.ped, false) then + self.vehicle = GetVehiclePedIsIn(ESX.PlayerData.ped, false) + self:WarpEnter() + end + elseif self.inVehicle then + self:ExitVehicle() + self:TrackSeat() + end +end + +function Actions:TrackSeat() + if not self.inVehicle then + return + end + + local newSeat = self:GetSeatPedIsIn() + if newSeat ~= self.seat then + self.seat = newSeat + ESX.SetPlayerData("seat", self.seat) + TriggerEvent("esx:vehicleSeatChanged", self.seat) + + if Config.EnableDebug then + print("[DEBUG] Vehicle seat changed:", self.seat) + end + end +end + +function Actions:TrackWeapon() + ---@type number|false + local newWeapon = GetSelectedPedWeapon(ESX.PlayerData.ped) + newWeapon = newWeapon ~= `WEAPON_UNARMED` and newWeapon or false + + if newWeapon ~= self.currentWeapon then + self.currentWeapon = newWeapon + ESX.SetPlayerData("weapon", self.currentWeapon) + TriggerEvent("esx:weaponChanged", self.currentWeapon) + + if Config.EnableDebug then + print("[DEBUG] Weapon changed:", self.currentWeapon) + end + end +end + +function Actions:SlowLoop() + CreateThread(function() + while ESX.PlayerLoaded do + self:TrackPauseMenu() + self:TrackVehicle() + self:TrackWeapon() + Wait(500) + end + end) +end + +function Actions:PedLoop() + CreateThread(function() + while ESX.PlayerLoaded do + self:TrackPed() + Wait(0) + end + end) +end + +function Actions:Init() + self:SlowLoop() + self:PedLoop() + self:TrackPedCoordsOnce() +end + +Actions:Init() diff --git a/resources/[core]/es_extended/client/modules/adjustments.lua b/resources/[core]/es_extended/client/modules/adjustments.lua new file mode 100644 index 0000000..1c83b14 --- /dev/null +++ b/resources/[core]/es_extended/client/modules/adjustments.lua @@ -0,0 +1,253 @@ +Adjustments = {} + +function Adjustments:RemoveHudComponents() + for i = 1, #Config.RemoveHudComponents do + if Config.RemoveHudComponents[i] then + SetHudComponentSize(i, 0.0, 0.0) + SetHudComponentPosition(i, 900.0, 900.0) + end + end +end + +function Adjustments:DisableAimAssist() + if Config.DisableAimAssist then + SetPlayerTargetingMode(3) + end +end + +function Adjustments:DisableNPCDrops() + if Config.DisableNPCDrops then + local weaponPickups = { `PICKUP_WEAPON_CARBINERIFLE`, `PICKUP_WEAPON_PISTOL`, `PICKUP_WEAPON_PUMPSHOTGUN` } + for i = 1, #weaponPickups do + ToggleUsePickupsForPlayer(ESX.playerId, weaponPickups[i], false) + end + end +end + +function Adjustments:SeatShuffle() + if Config.DisableVehicleSeatShuff then + AddEventHandler("esx:enteredVehicle", function(vehicle, _, seat) + if seat > -1 then + SetPedIntoVehicle(ESX.PlayerData.ped, vehicle, seat) + SetPedConfigFlag(ESX.PlayerData.ped, 184, true) + end + end) + end +end + +function Adjustments:HealthRegeneration() + if Config.DisableHealthRegeneration then + SetPlayerHealthRechargeMultiplier(ESX.playerId, 0.0) + end +end + +function Adjustments:AmmoAndVehicleRewards() + CreateThread(function() + while true do + if Config.DisableDisplayAmmo then + DisplayAmmoThisFrame(false) + end + + if Config.DisableVehicleRewards then + DisablePlayerVehicleRewards(ESX.playerId) + end + + Wait(0) + end + end) +end + +function Adjustments:EnablePvP() + if Config.EnablePVP then + SetCanAttackFriendly(ESX.PlayerData.ped, true, false) + NetworkSetFriendlyFireOption(true) + end +end + +function Adjustments:DispatchServices() + if Config.DisableDispatchServices then + for i = 1, 15 do + EnableDispatchService(i, false) + end + SetAudioFlag('PoliceScannerDisabled', true) + end +end + +function Adjustments:NPCScenarios() + if Config.DisableScenarios then + local scenarios = { + "WORLD_VEHICLE_ATTRACTOR", + "WORLD_VEHICLE_AMBULANCE", + "WORLD_VEHICLE_BICYCLE_BMX", + "WORLD_VEHICLE_BICYCLE_BMX_BALLAS", + "WORLD_VEHICLE_BICYCLE_BMX_FAMILY", + "WORLD_VEHICLE_BICYCLE_BMX_HARMONY", + "WORLD_VEHICLE_BICYCLE_BMX_VAGOS", + "WORLD_VEHICLE_BICYCLE_MOUNTAIN", + "WORLD_VEHICLE_BICYCLE_ROAD", + "WORLD_VEHICLE_BIKE_OFF_ROAD_RACE", + "WORLD_VEHICLE_BIKER", + "WORLD_VEHICLE_BOAT_IDLE", + "WORLD_VEHICLE_BOAT_IDLE_ALAMO", + "WORLD_VEHICLE_BOAT_IDLE_MARQUIS", + "WORLD_VEHICLE_BROKEN_DOWN", + "WORLD_VEHICLE_BUSINESSMEN", + "WORLD_VEHICLE_HELI_LIFEGUARD", + "WORLD_VEHICLE_CLUCKIN_BELL_TRAILER", + "WORLD_VEHICLE_CONSTRUCTION_SOLO", + "WORLD_VEHICLE_CONSTRUCTION_PASSENGERS", + "WORLD_VEHICLE_DRIVE_PASSENGERS", + "WORLD_VEHICLE_DRIVE_PASSENGERS_LIMITED", + "WORLD_VEHICLE_DRIVE_SOLO", + "WORLD_VEHICLE_FIRE_TRUCK", + "WORLD_VEHICLE_EMPTY", + "WORLD_VEHICLE_MARIACHI", + "WORLD_VEHICLE_MECHANIC", + "WORLD_VEHICLE_MILITARY_PLANES_BIG", + "WORLD_VEHICLE_MILITARY_PLANES_SMALL", + "WORLD_VEHICLE_PARK_PARALLEL", + "WORLD_VEHICLE_PARK_PERPENDICULAR_NOSE_IN", + "WORLD_VEHICLE_PASSENGER_EXIT", + "WORLD_VEHICLE_POLICE_BIKE", + "WORLD_VEHICLE_POLICE_CAR", + "WORLD_VEHICLE_POLICE", + "WORLD_VEHICLE_POLICE_NEXT_TO_CAR", + "WORLD_VEHICLE_QUARRY", + "WORLD_VEHICLE_SALTON", + "WORLD_VEHICLE_SALTON_DIRT_BIKE", + "WORLD_VEHICLE_SECURITY_CAR", + "WORLD_VEHICLE_STREETRACE", + "WORLD_VEHICLE_TOURBUS", + "WORLD_VEHICLE_TOURIST", + "WORLD_VEHICLE_TANDL", + "WORLD_VEHICLE_TRACTOR", + "WORLD_VEHICLE_TRACTOR_BEACH", + "WORLD_VEHICLE_TRUCK_LOGS", + "WORLD_VEHICLE_TRUCKS_TRAILERS", + "WORLD_VEHICLE_DISTANT_EMPTY_GROUND", + "WORLD_HUMAN_PAPARAZZI", + } + + for i=1, #scenarios do + SetScenarioTypeEnabled(scenarios[i], false) + end + end +end + +function Adjustments:LicensePlates() + SetDefaultVehicleNumberPlateTextPattern(-1, Config.CustomAIPlates) +end + +local placeHolders = { + server_name = function() + return GetConvar("sv_projectName", "ESX-Framework") + end, + server_endpoint = function() + return GetCurrentServerEndpoint() or "localhost:30120" + end, + server_players = function() + return GlobalState.playerCount or 0 + end, + server_maxplayers = function() + return GetConvarInt("sv_maxClients", 48) + end, + player_name = function() + return GetPlayerName(ESX.playerId) + end, + player_rp_name = function() + return ESX.PlayerData.name or "John Doe" + end, + player_id = function() + return ESX.serverId + end, + player_street = function() + if not ESX.PlayerData.ped then return "Unknown" end + + local playerCoords = GetEntityCoords(ESX.PlayerData.ped) + local streetHash = GetStreetNameAtCoord(playerCoords.x, playerCoords.y, playerCoords.z) + + return GetStreetNameFromHashKey(streetHash) or "Unknown" + end, +} + +function Adjustments:ReplacePlaceholders(text) + for placeholder, cb in pairs(placeHolders) do + local success, result = pcall(cb) + + if not success then + error(("Failed to execute placeholder: ^5%s^7\n%s"):format(placeholder, result)) + result = "Unknown" + end + + text = text:gsub(("{%s}"):format(placeholder), tostring(result)) + end + return text +end + +function Adjustments:DiscordPresence() + if Config.DiscordActivity.appId ~= 0 then + CreateThread(function() + while true do + SetDiscordAppId(Config.DiscordActivity.appId) + SetRichPresence(self:ReplacePlaceholders(Config.DiscordActivity.presence)) + SetDiscordRichPresenceAsset(Config.DiscordActivity.assetName) + SetDiscordRichPresenceAssetText(self:ReplacePlaceholders(Config.DiscordActivity.assetText)) + + for i = 1, #Config.DiscordActivity.buttons do + local button = Config.DiscordActivity.buttons[i] + local buttonUrl = self:ReplacePlaceholders(button.url) + SetDiscordRichPresenceAction(i - 1, button.label, buttonUrl) + end + + Wait(Config.DiscordActivity.refresh) + end + end) + end +end + +function Adjustments:WantedLevel() + if not Config.EnableWantedLevel then + ClearPlayerWantedLevel(ESX.playerId) + SetMaxWantedLevel(0) + end +end + +function Adjustments:DisableRadio() + if Config.RemoveHudComponents[16] then + AddEventHandler("esx:enteredVehicle", function(vehicle, plate, seat, displayName, netId) + SetVehRadioStation(vehicle,"OFF") + SetUserRadioControlEnabled(false) + end) + end +end + +function Adjustments:Multipliers() + CreateThread(function() + while true do + SetPedDensityMultiplierThisFrame(Config.Multipliers.pedDensity) + SetScenarioPedDensityMultiplierThisFrame(Config.Multipliers.scenarioPedDensityInterior, Config.Multipliers.scenarioPedDensityExterior) + SetAmbientVehicleRangeMultiplierThisFrame(Config.Multipliers.ambientVehicleRange) + SetParkedVehicleDensityMultiplierThisFrame(Config.Multipliers.parkedVehicleDensity) + SetRandomVehicleDensityMultiplierThisFrame(Config.Multipliers.randomVehicleDensity) + SetVehicleDensityMultiplierThisFrame(Config.Multipliers.vehicleDensity) + Wait(0) + end + end) +end + +function Adjustments:Load() + self:RemoveHudComponents() + self:DisableAimAssist() + self:DisableNPCDrops() + self:SeatShuffle() + self:HealthRegeneration() + self:AmmoAndVehicleRewards() + self:EnablePvP() + self:DispatchServices() + self:NPCScenarios() + self:LicensePlates() + self:DiscordPresence() + self:WantedLevel() + self:DisableRadio() + self:Multipliers() +end diff --git a/resources/[core]/es_extended/client/modules/callback.lua b/resources/[core]/es_extended/client/modules/callback.lua new file mode 100644 index 0000000..30211b9 --- /dev/null +++ b/resources/[core]/es_extended/client/modules/callback.lua @@ -0,0 +1,146 @@ +---@diagnostic disable: duplicate-set-field + +-- ============================================= +-- MARK: Variables +-- ============================================= + +Callbacks = {} + +Callbacks.requests = {} +Callbacks.storage = {} +Callbacks.id = 0 + +-- ============================================= +-- MARK: Internal Functions +-- ============================================= + + +function Callbacks:Register(name, resource, cb) + self.storage[name] = { + resource = resource, + cb = cb + } +end + +function Callbacks:Execute(cb, id, ...) + local success, errorString = pcall(cb, ...) + + if not success then + print(("[^1ERROR^7] Failed to execute Callback with RequestId: ^5%s^7"):format(id)) + error(errorString) + return + end +end + +function Callbacks:Trigger(event, cb, invoker, ...) + self.requests[self.id] = { + await = type(cb) == "boolean", + cb = cb or promise:new() + } + local table = self.requests[self.id] + + TriggerServerEvent("esx:triggerServerCallback", event, self.id, invoker, ...) + + self.id += 1 + + return table.cb +end + +function Callbacks:ServerRecieve(requestId, invoker, ...) + if not self.requests[requestId] then + return error(("Server Callback with requestId ^5%s^1 Was Called by ^5%s^1 but does not exist."):format(requestId, invoker)) + end + + local callback = self.requests[requestId] + + self.requests[requestId] = nil + + if callback.await then + callback.cb:resolve({ ... }) + else + self:Execute(callback.cb, requestId, ...) + end +end + +function Callbacks:ClientRecieve(eventName, requestId, invoker, ...) + if not self.storage[eventName] then + return error(("Client Callback with requestId ^5%s^1 Was Called by ^5%s^1 but does not exist."):format(eventName, invoker)) + end + + local returnCb = function(...) + TriggerServerEvent("esx:clientCallback", requestId, invoker, ...) + end + local callback = self.storage[eventName].cb + + self:Execute(callback, requestId, returnCb, ...) +end + +-- ============================================= +-- MARK: ESX Functions +-- ============================================= + +---@param eventName string +---@param callback function +---@param ... any +---@return nil +function ESX.TriggerServerCallback(eventName, callback, ...) + local invokingResource = GetInvokingResource() + local invoker = (invokingResource and invokingResource ~= "unknown") and invokingResource or "es_extended" + + Callbacks:Trigger(eventName, callback, invoker, ...) +end + +---@param eventName string +---@param ... any +---@return ... +function ESX.AwaitServerCallback(eventName, ...) + local invokingResource = GetInvokingResource() + local invoker = (invokingResource and invokingResource ~= "unknown") and invokingResource or "es_extended" + + local p = Callbacks:Trigger(eventName, false, invoker, ...) + if not p then return end + + -- if the server callback takes longer than 15 seconds to respond, reject the promise + SetTimeout(15000, function() + if p.state == "pending" then + p:reject("Server Callback Timed Out") + end + end) + + Citizen.Await(p) + + return table.unpack(p.value) +end + +function ESX.RegisterClientCallback(eventName, callback) + local invokingResource = GetInvokingResource() + local invoker = (invokingResource and invokingResource ~= "Unknown") and invokingResource or "es_extended" + + Callbacks:Register(eventName, invoker, callback) +end + +---@param eventName string +---@return boolean +function ESX.DoesClientCallbackExist(eventName) + return Callbacks.storage[eventName] ~= nil +end + +-- ============================================= +-- MARK: Events +-- ============================================= + +ESX.SecureNetEvent("esx:serverCallback", function(...) + Callbacks:ServerRecieve(...) +end) + +ESX.SecureNetEvent("esx:triggerClientCallback", function(...) + Callbacks:ClientRecieve(...) +end) + +AddEventHandler("onResourceStop", function(resource) + for k, v in pairs(Callbacks.storage) do + if v.resource == resource then + Callbacks.storage[k] = nil + end + end +end) diff --git a/resources/[core]/es_extended/client/modules/death.lua b/resources/[core]/es_extended/client/modules/death.lua new file mode 100644 index 0000000..346c3ce --- /dev/null +++ b/resources/[core]/es_extended/client/modules/death.lua @@ -0,0 +1,75 @@ +Death = {} +Death._index = Death + +function Death:ResetValues() + self.killerEntity = nil + self.deathCause = nil + self.killerId = nil + self.killerServerId = nil +end + +function Death:ByPlayer() + local victimCoords = GetEntityCoords(ESX.PlayerData.ped) + local killerCoords = GetEntityCoords(self.killerEntity) + local distance = #(victimCoords - killerCoords) + + local data = { + victimCoords = { x = ESX.Math.Round(victimCoords.x, 1), y = ESX.Math.Round(victimCoords.y, 1), z = ESX.Math.Round(victimCoords.z, 1) }, + killerCoords = { x = ESX.Math.Round(killerCoords.x, 1), y = ESX.Math.Round(killerCoords.y, 1), z = ESX.Math.Round(killerCoords.z, 1) }, + + killedByPlayer = true, + deathCause = self.deathCause, + distance = ESX.Math.Round(distance, 1), + + killerServerId = self.killerServerId, + killerClientId = self.killerId, + } + + TriggerEvent("esx:onPlayerDeath", data) + TriggerServerEvent("esx:onPlayerDeath", data) +end + +function Death:Natural() + local coords = GetEntityCoords(ESX.PlayerData.ped) + + local data = { + victimCoords = { x = ESX.Math.Round(coords.x, 1), y = ESX.Math.Round(coords.y, 1), z = ESX.Math.Round(coords.z, 1) }, + + killedByPlayer = false, + deathCause = self.deathCause, + } + + TriggerEvent("esx:onPlayerDeath", data) + TriggerServerEvent("esx:onPlayerDeath", data) +end + +function Death:Died() + self.killerEntity = GetPedSourceOfDeath(ESX.PlayerData.ped) + self.deathCause = GetPedCauseOfDeath(ESX.PlayerData.ped) + self.killerId = NetworkGetPlayerIndexFromPed(self.killerEntity) + self.killerServerId = GetPlayerServerId(self.killerId) + + local isActive = NetworkIsPlayerActive(self.killerId) + + if self.killerEntity ~= ESX.PlayerData.ped and self.killerId and isActive then + self:ByPlayer() + else + self:Natural() + end + + self:ResetValues() +end + +AddEventHandler("esx:onPlayerSpawn", function() + Citizen.CreateThreadNow(function() + while not ESX.PlayerLoaded do Wait(0) end + + while ESX.PlayerLoaded and not ESX.PlayerData.dead do + if DoesEntityExist(ESX.PlayerData.ped) and (IsPedDeadOrDying(ESX.PlayerData.ped, true) or IsPedFatallyInjured(ESX.PlayerData.ped)) then + Death:Died() + break + end + Citizen.Wait(250) + end + end) +end) diff --git a/resources/[core]/es_extended/client/modules/events.lua b/resources/[core]/es_extended/client/modules/events.lua new file mode 100644 index 0000000..5cffaeb --- /dev/null +++ b/resources/[core]/es_extended/client/modules/events.lua @@ -0,0 +1,615 @@ +local pickups = {} + +RegisterNetEvent("esx:requestModel", function(model) + ESX.Streaming.RequestModel(model) +end) + +RegisterNetEvent("esx:playerLoaded", function(xPlayer, _, skin) + ESX.PlayerData = xPlayer + + if not Config.Multichar then + ESX.SpawnPlayer(skin, ESX.PlayerData.coords, function() + TriggerEvent("esx:onPlayerSpawn") + TriggerEvent("esx:restoreLoadout") + TriggerServerEvent("esx:onPlayerSpawn") + TriggerEvent("esx:loadingScreenOff") + ShutdownLoadingScreen() + ShutdownLoadingScreenNui() + end) + end + + while not DoesEntityExist(ESX.PlayerData.ped) do + Wait(20) + end + + ESX.PlayerLoaded = true + + local timer = GetGameTimer() + while not HaveAllStreamingRequestsCompleted(ESX.PlayerData.ped) and (GetGameTimer() - timer) < 2000 do + Wait(0) + end + + Adjustments:Load() + + ClearPedTasksImmediately(ESX.PlayerData.ped) + + if not Config.Multichar then + Core.FreezePlayer(false) + end + + if IsScreenFadedOut() then + DoScreenFadeIn(500) + end + + Actions:Init() + StartPointsLoop() + StartServerSyncLoops() + NetworkSetLocalPlayerSyncLookAt(true) +end) + +local isFirstSpawn = true +ESX.SecureNetEvent("esx:onPlayerLogout", function() + ESX.PlayerLoaded = false + isFirstSpawn = true +end) + +ESX.SecureNetEvent("esx:setMaxWeight", function(newMaxWeight) + ESX.SetPlayerData("maxWeight", newMaxWeight) +end) + +ESX.SecureNetEvent("esx:setInventory", function(newInventory) + ESX.SetPlayerData("inventory", newInventory) +end) + +local function onPlayerSpawn() + ESX.SetPlayerData("ped", PlayerPedId()) + ESX.SetPlayerData("dead", false) +end + +AddEventHandler("playerSpawned", onPlayerSpawn) +AddEventHandler("esx:onPlayerSpawn", function() + onPlayerSpawn() + + if isFirstSpawn then + isFirstSpawn = false + + if ESX.PlayerData.metadata.health and (ESX.PlayerData.metadata.health > 0 or Config.SaveDeathStatus) then + SetEntityHealth(ESX.PlayerData.ped, ESX.PlayerData.metadata.health) + end + + if ESX.PlayerData.metadata.armor and ESX.PlayerData.metadata.armor > 0 then + SetPedArmour(ESX.PlayerData.ped, ESX.PlayerData.metadata.armor) + end + end +end) + +AddEventHandler("esx:onPlayerDeath", function() + ESX.SetPlayerData("ped", PlayerPedId()) + ESX.SetPlayerData("dead", true) +end) + +AddEventHandler("skinchanger:modelLoaded", function() + while not ESX.PlayerLoaded do + Wait(100) + end + TriggerEvent("esx:restoreLoadout") +end) + +AddEventHandler("esx:restoreLoadout", function() + ESX.SetPlayerData("ped", PlayerPedId()) + + if not Config.CustomInventory then + local ammoTypes = {} + RemoveAllPedWeapons(ESX.PlayerData.ped, true) + + for _, v in ipairs(ESX.PlayerData.loadout) do + local weaponName = v.name + local weaponHash = joaat(weaponName) + + GiveWeaponToPed(ESX.PlayerData.ped, weaponHash, 0, false, false) + SetPedWeaponTintIndex(ESX.PlayerData.ped, weaponHash, v.tintIndex) + + local ammoType = GetPedAmmoTypeFromWeapon(ESX.PlayerData.ped, weaponHash) + + for _, v2 in ipairs(v.components) do + local componentHash = ESX.GetWeaponComponent(weaponName, v2).hash + GiveWeaponComponentToPed(ESX.PlayerData.ped, weaponHash, componentHash) + end + + if not ammoTypes[ammoType] then + AddAmmoToPed(ESX.PlayerData.ped, weaponHash, v.ammo) + ammoTypes[ammoType] = true + end + end + end +end) + +---@diagnostic disable-next-line: param-type-mismatch +AddStateBagChangeHandler("VehicleProperties", nil, function(bagName, _, value) + if not value then + return + end + + bagName = bagName:gsub("entity:", "") + local netId = tonumber(bagName) + if not netId then + error("Tried to set vehicle properties with invalid netId") + return + end + + local tries = 0 + + while not NetworkDoesEntityExistWithNetworkId(netId) do + Wait(200) + tries = tries + 1 + if tries > 20 then + return error(("Invalid entity - ^5%s^7!"):format(netId)) + end + end + + local vehicle = NetToVeh(netId) + + if NetworkGetEntityOwner(vehicle) ~= ESX.playerId then + return + end + + ESX.Game.SetVehicleProperties(vehicle, value) +end) + +ESX.SecureNetEvent("esx:setAccountMoney", function(account) + for i = 1, #ESX.PlayerData.accounts do + if ESX.PlayerData.accounts[i].name == account.name then + ESX.PlayerData.accounts[i] = account + break + end + end + + ESX.SetPlayerData("accounts", ESX.PlayerData.accounts) +end) + +if not Config.CustomInventory then + ESX.SecureNetEvent("esx:addInventoryItem", function(item, count, showNotification) + for k, v in ipairs(ESX.PlayerData.inventory) do + if v.name == item then + ESX.UI.ShowInventoryItemNotification(true, v.label, count - v.count) + ESX.PlayerData.inventory[k].count = count + break + end + end + + if showNotification then + ESX.UI.ShowInventoryItemNotification(true, item, count) + end + end) + + ESX.SecureNetEvent("esx:removeInventoryItem", function(item, count, showNotification) + for i = 1, #ESX.PlayerData.inventory do + if ESX.PlayerData.inventory[i].name == item then + ESX.UI.ShowInventoryItemNotification(false, ESX.PlayerData.inventory[i].label, ESX.PlayerData.inventory[i].count - count) + ESX.PlayerData.inventory[i].count = count + break + end + end + + if showNotification then + ESX.UI.ShowInventoryItemNotification(false, item, count) + end + end) + + ESX.SecureNetEvent("esx:addLoadoutItem", function(weaponName, weaponLabel, ammo) + table.insert(ESX.PlayerData.loadout, { + name = weaponName, + ammo = ammo, + label = weaponLabel, + components = {}, + tintIndex = 0, + }) + end) + + ESX.SecureNetEvent("esx:removeLoadoutItem", function(weaponName, weaponLabel) + for i = 1, #ESX.PlayerData.loadout do + if ESX.PlayerData.loadout[i].name == weaponName then + table.remove(ESX.PlayerData.loadout, i) + break + end + end + end) + + RegisterNetEvent("esx:addWeapon", function() + error("event ^5'esx:addWeapon'^1 Has Been Removed. Please use ^5xPlayer.addWeapon^1 Instead!") + end) + + + RegisterNetEvent("esx:addWeaponComponent", function() + error("event ^5'esx:addWeaponComponent'^1 Has Been Removed. Please use ^5xPlayer.addWeaponComponent^1 Instead!") + end) + + RegisterNetEvent("esx:setWeaponAmmo", function() + error("event ^5'esx:setWeaponAmmo'^1 Has Been Removed. Please use ^5xPlayer.addWeaponAmmo^1 Instead!") + end) + + ESX.SecureNetEvent("esx:setWeaponTint", function(weapon, weaponTintIndex) + SetPedWeaponTintIndex(ESX.PlayerData.ped, joaat(weapon), weaponTintIndex) + end) + + RegisterNetEvent("esx:removeWeapon", function() + error("event ^5'esx:removeWeapon'^1 Has Been Removed. Please use ^5xPlayer.removeWeapon^1 Instead!") + end) + + ESX.SecureNetEvent("esx:removeWeaponComponent", function(weapon, weaponComponent) + local componentHash = ESX.GetWeaponComponent(weapon, weaponComponent).hash + RemoveWeaponComponentFromPed(ESX.PlayerData.ped, joaat(weapon), componentHash) + end) +end + +ESX.SecureNetEvent("esx:setJob", function(Job) + ESX.SetPlayerData("job", Job) +end) + +ESX.SecureNetEvent("esx:setGroup", function(group) + ESX.SetPlayerData("group", group) +end) + +if not Config.CustomInventory then + ESX.SecureNetEvent("esx:createPickup", function(pickupId, label, coords, itemType, name, components, tintIndex) + local function setObjectProperties(object) + SetEntityAsMissionEntity(object, true, false) + PlaceObjectOnGroundProperly(object) + FreezeEntityPosition(object, true) + SetEntityCollision(object, false, true) + + pickups[pickupId] = { + obj = object, + label = label, + inRange = false, + coords = coords, + } + end + + if itemType == "item_weapon" then + local weaponHash = joaat(name) + ESX.Streaming.RequestWeaponAsset(weaponHash) + local pickupObject = CreateWeaponObject(weaponHash, 50, coords.x, coords.y, coords.z, true, 1.0, 0) + SetWeaponObjectTintIndex(pickupObject, tintIndex) + + for _, v in ipairs(components) do + local component = ESX.GetWeaponComponent(name, v) + if component then + GiveWeaponComponentToWeaponObject(pickupObject, component.hash) + end + end + + setObjectProperties(pickupObject) + else + ESX.Game.SpawnLocalObject("prop_money_bag_01", coords, setObjectProperties) + end + end) + + ESX.SecureNetEvent("esx:createMissingPickups", function(missingPickups) + for pickupId, pickup in pairs(missingPickups) do + TriggerEvent("esx:createPickup", pickupId, pickup.label, vector3(pickup.coords.x, pickup.coords.y, pickup.coords.z - 1.0), pickup.type, pickup.name, pickup.components, pickup.tintIndex) + end + end) +end + +ESX.SecureNetEvent("esx:registerSuggestions", function(registeredCommands) + for name, command in pairs(registeredCommands) do + if command.suggestion then + TriggerEvent("chat:addSuggestion", ("/%s"):format(name), command.suggestion.help, command.suggestion.arguments) + end + end +end) + +if not Config.CustomInventory then + ESX.SecureNetEvent("esx:removePickup", function(pickupId) + if pickups[pickupId] and pickups[pickupId].obj then + ESX.Game.DeleteObject(pickups[pickupId].obj) + pickups[pickupId] = nil + end + end) +end + +function StartServerSyncLoops() + if Config.CustomInventory then return end + + local currentWeapon = { + ---@type number + ---@diagnostic disable-next-line: assign-type-mismatch + hash = `WEAPON_UNARMED`, + ammo = 0, + } + + local function updateCurrentWeaponAmmo(weaponName) + local newAmmo = GetAmmoInPedWeapon(ESX.PlayerData.ped, currentWeapon.hash) + + if newAmmo ~= currentWeapon.ammo then + currentWeapon.ammo = newAmmo + TriggerServerEvent("esx:updateWeaponAmmo", weaponName, newAmmo) + end + end + + CreateThread(function() + while ESX.PlayerLoaded do + currentWeapon.hash = GetSelectedPedWeapon(ESX.PlayerData.ped) + + if currentWeapon.hash ~= `WEAPON_UNARMED` then + local weaponConfig = ESX.GetWeaponFromHash(currentWeapon.hash) + + if weaponConfig then + currentWeapon.ammo = GetAmmoInPedWeapon(ESX.PlayerData.ped, currentWeapon.hash) + + while GetSelectedPedWeapon(ESX.PlayerData.ped) == currentWeapon.hash do + updateCurrentWeaponAmmo(weaponConfig.name) + Wait(1000) + end + + updateCurrentWeaponAmmo(weaponConfig.name) + end + end + Wait(250) + end + end) + + CreateThread(function() + local PARACHUTE_OPENING = 1 + local PARACHUTE_OPEN = 2 + + while ESX.PlayerLoaded do + local parachuteState = GetPedParachuteState(ESX.PlayerData.ped) + + if parachuteState == PARACHUTE_OPENING or parachuteState == PARACHUTE_OPEN then + TriggerServerEvent("esx:updateWeaponAmmo", "GADGET_PARACHUTE", 0) + + while GetPedParachuteState(ESX.PlayerData.ped) ~= -1 do Wait(1000) end + end + Wait(500) + end + end) +end + +if not Config.CustomInventory then + CreateThread(function() + while true do + local Sleep = 1500 + local playerCoords = GetEntityCoords(ESX.PlayerData.ped) + local _, closestDistance = ESX.Game.GetClosestPlayer(playerCoords) + + for pickupId, pickup in pairs(pickups) do + local distance = #(playerCoords - pickup.coords) + + if distance < 5 then + Sleep = 0 + local label = pickup.label + + if distance < 1 then + if IsControlJustReleased(0, 38) then + if IsPedOnFoot(ESX.PlayerData.ped) and (closestDistance == -1 or closestDistance > 3) and not pickup.inRange then + pickup.inRange = true + + local dict, anim = "weapons@first_person@aim_rng@generic@projectile@sticky_bomb@", "plant_floor" + ESX.Streaming.RequestAnimDict(dict) + TaskPlayAnim(ESX.PlayerData.ped, dict, anim, 8.0, 1.0, 1000, 16, 0.0, false, false, false) + RemoveAnimDict(dict) + Wait(1000) + + TriggerServerEvent("esx:onPickup", pickupId) + PlaySoundFrontend(-1, "PICK_UP", "HUD_FRONTEND_DEFAULT_SOUNDSET", false) + end + end + + label = ("%s~n~%s"):format(label, TranslateCap("threw_pickup_prompt")) + end + + local textCoords = pickup.coords + vector3(0.0, 0.0, 0.25) + ESX.Game.Utils.DrawText3D(textCoords, label, 1.2, 1) + elseif pickup.inRange then + pickup.inRange = false + end + end + Wait(Sleep) + end + end) +end + +----- Admin commands from esx_adminplus +RegisterNetEvent("esx:tpm", function() + local GetEntityCoords = GetEntityCoords + local GetGroundZFor_3dCoord = GetGroundZFor_3dCoord + local GetFirstBlipInfoId = GetFirstBlipInfoId + local DoesBlipExist = DoesBlipExist + local DoScreenFadeOut = DoScreenFadeOut + local GetBlipInfoIdCoord = GetBlipInfoIdCoord + local GetVehiclePedIsIn = GetVehiclePedIsIn + + ESX.TriggerServerCallback("esx:isUserAdmin", function(admin) + if not admin then + return + end + local blipMarker = GetFirstBlipInfoId(8) + if not DoesBlipExist(blipMarker) then + ESX.ShowNotification(TranslateCap("tpm_nowaypoint"), "error") + return "marker" + end + + -- Fade screen to hide how clients get teleported. + DoScreenFadeOut(650) + while not IsScreenFadedOut() do + Wait(0) + end + + local ped, coords = ESX.PlayerData.ped, GetBlipInfoIdCoord(blipMarker) + local vehicle = GetVehiclePedIsIn(ped, false) + local oldCoords = GetEntityCoords(ped) + + -- Unpack coords instead of having to unpack them while iterating. + -- 825.0 seems to be the max a player can reach while 0.0 being the lowest. + local x, y, groundZ, Z_START = coords["x"], coords["y"], 850.0, 950.0 + local found = false + FreezeEntityPosition(vehicle > 0 and vehicle or ped, true) + + for i = Z_START, 0, -25.0 do + local z = i + if (i % 2) ~= 0 then + z = Z_START - i + end + + NewLoadSceneStart(x, y, z, x, y, z, 50.0, 0) + local curTime = GetGameTimer() + while IsNetworkLoadingScene() do + if GetGameTimer() - curTime > 1000 then + break + end + Wait(0) + end + NewLoadSceneStop() + SetPedCoordsKeepVehicle(ped, x, y, z) + + while not HasCollisionLoadedAroundEntity(ped) do + RequestCollisionAtCoord(x, y, z) + if GetGameTimer() - curTime > 1000 then + break + end + Wait(0) + end + + -- Get ground coord. As mentioned in the natives, this only works if the client is in render distance. + found, groundZ = GetGroundZFor_3dCoord(x, y, z, false) + if found then + Wait(0) + SetPedCoordsKeepVehicle(ped, x, y, groundZ) + break + end + Wait(0) + end + + -- Remove black screen once the loop has ended. + DoScreenFadeIn(650) + FreezeEntityPosition(vehicle > 0 and vehicle or ped, false) + + if not found then + -- If we can't find the coords, set the coords to the old ones. + -- We don't unpack them before since they aren't in a loop and only called once. + SetPedCoordsKeepVehicle(ped, oldCoords["x"], oldCoords["y"], oldCoords["z"] - 1.0) + ESX.ShowNotification(TranslateCap("tpm_success"), "success") + end + + -- If Z coord was found, set coords in found coords. + SetPedCoordsKeepVehicle(ped, x, y, groundZ) + ESX.ShowNotification(TranslateCap("tpm_success"), "success") + end) +end) + +local noclip = false +local noclip_pos = vector3(0, 0, 70) +local heading = 0 + +local function noclipThread() + while noclip do + SetEntityCoordsNoOffset(ESX.PlayerData.ped, noclip_pos.x, noclip_pos.y, noclip_pos.z, false, false, true) + + if IsControlPressed(1, 34) then + heading = heading + 1.5 + if heading > 360 then + heading = 0 + end + + SetEntityHeading(ESX.PlayerData.ped, heading) + end + + if IsControlPressed(1, 9) then + heading = heading - 1.5 + if heading < 0 then + heading = 360 + end + + SetEntityHeading(ESX.PlayerData.ped, heading) + end + + if IsControlPressed(1, 8) then + noclip_pos = GetOffsetFromEntityInWorldCoords(ESX.PlayerData.ped, 0.0, 1.0, 0.0) + end + + if IsControlPressed(1, 32) then + noclip_pos = GetOffsetFromEntityInWorldCoords(ESX.PlayerData.ped, 0.0, -1.0, 0.0) + end + + if IsControlPressed(1, 27) then + noclip_pos = GetOffsetFromEntityInWorldCoords(ESX.PlayerData.ped, 0.0, 0.0, 1.0) + end + + if IsControlPressed(1, 173) then + noclip_pos = GetOffsetFromEntityInWorldCoords(ESX.PlayerData.ped, 0.0, 0.0, -1.0) + end + Wait(0) + end +end + +RegisterNetEvent("esx:noclip", function() + ESX.TriggerServerCallback("esx:isUserAdmin", function(admin) + if not admin then + return + end + + if not noclip then + noclip_pos = GetEntityCoords(ESX.PlayerData.ped, false) + heading = GetEntityHeading(ESX.PlayerData.ped) + end + + noclip = not noclip + if noclip then + CreateThread(noclipThread) + end + + if noclip then + ESX.ShowNotification(TranslateCap("noclip_message", Translate("enabled")), "success") + else + ESX.ShowNotification(TranslateCap("noclip_message", Translate("disabled")), "error") + end + end) +end) + +RegisterNetEvent("esx:killPlayer", function() + SetEntityHealth(ESX.PlayerData.ped, 0) +end) + +RegisterNetEvent("esx:repairPedVehicle", function() + local ped = ESX.PlayerData.ped + local vehicle = GetVehiclePedIsIn(ped, false) + SetVehicleEngineHealth(vehicle, 1000) + SetVehicleEngineOn(vehicle, true, true, false) + SetVehicleFixed(vehicle) + SetVehicleDirtLevel(vehicle, 0) +end) + +RegisterNetEvent("esx:freezePlayer", function(input) + if input == "freeze" then + SetEntityCollision(ESX.PlayerData.ped, false, false) + FreezeEntityPosition(ESX.PlayerData.ped, true) + SetPlayerInvincible(ESX.playerId, true) + elseif input == "unfreeze" then + SetEntityCollision(ESX.PlayerData.ped, true, true) + FreezeEntityPosition(ESX.PlayerData.ped, false) + SetPlayerInvincible(ESX.playerId, false) + end +end) + +ESX.RegisterClientCallback("esx:GetVehicleType", function(cb, model) + cb(ESX.GetVehicleTypeClient(model)) +end) + +ESX.SecureNetEvent('esx:updatePlayerData', function(key, val) + ESX.SetPlayerData(key, val) +end) + +---@param command string +ESX.SecureNetEvent("esx:executeCommand", function(command) + ExecuteCommand(command) +end) + +AddEventHandler("onResourceStop", function(resource) + if Core.Events[resource] then + for i = 1, #Core.Events[resource] do + RemoveEventHandler(Core.Events[resource][i]) + end + end +end) diff --git a/resources/[core]/es_extended/client/modules/interactions.lua b/resources/[core]/es_extended/client/modules/interactions.lua new file mode 100644 index 0000000..0a1a31f --- /dev/null +++ b/resources/[core]/es_extended/client/modules/interactions.lua @@ -0,0 +1,38 @@ +local interactions = {} +local pressedInteractions = {} + +function ESX.RemoveInteraction(name) + if not interactions[name] then return end + interactions[name] = nil +end + +ESX.RegisterInteraction = function(name, onPress, condition) + interactions[name] = { + condition = condition or function() return true end, + onPress = onPress, + creator = GetInvokingResource() or "es_extended" + } +end + +function ESX.GetInteractKey() + local hash = joaat('esx_interact') | 0x80000000 + return GetControlInstructionalButton(0, hash, true):sub(3) +end + +ESX.RegisterInput("esx_interact", "Interact", "keyboard", "e", function() + for _, interaction in pairs(interactions) do + local success, result = pcall(interaction.condition) + if success and result then + pressedInteractions[#pressedInteractions+1] = interaction + interaction.onPress() + end + end +end) + +AddEventHandler("onResourceStop", function(resource) + for name, interaction in pairs(interactions) do + if interaction.creator == resource then + interactions[name] = nil + end + end +end) \ No newline at end of file diff --git a/resources/[core]/es_extended/client/modules/npwd.lua b/resources/[core]/es_extended/client/modules/npwd.lua new file mode 100644 index 0000000..a1aa73a --- /dev/null +++ b/resources/[core]/es_extended/client/modules/npwd.lua @@ -0,0 +1,57 @@ +local npwd = GetResourceState("npwd"):find("start") and exports.npwd or nil + +local function checkPhone() + if not npwd then + return + end + + local phoneItem = ESX.SearchInventory("phone") + npwd:setPhoneDisabled((phoneItem and phoneItem.count or 0) <= 0) +end + +RegisterNetEvent("esx:playerLoaded", checkPhone) + +AddEventHandler("onClientResourceStart", function(resource) + if resource ~= "npwd" then + return + end + + npwd = GetResourceState("npwd"):find("start") and exports.npwd or nil + + if ESX.PlayerLoaded then + checkPhone() + end +end) + +AddEventHandler("onClientResourceStop", function(resource) + if resource == "npwd" then + npwd = nil + end +end) + +ESX.SecureNetEvent("esx:onPlayerLogout", function() + if not npwd then + return + end + + npwd:setPhoneVisible(false) + npwd:setPhoneDisabled(true) +end) + +ESX.SecureNetEvent("esx:removeInventoryItem", function(item, count) + if not npwd then + return + end + + if item == "phone" and count == 0 then + npwd:setPhoneDisabled(true) + end +end) + +ESX.SecureNetEvent("esx:addInventoryItem", function(item) + if not npwd or item ~= "phone" then + return + end + + npwd:setPhoneDisabled(false) +end) diff --git a/resources/[core]/es_extended/client/modules/points.lua b/resources/[core]/es_extended/client/modules/points.lua new file mode 100644 index 0000000..21f7911 --- /dev/null +++ b/resources/[core]/es_extended/client/modules/points.lua @@ -0,0 +1,54 @@ +local points = {} + +function ESX.CreatePointInternal(coords, distance, hidden, enter, leave) + local point = { + coords = coords, + distance = distance, + hidden = hidden, + enter = enter, + leave = leave, + resource = GetInvokingResource() + } + local handle = ESX.Table.SizeOf(points) + 1 + points[handle] = point + return handle +end + +function ESX.RemovePointInternal(handle) + points[handle] = nil +end + +function ESX.HidePointInternal(handle, hidden) + if points[handle] then + points[handle].hidden = hidden + end +end + +function StartPointsLoop() + CreateThread(function() + while true do + local coords = GetEntityCoords(ESX.PlayerData.ped) + for handle, point in pairs(points) do + if not point.hidden and #(coords - point.coords) <= point.distance then + if not point.nearby then + points[handle].nearby = true + points[handle].enter() + end + elseif point.nearby then + points[handle].nearby = false + points[handle].leave() + end + end + Wait(500) + end + end) +end + + +AddEventHandler('onResourceStop', function(resource) + for handle, point in pairs(points) do + if point.resource == resource then + points[handle] = nil + end + end +end) \ No newline at end of file diff --git a/resources/[core]/es_extended/client/modules/scaleform.lua b/resources/[core]/es_extended/client/modules/scaleform.lua new file mode 100644 index 0000000..0662f9c --- /dev/null +++ b/resources/[core]/es_extended/client/modules/scaleform.lua @@ -0,0 +1,99 @@ +ESX.Scaleform = {} +ESX.Scaleform.Utils = {} + +function ESX.Scaleform.ShowFreemodeMessage(title, msg, sec) + local scaleform = ESX.Scaleform.Utils.RunMethod("MP_BIG_MESSAGE_FREEMODE", "SHOW_SHARD_WASTED_MP_MESSAGE", false, title, msg) + + local endTime = GetGameTimer() + (sec * 1000) + while GetGameTimer() < endTime do + Wait(0) + DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0) + end + + SetScaleformMovieAsNoLongerNeeded(scaleform) +end + +function ESX.Scaleform.ShowBreakingNews(title, msg, bottom, sec) + local scaleform = ESX.Scaleform.Utils.RunMethod("BREAKING_NEWS", "SET_TEXT", false, msg, bottom) + ESX.Scaleform.Utils.RunMethod(scaleform, "SET_SCROLL_TEXT", false, 0, 0, title) + ESX.Scaleform.Utils.RunMethod(scaleform, "DISPLAY_SCROLL_TEXT", false, 0, 0) + + local endTime = GetGameTimer() + (sec * 1000) + while GetGameTimer() < endTime do + Wait(0) + DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0) + end + + SetScaleformMovieAsNoLongerNeeded(scaleform) +end + +function ESX.Scaleform.ShowPopupWarning(title, msg, bottom, sec) + local scaleform = ESX.Scaleform.Utils.RunMethod("POPUP_WARNING", "SHOW_POPUP_WARNING", false, 500.0, title, msg, bottom, true) + + local endTime = GetGameTimer() + (sec * 1000) + while GetGameTimer() < endTime do + Wait(0) + DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0) + end + + SetScaleformMovieAsNoLongerNeeded(scaleform) +end + +function ESX.Scaleform.ShowTrafficMovie(sec) + local scaleform = ESX.Scaleform.Utils.RunMethod("TRAFFIC_CAM", "PLAY_CAM_MOVIE", false) + + local endTime = GetGameTimer() + (sec * 1000) + while GetGameTimer() < endTime do + Wait(0) + DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0) + end + + SetScaleformMovieAsNoLongerNeeded(scaleform) +end + +function ESX.Scaleform.Utils.RequestScaleformMovie(movie) + local scaleform = RequestScaleformMovie(movie) + + while not HasScaleformMovieLoaded(scaleform) do + Wait(0) + end + + return scaleform +end + +--- Executes a method on a scaleform movie with optional arguments and return value. +--- The caller is responsible for disposing of the scaleform using `SetScaleformMovieAsNoLongerNeeded`. +---@param scaleform number|string # Scaleform handle or name to request the scaleform movie +---@param methodName string # The method name to call on the scaleform +---@param returnValue? boolean # Whether to return the value from the method +---@param ... number|string|boolean # Arguments to pass to the method +---@return number, number? # The scaleform handle, and the return value if `returnValue` is true +function ESX.Scaleform.Utils.RunMethod(scaleform, methodName, returnValue, ...) + scaleform = type(scaleform) == "number" and scaleform or ESX.Scaleform.Utils.RequestScaleformMovie(scaleform) + BeginScaleformMovieMethod(scaleform, methodName) + + local args = { ... } + for _, arg in ipairs(args) do + local typeArg = type(arg) + + if typeArg == "number" then + if math.type(arg) == "float" then + ScaleformMovieMethodAddParamFloat(arg) + else + ScaleformMovieMethodAddParamInt(arg) + end + elseif typeArg == "string" then + ScaleformMovieMethodAddParamTextureNameString(arg) + elseif typeArg == "boolean" then + ScaleformMovieMethodAddParamBool(arg) + end + end + + if returnValue then + return scaleform, EndScaleformMovieMethodReturnValue() + end + + EndScaleformMovieMethod() + + return scaleform +end diff --git a/resources/[core]/es_extended/client/modules/streaming.lua b/resources/[core]/es_extended/client/modules/streaming.lua new file mode 100644 index 0000000..8614c4f --- /dev/null +++ b/resources/[core]/es_extended/client/modules/streaming.lua @@ -0,0 +1,70 @@ +ESX.Streaming = {} + +---@param modelHash number | string +---@param cb? function +---@return number | nil +function ESX.Streaming.RequestModel(modelHash, cb) + modelHash = type(modelHash) == "number" and modelHash or joaat(modelHash) + + if not IsModelInCdimage(modelHash) then return end + + RequestModel(modelHash) + while not HasModelLoaded(modelHash) do Wait(500) end + + return cb and cb(modelHash) or modelHash +end + +---@param textureDict string +---@param cb? function +---@return string | nil +function ESX.Streaming.RequestStreamedTextureDict(textureDict, cb) + RequestStreamedTextureDict(textureDict, false) + + while not HasStreamedTextureDictLoaded(textureDict) do Wait(500) end + + return cb and cb(textureDict) or textureDict +end + +---@param assetName string +---@param cb? function +---@return string | nil +function ESX.Streaming.RequestNamedPtfxAsset(assetName, cb) + RequestNamedPtfxAsset(assetName) + + while not HasNamedPtfxAssetLoaded(assetName) do Wait(500) end + + return cb and cb(assetName) or assetName +end + +---@param animSet string +---@param cb? function +---@return string | nil +function ESX.Streaming.RequestAnimSet(animSet, cb) + RequestAnimSet(animSet) + + while not HasAnimSetLoaded(animSet) do Wait(500) end + + return cb and cb(animSet) or animSet +end + +---@param animDict string +---@param cb? function +---@return string | nil +function ESX.Streaming.RequestAnimDict(animDict, cb) + RequestAnimDict(animDict) + + while not HasAnimDictLoaded(animDict) do Wait(500) end + + return cb and cb(animDict) or animDict +end + +---@param weaponHash number | string +---@param cb? function +---@return string | number | nil +function ESX.Streaming.RequestWeaponAsset(weaponHash, cb) + RequestWeaponAsset(weaponHash, 31, 0) + + while not HasWeaponAssetLoaded(weaponHash) do Wait(500) end + + return cb and cb(weaponHash) or weaponHash +end diff --git a/resources/[core]/es_extended/client/modules/wrapper.lua b/resources/[core]/es_extended/client/modules/wrapper.lua new file mode 100644 index 0000000..10247fe --- /dev/null +++ b/resources/[core]/es_extended/client/modules/wrapper.lua @@ -0,0 +1,14 @@ +local Chunks = {} + +RegisterNUICallback("__chunk", function(data, cb) + Chunks[data.id] = Chunks[data.id] or "" + Chunks[data.id] = Chunks[data.id] .. data.chunk + + if data["end"] then + local msg = json.decode(Chunks[data.id]) + TriggerEvent(GetCurrentResourceName() .. ":message:" .. data.__type, msg) + Chunks[data.id] = nil + end + + cb("") +end) diff --git a/resources/[core]/es_extended/es_extended.sql b/resources/[core]/es_extended/es_extended.sql new file mode 100644 index 0000000..b454611 --- /dev/null +++ b/resources/[core]/es_extended/es_extended.sql @@ -0,0 +1,59 @@ +CREATE DATABASE IF NOT EXISTS `es_extended`; + +ALTER DATABASE `es_extended` + DEFAULT CHARACTER SET UTF8MB4; + +ALTER DATABASE `es_extended` + DEFAULT COLLATE UTF8MB4_UNICODE_CI; + +USE `es_extended`; + +CREATE TABLE `users` ( + `identifier` VARCHAR(60) NOT NULL, + `ssn` VARCHAR(11) NOT NULL, + `accounts` LONGTEXT NULL DEFAULT NULL, + `group` VARCHAR(50) NULL DEFAULT 'user', + `inventory` LONGTEXT NULL DEFAULT NULL, + `job` VARCHAR(20) NULL DEFAULT 'unemployed', + `job_grade` INT NULL DEFAULT 0, + `loadout` LONGTEXT NULL DEFAULT NULL, + `metadata` LONGTEXT NULL DEFAULT NULL, + `position` longtext NULL DEFAULT NULL, + + PRIMARY KEY (`identifier`), + UNIQUE KEY `unique_ssn` (`ssn`) +) ENGINE=InnoDB; + +CREATE TABLE `items` ( + `name` VARCHAR(50) NOT NULL, + `label` VARCHAR(50) NOT NULL, + `weight` INT NOT NULL DEFAULT 1, + `rare` TINYINT NOT NULL DEFAULT 0, + `can_remove` TINYINT NOT NULL DEFAULT 1, + + PRIMARY KEY (`name`) +) ENGINE=InnoDB; + +CREATE TABLE `job_grades` ( + `id` INT NOT NULL AUTO_INCREMENT, + `job_name` VARCHAR(50) DEFAULT NULL, + `grade` INT NOT NULL, + `name` VARCHAR(50) NOT NULL, + `label` VARCHAR(50) NOT NULL, + `salary` INT NOT NULL, + `skin_male` LONGTEXT NOT NULL, + `skin_female` LONGTEXT NOT NULL, + + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +INSERT INTO `job_grades` VALUES (1,'unemployed',0,'unemployed','Unemployed',200,'{}','{}'); + +CREATE TABLE `jobs` ( + `name` VARCHAR(50) NOT NULL, + `label` VARCHAR(50) DEFAULT NULL, + + PRIMARY KEY (`name`) +) ENGINE=InnoDB; + +INSERT INTO `jobs` VALUES ('unemployed','Unemployed'); diff --git a/resources/[core]/es_extended/fxmanifest.lua b/resources/[core]/es_extended/fxmanifest.lua new file mode 100644 index 0000000..f7164c6 --- /dev/null +++ b/resources/[core]/es_extended/fxmanifest.lua @@ -0,0 +1,87 @@ +fx_version 'cerulean' + +game 'gta5' +description 'The Core resource that provides the functionalities for all other resources.' +lua54 'yes' +version '1.13.5' + +shared_scripts { + 'locale.lua', + + 'shared/config/main.lua', + 'shared/config/weapons.lua', + 'shared/config/adjustments.lua', + + 'shared/main.lua', + 'shared/functions.lua', + 'shared/modules/*.lua', +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'shared/config/logs.lua', + + 'server/core.lua', + 'server/functions.lua', + 'server/common.lua', + 'server/modules/callback.lua', + 'server/classes/player.lua', + 'server/classes/vehicle.lua', + 'server/classes/overrides/*.lua', + 'server/modules/onesync.lua', + 'server/modules/paycheck.lua', + + 'server/main.lua', + 'server/modules/commands.lua', + + 'server/bridge/**/*.lua', + 'server/modules/npwd.lua', + 'server/modules/createJob.lua', + 'server/migration/**/main.lua', + 'server/migration/main.lua', +} + +client_scripts { + 'client/main.lua', + 'client/functions.lua', + 'client/modules/wrapper.lua', + 'client/modules/callback.lua', + 'client/modules/adjustments.lua', + 'client/modules/points.lua', + + 'client/modules/events.lua', + + 'client/modules/actions.lua', + 'client/modules/death.lua', + 'client/modules/npwd.lua', + 'client/modules/interactions.lua', + 'client/modules/scaleform.lua', + 'client/modules/streaming.lua', +} + +ui_page { + 'html/ui.html' +} + +files { + 'imports.lua', + 'locales/*.lua', + 'locale.js', + 'html/ui.html', + + 'html/css/app.css', + + 'html/js/mustache.min.js', + 'html/js/wrapper.js', + 'html/js/app.js', + + 'html/fonts/pdown.ttf', + 'html/fonts/bankgothic.ttf', + "client/imports/*.lua", +} + +dependencies { + '/native:0x6AE51D4B', + '/native:0xA61C8FC6', + 'oxmysql', +} diff --git a/resources/[core]/es_extended/html/css/app.css b/resources/[core]/es_extended/html/css/app.css new file mode 100644 index 0000000..6d4b095 --- /dev/null +++ b/resources/[core]/es_extended/html/css/app.css @@ -0,0 +1,75 @@ +@font-face { + font-family: "Pricedown"; + src: url("../fonts/pdown.ttf"); +} + +@font-face { + font-family: "bankgothic"; + src: url("../fonts/bankgothic.ttf"); +} + +html { + overflow: hidden; +} + +#inventory_notifications { + font-family: bankgothic; + position: absolute; + right: 40; + bottom: 40; + font-size: 2em; + font-weight: bold; + color: #fff; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; +} + +.menu { + font-family: "Open Sans", sans-serif; + min-width: 400px; + min-height: 250px; + color: #fff; + position: absolute; + left: 40; + top: 0; +} + +.menu .head { + font-family: "Open Sans", sans-serif; + font-size: 28px; + padding: 10px; + background: #1a1a1a; + border-bottom: 3px solid #bc1635; + border-radius: 10px 10px 0 0; + -webkit-border-radius: 10px 10px 0 0; + -moz-border-radius: 10px 10px 0 0; + -o-border-radius: 10px 10px 0 0; + box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28); + -webkit-box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28); + -moz-box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28); + -o-box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28); + box-shadow: 1px 1px 10px 4px rgba(0, 0, 0, 0.4); +} + +.menu .head span { + font-family: "Pricedown"; + font-size: 28px; + padding-left: 15px; + padding-top: 6px; +} + +.menu .menu-items .menu-item { + font-family: "Open Sans", sans-serif; + font-size: 14px; + height: 40px; + display: block; + background-color: #f1f1f1; + box-shadow: inset 1px 0px 0px 1px #b8b8b8; + height: 32px; + line-height: 32px; + color: #3a3a3a; + text-align: center; +} + +.menu .menu-items .menu-item.selected { + background-color: #ccc; +} diff --git a/resources/[core]/es_extended/html/fonts/bankgothic.ttf b/resources/[core]/es_extended/html/fonts/bankgothic.ttf new file mode 100644 index 0000000..f3d8049 Binary files /dev/null and b/resources/[core]/es_extended/html/fonts/bankgothic.ttf differ diff --git a/resources/[core]/es_extended/html/fonts/pdown.ttf b/resources/[core]/es_extended/html/fonts/pdown.ttf new file mode 100644 index 0000000..69c76cf Binary files /dev/null and b/resources/[core]/es_extended/html/fonts/pdown.ttf differ diff --git a/resources/[core]/es_extended/html/js/app.js b/resources/[core]/es_extended/html/js/app.js new file mode 100644 index 0000000..4a95fe1 --- /dev/null +++ b/resources/[core]/es_extended/html/js/app.js @@ -0,0 +1,40 @@ +(() => { + ESX = {}; + + ESX.inventoryNotification = function (add, label, count) { + let notif = ""; + + if (add) { + notif += "+"; + } else { + notif += "-"; + } + + if (count) { + notif += count + " " + label; + } else { + notif += " " + label; + } + + let elem = $("

" + notif + "
"); + $("#inventory_notifications").append(elem); + + $(elem) + .delay(3000) + .fadeOut(1000, function () { + elem.remove(); + }); + }; + + window.onData = (data) => { + if (data.action === "inventoryNotification") { + ESX.inventoryNotification(data.add, data.item, data.count); + } + }; + + window.onload = function (e) { + window.addEventListener("message", (event) => { + onData(event.data); + }); + }; +})(); diff --git a/resources/[core]/es_extended/html/js/mustache.min.js b/resources/[core]/es_extended/html/js/mustache.min.js new file mode 100644 index 0000000..f365659 --- /dev/null +++ b/resources/[core]/es_extended/html/js/mustache.min.js @@ -0,0 +1,347 @@ +(function defineMustache(global, factory) { + if (typeof exports === "object" && exports && typeof exports.nodeName !== "string") { + factory(exports); + } else if (typeof define === "function" && define.amd) { + define(["exports"], factory); + } else { + global.Mustache = {}; + factory(global.Mustache); + } +})(this, function mustacheFactory(mustache) { + var objectToString = Object.prototype.toString; + var isArray = + Array.isArray || + function isArrayPolyfill(object) { + return objectToString.call(object) === "[object Array]"; + }; + function isFunction(object) { + return typeof object === "function"; + } + function typeStr(obj) { + return isArray(obj) ? "array" : typeof obj; + } + function escapeRegExp(string) { + return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); + } + function hasProperty(obj, propName) { + return obj != null && typeof obj === "object" && propName in obj; + } + var regExpTest = RegExp.prototype.test; + function testRegExp(re, string) { + return regExpTest.call(re, string); + } + var nonSpaceRe = /\S/; + function isWhitespace(string) { + return !testRegExp(nonSpaceRe, string); + } + var entityMap = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "/": "/", "`": "`", "=": "=" }; + function escapeHtml(string) { + return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap(s) { + return entityMap[s]; + }); + } + var whiteRe = /\s*/; + var spaceRe = /\s+/; + var equalsRe = /\s*=/; + var curlyRe = /\s*\}/; + var tagRe = /#|\^|\/|>|\{|&|=|!/; + function parseTemplate(template, tags) { + if (!template) return []; + var sections = []; + var tokens = []; + var spaces = []; + var hasTag = false; + var nonSpace = false; + function stripSpace() { + if (hasTag && !nonSpace) { + while (spaces.length) delete tokens[spaces.pop()]; + } else { + spaces = []; + } + hasTag = false; + nonSpace = false; + } + var openingTagRe, closingTagRe, closingCurlyRe; + function compileTags(tagsToCompile) { + if (typeof tagsToCompile === "string") tagsToCompile = tagsToCompile.split(spaceRe, 2); + if (!isArray(tagsToCompile) || tagsToCompile.length !== 2) throw new Error("Invalid tags: " + tagsToCompile); + openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + "\\s*"); + closingTagRe = new RegExp("\\s*" + escapeRegExp(tagsToCompile[1])); + closingCurlyRe = new RegExp("\\s*" + escapeRegExp("}" + tagsToCompile[1])); + } + compileTags(tags || mustache.tags); + var scanner = new Scanner(template); + var start, type, value, chr, token, openSection; + while (!scanner.eos()) { + start = scanner.pos; + value = scanner.scanUntil(openingTagRe); + if (value) { + for (var i = 0, valueLength = value.length; i < valueLength; ++i) { + chr = value.charAt(i); + if (isWhitespace(chr)) { + spaces.push(tokens.length); + } else { + nonSpace = true; + } + tokens.push(["text", chr, start, start + 1]); + start += 1; + if (chr === "\n") stripSpace(); + } + } + if (!scanner.scan(openingTagRe)) break; + hasTag = true; + type = scanner.scan(tagRe) || "name"; + scanner.scan(whiteRe); + if (type === "=") { + value = scanner.scanUntil(equalsRe); + scanner.scan(equalsRe); + scanner.scanUntil(closingTagRe); + } else if (type === "{") { + value = scanner.scanUntil(closingCurlyRe); + scanner.scan(curlyRe); + scanner.scanUntil(closingTagRe); + type = "&"; + } else { + value = scanner.scanUntil(closingTagRe); + } + if (!scanner.scan(closingTagRe)) throw new Error("Unclosed tag at " + scanner.pos); + token = [type, value, start, scanner.pos]; + tokens.push(token); + if (type === "#" || type === "^") { + sections.push(token); + } else if (type === "/") { + openSection = sections.pop(); + if (!openSection) throw new Error('Unopened section "' + value + '" at ' + start); + if (openSection[1] !== value) throw new Error('Unclosed section "' + openSection[1] + '" at ' + start); + } else if (type === "name" || type === "{" || type === "&") { + nonSpace = true; + } else if (type === "=") { + compileTags(value); + } + } + openSection = sections.pop(); + if (openSection) throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos); + return nestTokens(squashTokens(tokens)); + } + function squashTokens(tokens) { + var squashedTokens = []; + var token, lastToken; + for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { + token = tokens[i]; + if (token) { + if (token[0] === "text" && lastToken && lastToken[0] === "text") { + lastToken[1] += token[1]; + lastToken[3] = token[3]; + } else { + squashedTokens.push(token); + lastToken = token; + } + } + } + return squashedTokens; + } + function nestTokens(tokens) { + var nestedTokens = []; + var collector = nestedTokens; + var sections = []; + var token, section; + for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { + token = tokens[i]; + switch (token[0]) { + case "#": + case "^": + collector.push(token); + sections.push(token); + collector = token[4] = []; + break; + case "/": + section = sections.pop(); + section[5] = token[2]; + collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens; + break; + default: + collector.push(token); + } + } + return nestedTokens; + } + function Scanner(string) { + this.string = string; + this.tail = string; + this.pos = 0; + } + Scanner.prototype.eos = function eos() { + return this.tail === ""; + }; + Scanner.prototype.scan = function scan(re) { + var match = this.tail.match(re); + if (!match || match.index !== 0) return ""; + var string = match[0]; + this.tail = this.tail.substring(string.length); + this.pos += string.length; + return string; + }; + Scanner.prototype.scanUntil = function scanUntil(re) { + var index = this.tail.search(re), + match; + switch (index) { + case -1: + match = this.tail; + this.tail = ""; + break; + case 0: + match = ""; + break; + default: + match = this.tail.substring(0, index); + this.tail = this.tail.substring(index); + } + this.pos += match.length; + return match; + }; + function Context(view, parentContext) { + this.view = view; + this.cache = { ".": this.view }; + this.parent = parentContext; + } + Context.prototype.push = function push(view) { + return new Context(view, this); + }; + Context.prototype.lookup = function lookup(name) { + var cache = this.cache; + var value; + if (cache.hasOwnProperty(name)) { + value = cache[name]; + } else { + var context = this, + names, + index, + lookupHit = false; + while (context) { + if (name.indexOf(".") > 0) { + value = context.view; + names = name.split("."); + index = 0; + while (value != null && index < names.length) { + if (index === names.length - 1) lookupHit = hasProperty(value, names[index]); + value = value[names[index++]]; + } + } else { + value = context.view[name]; + lookupHit = hasProperty(context.view, name); + } + if (lookupHit) break; + context = context.parent; + } + cache[name] = value; + } + if (isFunction(value)) value = value.call(this.view); + return value; + }; + function Writer() { + this.cache = {}; + } + Writer.prototype.clearCache = function clearCache() { + this.cache = {}; + }; + Writer.prototype.parse = function parse(template, tags) { + var cache = this.cache; + var tokens = cache[template]; + if (tokens == null) tokens = cache[template] = parseTemplate(template, tags); + return tokens; + }; + Writer.prototype.render = function render(template, view, partials) { + var tokens = this.parse(template); + var context = view instanceof Context ? view : new Context(view); + return this.renderTokens(tokens, context, partials, template); + }; + Writer.prototype.renderTokens = function renderTokens(tokens, context, partials, originalTemplate) { + var buffer = ""; + var token, symbol, value; + for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { + value = undefined; + token = tokens[i]; + symbol = token[0]; + if (symbol === "#") value = this.renderSection(token, context, partials, originalTemplate); + else if (symbol === "^") value = this.renderInverted(token, context, partials, originalTemplate); + else if (symbol === ">") value = this.renderPartial(token, context, partials, originalTemplate); + else if (symbol === "&") value = this.unescapedValue(token, context); + else if (symbol === "name") value = this.escapedValue(token, context); + else if (symbol === "text") value = this.rawValue(token); + if (value !== undefined) buffer += value; + } + return buffer; + }; + Writer.prototype.renderSection = function renderSection(token, context, partials, originalTemplate) { + var self = this; + var buffer = ""; + var value = context.lookup(token[1]); + function subRender(template) { + return self.render(template, context, partials); + } + if (!value) return; + if (isArray(value)) { + for (var j = 0, valueLength = value.length; j < valueLength; ++j) { + buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate); + } + } else if (typeof value === "object" || typeof value === "string" || typeof value === "number") { + buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate); + } else if (isFunction(value)) { + if (typeof originalTemplate !== "string") throw new Error("Cannot use higher-order sections without the original template"); + value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender); + if (value != null) buffer += value; + } else { + buffer += this.renderTokens(token[4], context, partials, originalTemplate); + } + return buffer; + }; + Writer.prototype.renderInverted = function renderInverted(token, context, partials, originalTemplate) { + var value = context.lookup(token[1]); + if (!value || (isArray(value) && value.length === 0)) return this.renderTokens(token[4], context, partials, originalTemplate); + }; + Writer.prototype.renderPartial = function renderPartial(token, context, partials) { + if (!partials) return; + var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; + if (value != null) return this.renderTokens(this.parse(value), context, partials, value); + }; + Writer.prototype.unescapedValue = function unescapedValue(token, context) { + var value = context.lookup(token[1]); + if (value != null) return value; + }; + Writer.prototype.escapedValue = function escapedValue(token, context) { + var value = context.lookup(token[1]); + if (value != null) return mustache.escape(value); + }; + Writer.prototype.rawValue = function rawValue(token) { + return token[1]; + }; + mustache.name = "mustache.js"; + mustache.version = "2.3.0"; + mustache.tags = ["{{", "}}"]; + var defaultWriter = new Writer(); + mustache.clearCache = function clearCache() { + return defaultWriter.clearCache(); + }; + mustache.parse = function parse(template, tags) { + return defaultWriter.parse(template, tags); + }; + mustache.render = function render(template, view, partials) { + if (typeof template !== "string") { + throw new TypeError('Invalid template! Template should be a "string" ' + 'but "' + typeStr(template) + '" was given as the first ' + "argument for mustache#render(template, view, partials)"); + } + return defaultWriter.render(template, view, partials); + }; + mustache.to_html = function to_html(template, view, partials, send) { + var result = mustache.render(template, view, partials); + if (isFunction(send)) { + send(result); + } else { + return result; + } + }; + mustache.escape = escapeHtml; + mustache.Scanner = Scanner; + mustache.Context = Context; + mustache.Writer = Writer; + return mustache; +}); diff --git a/resources/[core]/es_extended/html/js/wrapper.js b/resources/[core]/es_extended/html/js/wrapper.js new file mode 100644 index 0000000..ee20f26 --- /dev/null +++ b/resources/[core]/es_extended/html/js/wrapper.js @@ -0,0 +1,34 @@ +(() => { + let ESXWrapper = {}; + ESXWrapper.MessageSize = 1024; + ESXWrapper.messageId = 0; + + window.SendMessage = function (namespace, type, msg) { + ESXWrapper.messageId = ESXWrapper.messageId < 65535 ? ESXWrapper.messageId + 1 : 0; + const str = JSON.stringify(msg); + + for (let i = 0; i < str.length; i++) { + let count = 0; + let chunk = ""; + + while (count < ESXWrapper.MessageSize && i < str.length) { + chunk += str[i]; + + count++; + i++; + } + + i--; + + const data = { + __type: type, + id: ESXWrapper.messageId, + chunk: chunk, + }; + + if (i === str.length - 1) data.end = true; + + $.post("http://" + namespace + "/__chunk", JSON.stringify(data)); + } + }; +})(); diff --git a/resources/[core]/es_extended/html/ui.html b/resources/[core]/es_extended/html/ui.html new file mode 100644 index 0000000..bbc9c00 --- /dev/null +++ b/resources/[core]/es_extended/html/ui.html @@ -0,0 +1,12 @@ + + + + + +
+ + + + + + diff --git a/resources/[core]/es_extended/imports.lua b/resources/[core]/es_extended/imports.lua new file mode 100644 index 0000000..95797ba --- /dev/null +++ b/resources/[core]/es_extended/imports.lua @@ -0,0 +1,346 @@ +ESX = exports["es_extended"]:getSharedObject() +ESX.currentResourceName = GetCurrentResourceName() + +OnPlayerData = function(key, val, last) end + +local function TrackPedCoordsOnce() + if not ESX or not ESX.PlayerData then + return + end + + ESX.PlayerData.coords = nil + + setmetatable(ESX.PlayerData, { + __index = function(self, key) + if key ~= "coords" then + return + end + + local coords = GetEntityCoords(ESX.PlayerData.ped) + + return coords + end + }) +end + +if not IsDuplicityVersion() then -- Only register this event for the client + AddEventHandler("esx:setPlayerData", function(key, val, last) + if GetInvokingResource() == "es_extended" then + ESX.PlayerData[key] = val + if OnPlayerData then + OnPlayerData(key, val, last) + end + end + end) + + RegisterNetEvent("esx:playerLoaded", function(xPlayer) + ESX.PlayerData = xPlayer + while not ESX.PlayerData.ped or not DoesEntityExist(ESX.PlayerData.ped) do Wait(0) end + ESX.PlayerLoaded = true + + TrackPedCoordsOnce() + end) + + TrackPedCoordsOnce() + + ESX.SecureNetEvent("esx:onPlayerLogout", function() + ESX.PlayerLoaded = false + ESX.PlayerData = {} + end) + + if not ESX.GetConfig("CustomInventory") then + ESX.SecureNetEvent("esx:addInventoryItem", function(item, count, showNotification) + for i = 1, #ESX.PlayerData.inventory do + if ESX.PlayerData.inventory[i].name == item then + ESX.PlayerData.inventory[i].count = count + break + end + end + end) + + ESX.SecureNetEvent("esx:removeInventoryItem", function(item, count, showNotification) + for i = 1, #ESX.PlayerData.inventory do + if ESX.PlayerData.inventory[i].name == item then + ESX.PlayerData.inventory[i].count = count + break + end + end + end) + + ESX.SecureNetEvent("esx:addLoadoutItem", function(weaponName, weaponLabel, ammo) + table.insert(ESX.PlayerData.loadout, { + name = weaponName, + ammo = ammo, + label = weaponLabel, + components = {}, + tintIndex = 0, + }) + end) + + ESX.SecureNetEvent("esx:removeLoadoutItem", function(weaponName, weaponLabel) + for i = 1, #ESX.PlayerData.loadout do + if ESX.PlayerData.loadout[i].name == weaponName then + table.remove(ESX.PlayerData.loadout, i) + break + end + end + end) + end + + local external = { { "Class", "class.lua" }, { "Point", "point.lua" } } + for i = 1, #external do + local module = external[i] + local path = string.format("client/imports/%s", module[2]) + + local file = LoadResourceFile("es_extended", path) + if file then + local fn, err = load(file, ('@@es_extended/%s'):format(path)) + + if not fn or err then + return error(('\n^1Error importing module (%s)'):format(external[i])) + end + + ESX[module[1]] = fn() + else + return error(('\n^1Error loading module (%s)'):format(external[i])) + end + end +else + ---@param src number + ---@return StaticPlayer + local function createStaticPlayer(src) + return setmetatable({ src = src }, { + __index = function(self, method) + return function(...) + return exports.es_extended:RunStaticPlayerMethod(self.src, method, ...) + end + end + }) + end + + ---@param src number|string + ---@return StaticPlayer? + function ESX.Player(src) + if type(src) ~= "number" then + src = ESX.GetPlayerIdFromIdentifier(src) + if not src then return end + elseif not ESX.IsPlayerLoaded(src) then + return + end + + return createStaticPlayer(src) + end + + ---@param key? string + ---@param val? string|string[] + ---@return StaticPlayer[] | table + function ESX.ExtendedPlayers(key, val) + local playerIds = ESX.GetExtendedPlayers(key, val, true) + + if key and type(val) == "table" then + ---@cast playerIds table + local retVal = {} + for group, ids in pairs(playerIds) do + retVal[group] = {} + for i = 1, #ids do + retVal[group][i] = createStaticPlayer(ids[i]) + end + end + return retVal + else + ---@cast playerIds number[] + local retVal = {} + for i = 1, #playerIds do + retVal[i] = createStaticPlayer(playerIds[i]) + end + return retVal + end + end +end + +if GetResourceState("ox_lib") == "missing" then + ---@Credits: https://github.com/overextended/ox_lib/blob/master/imports/require/shared.lua - Licensed under the GNU Lesser General Public License v3.0 + local loaded = {} + local _require = require + + package = { + path = './?.lua;./?/init.lua', + preload = {}, + loaded = setmetatable({}, { + __index = loaded, + __newindex = function() end, + __metatable = false, + }) + } + + ---@param modName string + ---@return string + ---@return string + local function getModuleInfo(modName) + local resource = modName:match('^@(.-)/.+') --[[@as string?]] + + if resource then + return resource, modName:sub(#resource + 3) + end + + local idx = 4 -- call stack depth (kept slightly lower than expected depth "just in case") + + while true do + local dbgInfo = debug.getinfo(idx, 'S') + local src = dbgInfo and dbgInfo.source + + if not src then + return ESX.currentResourceName, modName + end + + resource = src:match('^@@([^/]+)/.+') + + if resource and not src:find('^@@es_extended/imports') then + return resource, modName + end + + idx = idx + 1 + end + end + + local tempData = {} + + ---@param name string + ---@param path string + ---@return string? filename + ---@return string? errmsg + ---@diagnostic disable-next-line: duplicate-set-field + function package.searchpath(name, path) + local resource, modName = getModuleInfo(name:gsub('%.', '/')) + local tried = {} + + for template in path:gmatch('[^;]+') do + local fileName = template:gsub('^%./', ''):gsub('?', modName:gsub('%.', '/') or modName) + local file = LoadResourceFile(resource, fileName) + + if file then + tempData[1] = file + tempData[2] = resource + return fileName + end + + tried[#tried + 1] = ("no file '@%s/%s'"):format(resource, fileName) + end + + return nil, table.concat(tried, "\n\t") + end + + ---Attempts to load a module at the given path relative to the resource root directory.\ + ---Returns a function to load the module chunk, or a string containing all tested paths. + ---@param modName string + ---@param env? table + local function loadModule(modName, env) + local fileName, err = package.searchpath(modName, package.path) + + if fileName then + local file = tempData[1] + local resource = tempData[2] + + ESX.Table.Wipe(tempData) + return assert(load(file, ('@@%s/%s'):format(resource, fileName), 't', env or _ENV)) + end + + return nil, err or 'unknown error' + end + + ---@diagnostic disable-next-line: duplicate-doc-alias + ---@alias PackageSearcher + ---| fun(modName: string): function loader + ---| fun(modName: string): nil|false, string errmsg + + ---@type PackageSearcher[] + package.searchers = { + function(modName) + local ok, result = pcall(_require, modName) + + if ok then return result end + + return ok, result + end, + function(modName) + if package.preload[modName] ~= nil then + return package.preload[modName] + end + + return nil, ("no field package.preload['%s']"):format(modName) + end, + function(modName) return loadModule(modName) end, + } + + ---@param filePath string + ---@param env? table + ---@return unknown + ---Loads and runs a Lua file at the given path. Unlike require, the chunk is not cached for future use. + function ESX.load(filePath, env) + if type(filePath) ~= 'string' then + error(("file path must be a string (received '%s')"):format(filePath), 2) + end + + local result, err = loadModule(filePath, env) + + if result then return result() end + + error(("file '%s' not found\n\t%s"):format(filePath, err)) + end + + ---@param filePath string + ---@return table + ---Loads and decodes a json file at the given path. + function ESX.loadJson(filePath) + if type(filePath) ~= 'string' then + error(("file path must be a string (received '%s')"):format(filePath), 2) + end + + local resourceSrc, modPath = getModuleInfo(filePath:gsub('%.', '/')) + local resourceFile = LoadResourceFile(resourceSrc, ('%s.json'):format(modPath)) + + if resourceFile then + return json.decode(resourceFile) + end + + error(("json file '%s' not found\n\tno file '@%s/%s.json'"):format(filePath, resourceSrc, modPath)) + end + + ---Loads the given module, returns any value returned by the seacher (`true` when `nil`).\ + ---Passing `@resourceName.modName` loads a module from a remote resource. + ---@param modName string + ---@return unknown + function ESX.require(modName) + if type(modName) ~= 'string' then + error(("module name must be a string (received '%s')"):format(modName), 3) + end + + local module = loaded[modName] + + if module == '__loading' then + error(("^1circular-dependency occurred when loading module '%s'^0"):format(modName), 2) + end + + if module ~= nil then return module end + + loaded[modName] = '__loading' + + local err = {} + + for i = 1, #package.searchers do + local result, errMsg = package.searchers[i](modName) + if result then + if type(result) == 'function' then result = result() end + loaded[modName] = result or result == nil + + return loaded[modName] + end + + err[#err + 1] = errMsg + end + + error(("%s"):format(table.concat(err, "\n\t"))) + end + + require = ESX.require +end diff --git a/resources/[core]/es_extended/locale.js b/resources/[core]/es_extended/locale.js new file mode 100644 index 0000000..e47e434 --- /dev/null +++ b/resources/[core]/es_extended/locale.js @@ -0,0 +1,65 @@ +var locale = []; + +/** + * Similar to the concept of gettext, this function returns the + * localized string for the parsed string. The function supports + * wrapping. + * + * @param {string} args The string we want localized + * @return {string} Returns the localized string + * + */ +function _U() { + var args = arguments; + var string = args[0]; + + // Was a string specified? + if (!string) { + console.log('locale.js: no string was parsed'); + return 'locale.js: no string was parsed'; + } + + // Has the locale file been set? + if (locale.length === 0) { + console.log('locale.js: no locale has been set'); + return 'locale.js: no locale has been set'; + } + + // Does the translation exist? + if (!locale[string]) { + console.log('locale.js: translation [{0}] does not exist'.format(string)); + return 'locale.js: translation [{0}] does not exist'.format(string); + } + + // Do we need to format the string? + if (args.length === 1) { + return capitalize(locale[string]); + } else { + return formatString(args); + } +} + +function formatString(args) { + var string = capitalize(locale[args[0]]); + + for (var i = 1; i < args.length; i++) { + string = string.replace(/%s/, args[i]); + } + + return string; +} + +function capitalize(string) { + return string[0].toUpperCase() + string.slice(1); +} + +// https://stackoverflow.com/a/35359503 +String.prototype.format = function () { + var args = arguments; + return this.replace(/{(\d+)}/g, function (match, number) { + return typeof args[number] != 'undefined' + ? args[number] + : match + ; + }); +}; diff --git a/resources/[core]/es_extended/locale.lua b/resources/[core]/es_extended/locale.lua new file mode 100644 index 0000000..3f059b6 --- /dev/null +++ b/resources/[core]/es_extended/locale.lua @@ -0,0 +1,41 @@ +Locales = {} + +function Translate(str, ...) -- Translate string + if not str then + error(("Resource ^5%s^1 You did not specify a parameter for the Translate function or the value is nil!"):format(GetInvokingResource() or GetCurrentResourceName())) + end + + --- Load the locale file if it hasn't been loaded yet + if Locales[Config.Locale] == nil then + local success, result = pcall(function() + return assert(load(LoadResourceFile(GetCurrentResourceName(), ("locales/%s.lua"):format(Config.Locale))))() + end) + + Locales[Config.Locale] = success and result or false + end + + local translations = Locales[Config.Locale] + if not translations then + if Config.Locale == "en" then + return "Locale [en] does not exist" + end + + -- Fall back to English translation if the current locale is not found + Config.Locale = "en" + return Translate(str, ...) + end + + if translations[str] then + return translations[str]:format(...) + end + + return ("Translation [%s][%s] does not exist"):format(Config.Locale, str) +end + +function TranslateCap(str, ...) -- Translate string first char uppercase + return _(str, ...):gsub("^%l", string.upper) +end + +_ = Translate +-- luacheck: ignore _U +_U = TranslateCap \ No newline at end of file diff --git a/resources/[core]/es_extended/locales/cs.lua b/resources/[core]/es_extended/locales/cs.lua new file mode 100644 index 0000000..0e187be --- /dev/null +++ b/resources/[core]/es_extended/locales/cs.lua @@ -0,0 +1,404 @@ +return { + -- Inventory + ["inventory"] = "Inventář ( Váha %s / %s )", + ["use"] = "Použít", + ["give"] = "Darovat", + ["remove"] = "Odhodit", + ["return"] = "Vrátit", + ["give_to"] = "Darováno", + ["amount"] = "Počet", + ["giveammo"] = "Podat náboje", + ["amountammo"] = "Počet nábojů", + ["noammo"] = "Nedostatek!", + ["gave_item"] = "Daroval %sx %s pro %s", + ["received_item"] = "Získáno %sx %s od %s", + ["gave_weapon"] = "Předání %s pro %s", + ["gave_weapon_ammo"] = "Darování ~o~%sx %s do %s pro %s", + ["gave_weapon_withammo"] = "Darování %s s ~o~%sx %s pro %s", + ["gave_weapon_hasalready"] = "%s již vlastní %s", + ["gave_weapon_noweapon"] = "%s nemá tuto zbraň", + ["received_weapon"] = "Obdrženo %s od %s", + ["received_weapon_ammo"] = "Obdrženo ~o~%sx %s pro zbraň %s od %s", + ["received_weapon_withammo"] = "Obdrženo %s s ~o~%sx %s od %s", + ["received_weapon_hasalready"] = "%s se snažil darovat %s, ale již tuto zbraň máš", + ["received_weapon_noweapon"] = "%s se snažil ti dát náboje %s, ale nemáš potřebnou zbrań", + ["gave_account_money"] = "Darováno $%s (%s) pro %s", + ["received_account_money"] = "Získáno $%s (%s) od %s", + ["amount_invalid"] = "Špatné množství", + ["players_nearby"] = "Žádný hráč není poblíž", + ["ex_inv_lim"] = "Nelze sebrat,protože máš plné kapsy %s", + ["imp_invalid_quantity"] = "Neplatné množství", + ["imp_invalid_amount"] = "Nelze provést, neplatné množství", + ["threw_standard"] = "Zahozeno %sx %s", + ["threw_account"] = "Zahozeno $%s %s", + ["threw_weapon"] = "Zahozeno %s", + ["threw_weapon_ammo"] = "Zahozeno %s s ~o~%sx %s", + ["threw_weapon_already"] = "Již vlastníš tuto zbraň", + ["threw_cannot_pickup"] = "Kapsy máš plné, nemůžeš sebrat!", + ["threw_pickup_prompt"] = "Zmáčkni E pro sebrání!", + + -- Key mapping + ["keymap_showinventory"] = "Otevřít inventář", + + -- Salary related + ["received_salary"] = "Obdržel jsi: $%s", + ["received_help"] = "Obdržel jsi svůj podíl: $%s", + ["company_nomoney"] = "Firma kde pracujete je příliš chudá, aby vám zaplatila", + ["received_paycheck"] = "Obdržena platba", + ["bank"] = "Banka", + ["account_bank"] = "V bance", + ["account_black_money"] = "Špináve peníze", + ["account_money"] = "V kapse", + + ["act_imp"] = "Nelze provést", + ["in_vehicle"] = "Nelze provést, hráč je v autě", + ["not_in_vehicle"] = "Cannot Perform Action, Player isn't in a vehicle", + + -- Commands + ["command_bring"] = "Přivolat si hráče k sobě", + ["command_car"] = "Spawnout vozidlo", + ["command_car_car"] = "Zadej jméno vozidla nebo spawnname", + ["command_cardel"] = "Odstranění vozidla v okolí", + ["command_cardel_radius"] = "Odstranění vozidla v určeném dosahu", + ["command_repair"] = "Repair your vehicle", + ["command_repair_success"] = "Successfully repaired vehicle", + ["command_repair_success_target"] = "An admin repaired your vehicle", + ["command_clear"] = "Vymazat text v chatu", + ["command_clearall"] = "Vymazat chet pro všechny hráče", + ["command_clearinventory"] = "Vymazat všechny věci z invetáře hráče", + ["command_clearloadout"] = "Vymazat všechny zbraně z inventáře hráče", + ["command_freeze"] = "Zmrazit hráče", + ["command_unfreeze"] = "Odmrazit hráče", + ["command_giveaccountmoney"] = "Poslat peníze na účet ", + ["command_giveaccountmoney_account"] = "Převést peníze na účet", + ["command_giveaccountmoney_amount"] = "Částka k poslání", + ["command_giveaccountmoney_invalid"] = "Neplátné jméno", + ["command_giveitem"] = "Darovat věc hráči", + ["command_giveitem_item"] = "Název věci", + ["command_giveitem_count"] = "Množství", + ["command_giveweapon"] = "Dát zbraň hráči", + ["command_giveweapon_weapon"] = "Název zbraně", + ["command_giveweapon_ammo"] = "Množství náboje", + ["command_giveweapon_hasalready"] = "Hráč již má tuto zbraň", + ["command_giveweaponcomponent"] = "Darovat přídavek na zbraň", + ["command_giveweaponcomponent_component"] = "Název zbraně", + ["command_giveweaponcomponent_invalid"] = "Špatné jméno přídavku", + ["command_giveweaponcomponent_hasalready"] = "Hráč již má tento přídavek", + ["command_giveweaponcomponent_missingweapon"] = "Hráč nemá tuto zbrań", + ["command_goto"] = "Teleportování sebe k hráči", + ["command_kill"] = "Zabití hráče", + ["command_save"] = "Uložení dat hráče", + ["command_saveall"] = "Uložení veškerých dat hráče", + ["command_setaccountmoney"] = "Nastavení určeného počtu peněz", + ["command_setaccountmoney_amount"] = "Počet peněz", + ["command_setcoords"] = "Teleportování na určené souřadnice", + ["command_setcoords_x"] = "Hodnota X", + ["command_setcoords_y"] = "Hodnota Y", + ["command_setcoords_z"] = "Hodnota Z", + ["command_setjob"] = "Nastavit práci hráči", + ["command_setjob_job"] = "Název práce", + ["command_setjob_grade"] = "Pozice ve firmě", + ["command_setjob_invalid"] = "Špatné zadání práce,hodnosti nebo i obou hodnot", + ["command_setgroup"] = "Nastavení práv hráči", + ["command_setgroup_group"] = "Název skupiny", + ["commanderror_argumentmismatch"] = "Chybný počet hodnot (správně %s, potřebných %s)", + ["commanderror_argumentmismatch_number"] = "Chybně zadaná hodnot #%s (správně, špatně)", + ["commanderror_argumentmismatch_positive_number"] = "Chybně zadaná hodnota #%s (zadáno záporné/nula, požadováno kladné číslo)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (passed number, wanted string)", + ["commanderror_invaliditem"] = "Špatný předmět", + ["commanderror_invalidweapon"] = "Špatná zbraň", + ["commanderror_console"] = "příkaz nelze být zpracován v konzoli", + ["commanderror_invalidcommand"] = "Špatný příkaz - /%s", + ["commanderror_invalidplayerid"] = "Hráč není dostupný", + ["commandgeneric_playerid"] = "Id hráče", + ["command_giveammo_noweapon_found"] = "%s nemá tuto zbraň", + ["command_giveammo_weapon"] = "Název zbraně", + ["command_giveammo_ammo"] = "Počet nábojů", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "£%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dýka", + ["weapon_bat"] = "Baseballová pálka", + ["weapon_battleaxe"] = "Bitevní sekera", + ["weapon_bottle"] = "Rozbitá lahve", + ["weapon_crowbar"] = "Páčidlo", + ["weapon_flashlight"] = "Baterka", + ["weapon_golfclub"] = "Golfová hůl", + ["weapon_hammer"] = "Kladivo", + ["weapon_hatchet"] = "Sekera", + ["weapon_knife"] = "Nůž", + ["weapon_knuckle"] = "Boxer", + ["weapon_machete"] = "Mačeta", + ["weapon_nightstick"] = "Policejní obušek", + ["weapon_wrench"] = "Francouzský klíč", + ["weapon_poolcue"] = "Kulečníkové tágo", + ["weapon_stone_hatchet"] = "Kamenná sekera", + ["weapon_switchblade"] = "Vystřelovací nůž", + + -- Handguns + ["weapon_appistol"] = "AP pistol", + ["weapon_ceramicpistol"] = "Ceramic pistol", + ["weapon_combatpistol"] = "Combat pistol", + ["weapon_doubleaction"] = "Double-Action Revolver", + ["weapon_navyrevolver"] = "Navy Revolver", + ["weapon_flaregun"] = "Flaregun", + ["weapon_gadgetpistol"] = "Gadget Pistol", + ["weapon_heavypistol"] = "Heavy Pistol", + ["weapon_revolver"] = "Heavy Revolver", + ["weapon_revolver_mk2"] = "Heavy Revolver MK2", + ["weapon_marksmanpistol"] = "Marksman Pistol", + ["weapon_pistol"] = "Pistol", + ["weapon_pistol_mk2"] = "Pistol MK2", + ["weapon_pistol50"] = "Pistol .50", + ["weapon_snspistol"] = "SNS Pistol", + ["weapon_snspistol_mk2"] = "SNS Pistol MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Vintage Pistol", + + -- Shotguns + ["weapon_assaultshotgun"] = "Assault Shotgun", + ["weapon_autoshotgun"] = "Auto Shotgun", + ["weapon_bullpupshotgun"] = "Bullpup Shotgun", + ["weapon_combatshotgun"] = "Combat Shotgun", + ["weapon_dbshotgun"] = "Double Barrel Shotgun", + ["weapon_heavyshotgun"] = "Heavy Shotgun", + ["weapon_musket"] = "Musket", + ["weapon_pumpshotgun"] = "Pump Shotgun", + ["weapon_pumpshotgun_mk2"] = "Pump Shotgun MK2", + ["weapon_sawnoffshotgun"] = "Sawed Off Shotgun", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Assault SMG", + ["weapon_combatmg"] = "Combat MG", + ["weapon_combatmg_mk2"] = "Combat MG MK2", + ["weapon_combatpdw"] = "Combat PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Machine Pistol", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Unholy Hellbringer", + + -- Rifles + ["weapon_advancedrifle"] = "Advanced Rifle", + ["weapon_assaultrifle"] = "Assault Rifle", + ["weapon_assaultrifle_mk2"] = "Assault Rifle MK2", + ["weapon_bullpuprifle"] = "Bullpup Rifle", + ["weapon_bullpuprifle_mk2"] = "Bullpup Rifle MK2", + ["weapon_carbinerifle"] = "Carbine Rifle", + ["weapon_carbinerifle_mk2"] = "Carbine Rifle MK2", + ["weapon_compactrifle"] = "Compact Rifle", + ["weapon_militaryrifle"] = "Military Rifle", + ["weapon_specialcarbine"] = "Special Carbine", + ["weapon_specialcarbine_mk2"] = "Special Carbine MK2", + ["weapon_heavyrifle"] = "Heavy Rifle", -- Not Translated + + -- Sniper + ["weapon_heavysniper"] = "Heavy Sniper", + ["weapon_heavysniper_mk2"] = "Heavy Sniper MK2", + ["weapon_marksmanrifle"] = "Marksman Rifle", + ["weapon_marksmanrifle_mk2"] = "Marksman Rifle MK2", + ["weapon_sniperrifle"] = "Sniper Rifle", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Compact Launcher", + ["weapon_firework"] = "Firework Launcher", + ["weapon_grenadelauncher"] = "Grenade Launcher", + ["weapon_hominglauncher"] = "Homing Launcher", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Rocket Launcher", + ["weapon_rayminigun"] = "Widowmaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Detektor kovu", + ["weapon_precisionrifle"] = "Precision Rifle", + ["weapon_tactilerifle"] = "Service Carbine", + + -- Drug Wars DLC + ["weapon_candycane"] = "Candy Cane", -- not translated + ["weapon_acidpackage"] = "Acid Package", -- not translated + ["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated + ["weapon_railgunxm3"] = "Railgun", -- not translated + + -- Thrown + ["weapon_ball"] = "Míček", + ["weapon_bzgas"] = "Smrtící slzný plyn", + ["weapon_flare"] = "Světlice", + ["weapon_grenade"] = "Granát", + ["weapon_petrolcan"] = "Kanistr", + ["weapon_hazardcan"] = "Hazardous Jerrycan", + ["weapon_molotov"] = "Molotův koktejl", + ["weapon_proxmine"] = "Pohybová mina", + ["weapon_pipebomb"] = "Trubková bomba", + ["weapon_snowball"] = "Sněhová koule", + ["weapon_stickybomb"] = "C4", + ["weapon_smokegrenade"] = "Slzný plyn", + + -- Special + ["weapon_fireextinguisher"] = "Hasící přístroj", + ["weapon_digiscanner"] = "Skener", + ["weapon_garbagebag"] = "Odpadkový pytel", + ["weapon_handcuffs"] = "Pouta", + ["gadget_nightvision"] = "Noční vidění", + ["gadget_parachute"] = "Padák", + + -- Weapon Components + ["component_knuckle_base"] = "base Model", + ["component_knuckle_pimp"] = "the Pimp", + ["component_knuckle_ballas"] = "the Ballas", + ["component_knuckle_dollar"] = "the Hustler", + ["component_knuckle_diamond"] = "the Rock", + ["component_knuckle_hate"] = "the Hater", + ["component_knuckle_love"] = "the Lover", + ["component_knuckle_player"] = "the Player", + ["component_knuckle_king"] = "the King", + ["component_knuckle_vagos"] = "the Vagos", + + ["component_luxary_finish"] = "luxary Weapon Finish", + + ["component_handle_default"] = "default Handle", + ["component_handle_vip"] = "vIP Handle", + ["component_handle_bodyguard"] = "bodyguard Handle", + + ["component_vip_finish"] = "vIP Finish", + ["component_bodyguard_finish"] = "bodyguard Finish", + + ["component_camo_finish"] = "digital Camo", + ["component_camo_finish2"] = "brushstroke Camo", + ["component_camo_finish3"] = "woodland Camo", + ["component_camo_finish4"] = "skull Camo", + ["component_camo_finish5"] = "sessanta Nove Camo", + ["component_camo_finish6"] = "perseus Camo", + ["component_camo_finish7"] = "leopard Camo", + ["component_camo_finish8"] = "zebra Camo", + ["component_camo_finish9"] = "geometric Camo", + ["component_camo_finish10"] = "boom Camo", + ["component_camo_finish11"] = "patriotic Camo", + + ["component_camo_slide_finish"] = "digital Slide Camo", + ["component_camo_slide_finish2"] = "brushstroke Slide Camo", + ["component_camo_slide_finish3"] = "woodland Slide Camo", + ["component_camo_slide_finish4"] = "skull Slide Camo", + ["component_camo_slide_finish5"] = "sessanta Nove Slide Camo", + ["component_camo_slide_finish6"] = "perseus Slide Camo", + ["component_camo_slide_finish7"] = "leopard Slide Camo", + ["component_camo_slide_finish8"] = "zebra Slide Camo", + ["component_camo_slide_finish9"] = "geometric Slide Camo", + ["component_camo_slide_finish10"] = "boom Slide Camo", + ["component_camo_slide_finish11"] = "patriotic Slide Camo", + + ["component_clip_default"] = "default Magazine", + ["component_clip_extended"] = "extended Magazine", + ["component_clip_drum"] = "drum Magazine", + ["component_clip_box"] = "box Magazine", + + ["component_scope_holo"] = "holographic Scope", + ["component_scope_small"] = "small Scope", + ["component_scope_medium"] = "medium Scope", + ["component_scope_large"] = "large Scope", + ["component_scope"] = "mounted Scope", + ["component_scope_advanced"] = "advanced Scope", + ["component_ironsights"] = "ironsights", + + ["component_suppressor"] = "suppressor", + ["component_compensator"] = "compensator", + + ["component_muzzle_flat"] = "flat Muzzle Brake", + ["component_muzzle_tactical"] = "tactical Muzzle Brake", + ["component_muzzle_fat"] = "fat-End Muzzle Brake", + ["component_muzzle_precision"] = "precision Muzzle Brake", + ["component_muzzle_heavy"] = "heavy Duty Muzzle Brake", + ["component_muzzle_slanted"] = "slanted Muzzle Brake", + ["component_muzzle_split"] = "split-End Muzzle Brake", + ["component_muzzle_squared"] = "squared Muzzle Brake", + + ["component_flashlight"] = "flashlight", + ["component_grip"] = "grip", + + ["component_barrel_default"] = "default Barrel", + ["component_barrel_heavy"] = "heavy Barrel", + + ["component_ammo_tracer"] = "tracer Ammo", + ["component_ammo_incendiary"] = "incendiary Ammo", + ["component_ammo_hollowpoint"] = "hollowpoint Ammo", + ["component_ammo_fmj"] = "fMJ Ammo", + ["component_ammo_armor"] = "armor Piercing Ammo", + ["component_ammo_explosive"] = "armor Piercing Incendiary Ammo", + + ["component_shells_default"] = "default Shells", + ["component_shells_incendiary"] = "dragons Breath Shells", + ["component_shells_armor"] = "steel Buckshot Shells", + ["component_shells_hollowpoint"] = "flechette Shells", + ["component_shells_explosive"] = "explosive Slug Shells", + + -- Weapon Ammo + ["ammo_rounds"] = "round(s)", + ["ammo_shells"] = "shell(s)", + ["ammo_charge"] = "charge", + ["ammo_petrol"] = "gallons of fuel", + ["ammo_firework"] = "firework(s)", + ["ammo_rockets"] = "rocket(s)", + ["ammo_grenadelauncher"] = "grenade(s)", + ["ammo_grenade"] = "grenade(s)", + ["ammo_stickybomb"] = "bomb(s)", + ["ammo_pipebomb"] = "bomb(s)", + ["ammo_smokebomb"] = "bomb(s)", + ["ammo_molotov"] = "cocktail(s)", + ["ammo_proxmine"] = "mine(s)", + ["ammo_bzgas"] = "can(s)", + ["ammo_ball"] = "ball(s)", + ["ammo_snowball"] = "snowball(s)", + ["ammo_flare"] = "flare(s)", + ["ammo_flaregun"] = "flare(s)", + + -- Weapon Tints + ["tint_default"] = "default skin", + ["tint_green"] = "green skin", + ["tint_gold"] = "gold skin", + ["tint_pink"] = "pink skin", + ["tint_army"] = "army skin", + ["tint_lspd"] = "blue skin", + ["tint_orange"] = "orange skin", + ["tint_platinum"] = "platinum skin", + -- MK2 Weapon Tints + ["tint_classic_gray"] = "klasická šedá", + ["tint_classic_two_tone"] = "klasická dvoutónová", + ["tint_classic_white"] = "klasická bílá", + ["tint_classic_beige"] = "klasická béžová", + ["tint_classic_green"] = "klasická zelená", + ["tint_classic_blue"] = "klasická modrá", + ["tint_classic_earth"] = "klasická hnědá", + ["tint_classic_brown_black"] = "klasická hnědá-černá", + ["tint_contrast_red"] = "kontrastní červená", + ["tint_contrast_blue"] = "kontrastní modrá", + ["tint_contrast_yellow"] = "kontrastní žlutá", + ["tint_contrast_orange"] = "kontrastní oranžová", + ["tint_bold_pink"] = "odvážná růžová", + ["tint_bold_purple_yellow"] = "odvážná fialovo-žlutá", + ["tint_bold_orange"] = "odvážná oranžová", + ["tint_bold_green_purple"] = "odvážná zeleno-fialová", + ["tint_bold_red_feat"] = "odvážná červená feat", + ["tint_bold_green_feat"] = "odvážná zelená feat", + ["tint_bold_cyan_feat"] = "odvážná azurová feat", + ["tint_bold_yellow_feat"] = "odvážná žlutá feat", + ["tint_bold_red_white"] = "odvážná červená bílá", + ["tint_bold_blue_white"] = "odvážná modrá bílá", + ["tint_metallic_gold"] = "metalická zlatá", + ["tint_metallic_platinum"] = "metalická platina", + ["tint_metallic_gray_lilac"] = "metalická šedá lila", + ["tint_metallic_purple_lime"] = "metalická fialová limetka", + ["tint_metallic_red"] = "metalická červená", + ["tint_metallic_green"] = "metalická zelená", + ["tint_metallic_blue"] = "metalická modrá", + ["tint_metallic_white_aqua"] = "metalická bílá aqua", + ["tint_metallic_red_yellow"] = "metalická červená žlutá", +} diff --git a/resources/[core]/es_extended/locales/de.lua b/resources/[core]/es_extended/locales/de.lua new file mode 100644 index 0000000..f32b343 --- /dev/null +++ b/resources/[core]/es_extended/locales/de.lua @@ -0,0 +1,417 @@ +return { + -- Inventory + ["inventory"] = "Inventar ( Gewicht %s / %s )", + ["use"] = "Benutzen", + ["give"] = "Geben", + ["remove"] = "Entsorgen", + ["return"] = "Zurück", + ["give_to"] = "Geben an", + ["amount"] = "Anzahl", + ["giveammo"] = "Munition geben", + ["amountammo"] = "Munitions Anzahl", + ["noammo"] = "Nicht Genug!", + ["gave_item"] = "Du gibst %sx %s an %s", + ["received_item"] = "Du bekommst %sx %s von %s", + ["gave_weapon"] = "Du gibst %s an %s", + ["gave_weapon_ammo"] = "Du gibst ~o~%sx %s für %s an %s", + ["gave_weapon_withammo"] = "Du gibst %s mit ~o~%sx %s an %s", + ["gave_weapon_hasalready"] = "%s hat bereits %s", + ["gave_weapon_noweapon"] = "%s hat diese Waffe nicht", + ["received_weapon"] = "Du bekommst %s von %s", + ["received_weapon_ammo"] = "Du bekommst ~o~%sx %s für deine %s von %s", + ["received_weapon_withammo"] = "Du bekommst %s mit ~o~%sx %s von %s", + ["received_weapon_hasalready"] = "%s hat versucht dir eine %s zu geben, jedoch hast du diese Waffe bereits!", + ["received_weapon_noweapon"] = "%s hat versucht dir Munition für eine %s zu geben, jedoch hast du diese Waffe nicht!", + ["gave_account_money"] = "Du gibst %s€ (%s) an %s", + ["received_account_money"] = "Du bekommst %s€ (%s) von %s", + ["amount_invalid"] = "Ungültige Anzahl", + ["players_nearby"] = "Keine Personen in der Nähe!", + ["ex_inv_lim"] = "Du kannst diese Aktion nicht ausführen!, Inventarlimit für %s überschritten.", + ["imp_invalid_quantity"] = "Du kannst diese Aktion nicht ausführen!, Ungültige Anzahl!", + ["imp_invalid_amount"] = "Du kannst diese Aktion nicht ausführen!, Ungültige Anzahl", + ["threw_standard"] = "Du entsorgst %sx %s", + ["threw_account"] = "Du Entsorgst %s€ %s", + ["threw_weapon"] = "Du entsorgst %s", + ["threw_weapon_ammo"] = "Du entsorgst %s mit ~o~%sx %s", + ["threw_weapon_already"] = "Du hast diese Waffe bereits!", + ["threw_cannot_pickup"] = "Inventar ist voll! Du kannst dies nicht aufheben", + ["threw_pickup_prompt"] = "Drücke [E] zum aufheben", + + -- Key mapping + ["keymap_showinventory"] = "Inventar Anzeigen", + + -- Salary related + ["received_salary"] = "Dein Gehaltscheck ist angekommen!: %s€", + ["received_help"] = "Deine Sozialhilfe ist angekommen: %s€", + ["company_nomoney"] = "Die Firma an der du Angestellt bist, ist leider Arm und kann dich nicht bezahlen :(", + ["received_paycheck"] = "Gehaltscheck erhalten", + ["bank"] = "Maze Bank", + ["account_bank"] = "Bank", + ["account_black_money"] = "Schwarzgeld", + ["account_money"] = "Bargeld", + + ["act_imp"] = "Du kannst diese Aktion nicht ausführen!", + ["in_vehicle"] = "Person darf nicht in einem Fahrzeug sein!", + ["not_in_vehicle"] = "Person muss in einem Fahrzeug sein!", + + -- Commands + ["command_bring"] = "Person zu dir bringen", + ["command_car"] = "Fahrzeug Spawnen", + ["command_car_car"] = "Fahrzeug Model oder Hash", + ["command_cardel"] = "Fahrzeuge entfernen", + ["command_cardel_radius"] = "Entfernt alle Fahrzeuge in einem bestimmten Radius", + ["command_repair"] = "Fahrzeug reparieren", + ["command_repair_success"] = "Fahrzeug erfolgreich repariert.", + ["command_repair_success_target"] = "Ein Admin hat dein Fahrzeug repariert.", + ["command_clear"] = "Textchat leeren", + ["command_clearall"] = "Textchat für alle Spieler leeren", + ["command_clearinventory"] = "Alle Gegenstände vom Inventar eines Spielers entfernen", + ["command_clearloadout"] = "Alle Waffen vom Loadout eines Spielers entfernen", + ["command_freeze"] = "Spieler Freezen", + ["command_unfreeze"] = "Spieler Entfreezen", + ["command_giveaccountmoney"] = "Geld an ein bestimmtes Konto geben", + ["command_giveaccountmoney_account"] = "Konto, wohin das Geld hinzugefügt werden soll", + ["command_giveaccountmoney_amount"] = "Menge zum Hinzufügen", + ["command_giveaccountmoney_invalid"] = "Accountname ungültig!", + ["command_giveitem"] = "Spieler ein Gegenstand geben", + ["command_giveitem_item"] = "Gegenstand Name", + ["command_giveitem_count"] = "Menge", + ["command_giveweapon"] = "Spieler eine Waffe geben", + ["command_giveweapon_weapon"] = "Waffenname", + ["command_giveweapon_ammo"] = "Munitionsanzahl", + ["command_giveweapon_hasalready"] = "Spieler hat diese Waffe bereits!", + ["command_giveweaponcomponent"] = "Waffenkomponent an einen Spieler geben", + ["command_giveweaponcomponent_component"] = "Komponentenname", + ["command_giveweaponcomponent_invalid"] = "Ungültiger Komponentenname", + ["command_giveweaponcomponent_hasalready"] = "Spieler hat diese Komponente bereits!", + ["command_giveweaponcomponent_missingweapon"] = "Spieler hat diese Waffe nicht!", + ["command_goto"] = "Teleportiere dich zu einem Spieler", + ["command_kill"] = "Spieler Töten", + ["command_save"] = "Von einem bestimmten Spieler die Spielerdaten speichern", + ["command_saveall"] = "Von allen Spielern die Spielerdaten speichern", + ["command_setaccountmoney"] = "Geld auf einem bestimmten Konto festlegen", + ["command_setaccountmoney_amount"] = "Menge", + ["command_setcoords"] = "Zu den bestimmten Koordinaten teleportieren", + ["command_setcoords_x"] = "X Koordinate", + ["command_setcoords_y"] = "Y Koordinate", + ["command_setcoords_z"] = "Z Koordinate", + ["command_setjob"] = "Job eines Spielers setzen", + ["command_setjob_job"] = "Name", + ["command_setjob_grade"] = "Job Rang", + ["command_setjob_invalid"] = "Der Rang oder der Name und Rang sind ungültig", + ["command_setgroup"] = "Setzt eine Berechtigungs Gruppe für einen Benutzer", + ["command_setgroup_group"] = "Name der Gruppe", + ["command_removeaccountmoney"] = "Entfernt Geld von einem bestimmten Konto", + ["command_removeaccountmoney_account"] = "Konto von dem es entfernt werden soll", + ["command_removeaccountmoney_amount"] = "Menge, die entfernt werden soll", + ["command_removeaccountmoney_invalid"] = "Name des Kontos ungültig", + ["commanderror_argumentmismatch"] = "Ungültiges Argument (gegeben %s, gewollt %s)", + ["commanderror_argumentmismatch_number"] = "Ungültiges Argument #%s Datentyp (String gegeben, Nummer gefordert)", + ["commanderror_argumentmismatch_string"] = "Ungültiges Argument #%s Datentyp (Nummer gegeben, String gefordert)", + ["commanderror_argumentmismatch_positive_number"] = "Ungültiges Argument #%s Datentyp (negativ/null übergeben, positive Zahl gewünscht)", + ["commanderror_invaliditem"] = "Ungültiger Gegenstand", + ["commanderror_invalidweapon"] = "Ungültige Waffe", + ["commanderror_console"] = "Befehl kann nicht von der Konsole aus ausgeführt werden!", + ["commanderror_invalidcommand"] = "Ungültiger Befehl - /%s", + ["commanderror_invalidplayerid"] = "Angegebener Spieler ist nicht online!", + ["commandgeneric_playerid"] = "Spieler ID", + ["commandgeneric_dimension"] = "Ziel Dimension", + ["command_giveammo_noweapon_found"] = "%s besitzt diese Waffe nicht!", + ["command_giveammo_weapon"] = "Waffenname", + ["command_giveammo_ammo"] = "Munitionsanzahl", + ["command_setdim"] = "Setzt Spieler Dimension!", + ["tpm_nowaypoint"] = "Kein Wegpunkt gesetzt!", + ["tpm_success"] = "Erfolgreich teleportiert.", + + ["noclip_message"] = "Noclip wurde %s", + ["enabled"] = "~g~Aktiviert~s~", + ["disabled"] = "~r~Deaktiviert~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "%s€", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dolch", + ["weapon_bat"] = "Baseballschläger", + ["weapon_battleaxe"] = "Kampfaxt", + ["weapon_bottle"] = "Flasche", + ["weapon_crowbar"] = "Brechstange", + ["weapon_flashlight"] = "Taschenlampe", + ["weapon_golfclub"] = "Golfschläger", + ["weapon_hammer"] = "Hammer", + ["weapon_hatchet"] = "Beil", + ["weapon_knife"] = "Messer", + ["weapon_knuckle"] = "Schlagring", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Schlagstock", + ["weapon_wrench"] = "Rohrzange", + ["weapon_poolcue"] = "Billiardstange", + ["weapon_stone_hatchet"] = "Steinbeil", + ["weapon_switchblade"] = "Springmesser", + + -- Handguns + ["weapon_appistol"] = "AP Pistole", + ["weapon_ceramicpistol"] = "Keramikpistole", + ["weapon_combatpistol"] = "Kampfpistole", + ["weapon_doubleaction"] = "Double-Action Revolver", + ["weapon_navyrevolver"] = "Navy Revolver", + ["weapon_flaregun"] = "Flaregun", + ["weapon_gadgetpistol"] = "Gadgetpistole", + ["weapon_heavypistol"] = "Schwere Pistole", + ["weapon_revolver"] = "Schwerer Revolver", + ["weapon_revolver_mk2"] = "Schwerer Revolver MK2", + ["weapon_marksmanpistol"] = "Scharfschützen Pistole", + ["weapon_pistol"] = "Pistole", + ["weapon_pistol_mk2"] = "Pistole MK2", + ["weapon_pistol50"] = "Pistole 50 Kaliber", + ["weapon_snspistol"] = "SNS Pistol", + ["weapon_snspistol_mk2"] = "SNS Pistol MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Vintagepistole", + + -- Shotguns + ["weapon_assaultshotgun"] = "Sturmschrotflinte", + ["weapon_autoshotgun"] = "Automatische Schrotflinte", + ["weapon_bullpupshotgun"] = "Bullpup-Schrotflinte", + ["weapon_combatshotgun"] = "Kampfschrotfline", + ["weapon_dbshotgun"] = "Doppelbarrel Schrotflinte", + ["weapon_heavyshotgun"] = "Schwere Schrotflinte", + ["weapon_musket"] = "Muskete", + ["weapon_pumpshotgun"] = "Pump Schrotflinte", + ["weapon_pumpshotgun_mk2"] = "Pump Schrotflinte MK2", + ["weapon_sawnoffshotgun"] = "Abgesägte Schrotflinte", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Sturm SMG", + ["weapon_combatmg"] = "Kampf MG", + ["weapon_combatmg_mk2"] = "Kampf MG MK2", + ["weapon_combatpdw"] = "Kampf PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Maschinenpistole", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Mikro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Unheiliger Höllenbringer", + + -- Rifles + ["weapon_advancedrifle"] = "Fortgeschrittenes Gewehr", + ["weapon_assaultrifle"] = "Sturmgewehr", + ["weapon_assaultrifle_mk2"] = "Sturmgewehr MK2", + ["weapon_bullpuprifle"] = "Bullpup Gewehr", + ["weapon_bullpuprifle_mk2"] = "Bullpup Gewehr MK2", + ["weapon_carbinerifle"] = "Karabinergewehr", + ["weapon_carbinerifle_mk2"] = "Karabinergewehr MK2", + ["weapon_compactrifle"] = "Kompaktesgewehr", + ["weapon_militaryrifle"] = "Militärgewehr", + ["weapon_specialcarbine"] = "Spezialkarabiner", + ["weapon_specialcarbine_mk2"] = "Spezialkarabiner MK2", + ["weapon_heavyrifle"] = "Schweres Gewehr", + + -- Sniper + ["weapon_heavysniper"] = "Schwere Sniper", + ["weapon_heavysniper_mk2"] = "Schwere Sniper MK2", + ["weapon_marksmanrifle"] = "Scharfschützengewehr", + ["weapon_marksmanrifle_mk2"] = "Scharfschützengewehr MK2", + ["weapon_sniperrifle"] = "Sniper", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Kompaktlauncher", + ["weapon_firework"] = "Feuerwerklauncher", + ["weapon_grenadelauncher"] = "Granatwerfer", + ["weapon_hominglauncher"] = "Lenkraketenwerfer", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Raketenwerfer", + ["weapon_rayminigun"] = "Witwenmacher", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Metalldetektor", + ["weapon_precisionrifle"] = "Präzisionsgewehr", + ["weapon_tactilerifle"] = "Service Karabiner", + + -- Drug Wars DLC + ["weapon_candycane"] = "Zuckerstange", + ["weapon_acidpackage"] = "Säure Paket", + ["weapon_pistolxm3"] = "WM 29 Pistole", + ["weapon_railgunxm3"] = "Railgun", + + -- Thrown + ["weapon_ball"] = "Baseball", + ["weapon_bzgas"] = "BZ Gas", + ["weapon_flare"] = "Leuchtfackel", + ["weapon_grenade"] = "Granate", + ["weapon_petrolcan"] = "Benzinkanister", + ["weapon_hazardcan"] = "Gefährliche Kanister", + ["weapon_molotov"] = "Molotov Cocktail", + ["weapon_proxmine"] = "Annährungsmine", + ["weapon_pipebomb"] = "Rohrbombe", + ["weapon_snowball"] = "Schneeball", + ["weapon_stickybomb"] = "Haftbombe", + ["weapon_smokegrenade"] = "Tränengas", + + -- Special + ["weapon_fireextinguisher"] = "Feuerlöscher", + ["weapon_digiscanner"] = "Digitalscanner", + ["weapon_garbagebag"] = "Müllsack", + ["weapon_handcuffs"] = "Handschelle", + ["gadget_nightvision"] = "Nachtsicht", + ["gadget_parachute"] = "Fallschirm", + + -- Weapon Components + ["component_knuckle_base"] = "Basismodell", + ["component_knuckle_pimp"] = "Der Pimp", + ["component_knuckle_ballas"] = "Die Ballas", + ["component_knuckle_dollar"] = "Der Hustler", + ["component_knuckle_diamond"] = "Der Stein", + ["component_knuckle_hate"] = "Der Hater", + ["component_knuckle_love"] = "Der Lover", + ["component_knuckle_player"] = "Der Player", + ["component_knuckle_king"] = "Der King", + ["component_knuckle_vagos"] = "Die Vagos", + + ["component_luxary_finish"] = "Luxuswaffenlackierung", + + ["component_handle_default"] = "Normaler Handgriff", + ["component_handle_vip"] = "VIP Handgriff", + ["component_handle_bodyguard"] = "Bodyguard Handgriff", + + ["component_vip_finish"] = "VIP Lackierung", + ["component_bodyguard_finish"] = "Bodyguard Lackierung", + + ["component_camo_finish"] = "Digitales Camouflage", + ["component_camo_finish2"] = "Pinselstrich Camouflage", + ["component_camo_finish3"] = "Holzland Camouflage", + ["component_camo_finish4"] = "Kopf Camouflage", + ["component_camo_finish5"] = "Sessebta-Nove Camouflage", + ["component_camo_finish6"] = "Perseus Camouflage", + ["component_camo_finish7"] = "Leopard Camouflage", + ["component_camo_finish8"] = "Zebra Camouflage", + ["component_camo_finish9"] = "Geometrisch Camouflage", + ["component_camo_finish10"] = "BOOM Camouflage", + ["component_camo_finish11"] = "Patriotisch Camouflage", + + ["component_camo_slide_finish"] = "Digital Rutschen Camouflage", + ["component_camo_slide_finish2"] = "Pinselstrich Rutschen Camouflage", + ["component_camo_slide_finish3"] = "Holzland Rutschen Camouflage", + ["component_camo_slide_finish4"] = "Kopf Rutschen Camouflage", + ["component_camo_slide_finish5"] = "Sessebta-Nove Nove Rutschen Camouflage", + ["component_camo_slide_finish6"] = "Perseus Rutschen Camouflage", + ["component_camo_slide_finish7"] = "Leopard Rutschen Camouflage", + ["component_camo_slide_finish8"] = "Zebra Rutschen Camouflage", + ["component_camo_slide_finish9"] = "Geometrisch Rutschen Camouflage", + ["component_camo_slide_finish10"] = "BOOM Rutschen Camouflage", + ["component_camo_slide_finish11"] = "Patriotisch Rutschen Camouflage", + + ["component_clip_default"] = "Standard Magazin", + ["component_clip_extended"] = "Erweiterters Magazin", + ["component_clip_drum"] = "Trommelmagazin", + ["component_clip_box"] = "Kastenmagazin", + + ["component_scope_holo"] = "Holographisches Zielfernrohr", + ["component_scope_small"] = "Kleines Zielfernrohr", + ["component_scope_medium"] = "Mittleres Zielfernrohr", + ["component_scope_large"] = "Großes Zielfernrohr", + ["component_scope"] = "Montiertes Zielfernrohr", + ["component_scope_advanced"] = "Fortgeschrittenes Zielfernrohr", + ["component_ironsights"] = "Ironsights", + + ["component_suppressor"] = "Entstörer", + ["component_compensator"] = "Kompensator", + + ["component_muzzle_flat"] = "Flache Mündung", + ["component_muzzle_tactical"] = "Taktische Mündung", + ["component_muzzle_fat"] = "Fettes-Ende Mündung", + ["component_muzzle_precision"] = "Präzision Mündung", + ["component_muzzle_heavy"] = "Schwere Mündung", + ["component_muzzle_slanted"] = "Schräge Mündung", + ["component_muzzle_split"] = "Geteiletes-Ende Mündung", + ["component_muzzle_squared"] = "Quadratische Mündung", + + ["component_flashlight"] = "Taschenlampe", + ["component_grip"] = "Grip", + + ["component_barrel_default"] = "Normales Fass", + ["component_barrel_heavy"] = "Schweres Fass", + + ["component_ammo_tracer"] = "Tracer Munition", + ["component_ammo_incendiary"] = "Aufruhr Munition", + ["component_ammo_hollowpoint"] = "Hohlspitze Munition", + ["component_ammo_fmj"] = "FMJ Munition", + ["component_ammo_armor"] = "Panzerbrechende Munition", + ["component_ammo_explosive"] = "Panzerbrechende brennende Munition", + + ["component_shells_default"] = "Normale Hülsen", + ["component_shells_incendiary"] = "Drachenatem Hülsen", + ["component_shells_armor"] = "Stahlschrot Hülsen", + ["component_shells_hollowpoint"] = "Flechette Hülsen", + ["component_shells_explosive"] = "Explosives Geschoss Hülsen", + + -- Weapon Ammo + ["ammo_rounds"] = "Kugel(n)", + ["ammo_shells"] = "Schrotpatrone(n)", + ["ammo_charge"] = "Nachladen", + ["ammo_petrol"] = "Benzinkanister", + ["ammo_firework"] = "Feuerwerksrakete(n)", + ["ammo_rockets"] = "Rakete(n)", + ["ammo_grenadelauncher"] = "Granate(n)", + ["ammo_grenade"] = "Granate(n)", + ["ammo_stickybomb"] = "C4(s)", + ["ammo_pipebomb"] = "Rohrbombe(n)", + ["ammo_smokebomb"] = "Rauchgranate(n)", + ["ammo_molotov"] = "Molotovcocktail(s)", + ["ammo_proxmine"] = "Annäherungsmine(n)", + ["ammo_bzgas"] = "Bzgas", + ["ammo_ball"] = "Ball", + ["ammo_snowball"] = "Schneebälle", + ["ammo_flare"] = "Signalfackel(n)", + ["ammo_flaregun"] = "Signalfackeln(munition)", + + -- Weapon Tints + ["tint_default"] = "Standard", + ["tint_green"] = "Grün", + ["tint_gold"] = "Gold", + ["tint_pink"] = "Pink", + ["tint_army"] = "Camouflage", + ["tint_lspd"] = "Blau", + ["tint_orange"] = "Orange", + ["tint_platinum"] = "Platin", + -- MK2 Weapon Tints + ["tint_classic_black"] = "klassisches Schwarz", + ["tint_classic_gray"] = "klassisches Grau", + ["tint_classic_two_tone"] = "klassisches Zwei-Ton", + ["tint_classic_white"] = "klassisches Weiß", + ["tint_classic_beige"] = "klassisches Beige", + ["tint_classic_green"] = "klassisches Grün", + ["tint_classic_blue"] = "klassisches Blau", + ["tint_classic_earth"] = "klassisches Erdfarben", + ["tint_classic_brown_black"] = "klassisches Braun-Schwarz", + ["tint_contrast_red"] = "Kontrast Rot", + ["tint_contrast_blue"] = "Kontrast Blau", + ["tint_contrast_yellow"] = "Kontrast Gelb", + ["tint_contrast_orange"] = "Kontrast Orange", + ["tint_bold_pink"] = "fette Pink", + ["tint_bold_purple_yellow"] = "fette Lila-Gelb", + ["tint_bold_orange"] = "fette Orange", + ["tint_bold_green_purple"] = "fette Grün-Lila", + ["tint_bold_red_feat"] = "fette Rot feat", + ["tint_bold_green_feat"] = "fette Grün feat", + ["tint_bold_cyan_feat"] = "fette Cyan feat", + ["tint_bold_yellow_feat"] = "fette Gelb feat", + ["tint_bold_red_white"] = "fette Rot Weiß", + ["tint_bold_blue_white"] = "fette Blau Weiß", + ["tint_metallic_gold"] = "metallisches Gold", + ["tint_metallic_platinum"] = "metallisches Platin", + ["tint_metallic_gray_lilac"] = "metallisches Grau-Lila", + ["tint_metallic_purple_lime"] = "metallisches Lila-Limette", + ["tint_metallic_red"] = "metallisches Rot", + ["tint_metallic_green"] = "metallisches Grün", + ["tint_metallic_blue"] = "metallisches Blau", + ["tint_metallic_white_aqua"] = "metallisches Weiß-Aqua", + ["tint_metallic_red_yellow"] = "metallisches Rot-Gelb", +} diff --git a/resources/[core]/es_extended/locales/el.lua b/resources/[core]/es_extended/locales/el.lua new file mode 100644 index 0000000..365ba3a --- /dev/null +++ b/resources/[core]/es_extended/locales/el.lua @@ -0,0 +1,415 @@ +return { + -- Inventory + ["inventory"] = "Αποθήκη ( Βάρος %s / %s )", + ["use"] = "Χρήση", + ["give"] = "Δώσε", + ["remove"] = "Πέτα", + ["return"] = "Επιστροφή", + ["give_to"] = "Δώσε σε", + ["amount"] = "Ποσότητα", + ["giveammo"] = "Δώσε σφαίρες", + ["amountammo"] = "Ποσότητα σφαιρών", + ["noammo"] = "Δεν υπάρχουν αρκετές σφαίρες!", + ["gave_item"] = "Δώσατε %sx %s στον/στην %s", + ["received_item"] = "Λάβατε %sx %s από τον/την %s", + ["gave_weapon"] = "Δίνετε %s στον/στην %s", + ["gave_weapon_ammo"] = "Δίνετε ~o~%sx %s για %s στον/στην %s", + ["gave_weapon_withammo"] = "Δίνετε %s με ~o~%sx %s στον/στην %s", + ["gave_weapon_hasalready"] = "Ο/Η %s έχει ήδη ένα %s", + ["gave_weapon_noweapon"] = "Ο/Η %s δεν έχει αυτό το όπλο", + ["received_weapon"] = "Λάβατε %s από τον/την %s", + ["received_weapon_ammo"] = "Λάβατε ~o~%sx %s για το %s από τον/την %s", + ["received_weapon_withammo"] = "Λάβατε %s για ~o~%sx %s από τον/την %s", + ["received_weapon_hasalready"] = "Ο/Η %s προσπάθησε να σας δώσει ένα %s, αλλά το έχετε ήδη", + ["received_weapon_noweapon"] = "Ο/Η %s προσπάθησε να σας δώσει σφαίρες για το %s, αλλά δεν έχετε αυτό το όπλο", + ["gave_account_money"] = "Δίνετε $%s (%s) στον/στην %s", + ["received_account_money"] = "Λάβατε $%s (%s) από τον/την %s", + ["amount_invalid"] = "Μη έγκυρη ποσότητα", + ["players_nearby"] = "Δεν υπάρχουν κοντινοί παίκτες", + ["ex_inv_lim"] = "Δεν είναι δυνατή η ενέργεια, υπέρβαση του μέγιστου βάρους των %s", + ["imp_invalid_quantity"] = "Δεν είναι δυνατή η ενέργεια, η ποσότητα δεν είναι έγκυρη", + ["imp_invalid_amount"] = "Δεν είναι δυνατή η ενέργεια, το ποσό δεν είναι έγκυρο", + ["threw_standard"] = "Ρίχνοντας %sx %s", + ["threw_account"] = "Ρίχνοντας $%s %s", + ["threw_weapon"] = "Ρίχνοντας %s", + ["threw_weapon_ammo"] = "Ρίχνοντας %s με ~o~%sx %s", + ["threw_weapon_already"] = "Ήδη έχετε αυτό το όπλο", + ["threw_cannot_pickup"] = "Η αποθήκη είναι γεμάτη, δεν μπορείτε να σηκώσετε!", + ["threw_pickup_prompt"] = "Πατήστε E για να σηκώσετε", + + -- Key mapping + ["keymap_showinventory"] = "Εμφάνιση Αποθήκης", + + -- Salary related + ["received_salary"] = "Έχετε λάβει μισθό: $%s", + ["received_help"] = "Έχετε λάβει το βοήθημά σας: $%s", + ["company_nomoney"] = "Η εταιρεία στην οποία είστε απασχολούμενος/η δεν έχει αρκετά χρήματα για να καταβάλει τον μισθό σας", + ["received_paycheck"] = "λάβατε μισθό", + ["bank"] = "Τράπεζα Maze", + ["account_bank"] = "Τραπεζικός Λογαριασμός", + ["account_black_money"] = "Βρώμικα Χρήματα", + ["account_money"] = "Μετρητά", + + ["act_imp"] = "Δεν είναι δυνατή η εκτέλεση της ενέργειας", + ["in_vehicle"] = "Δεν είναι δυνατή η εκτέλεση της ενέργειας, ο παίκτης βρίσκεται σε όχημα", + ["not_in_vehicle"] = "Δεν είναι δυνατή η εκτέλεση της ενέργειας, ο παίκτης δεν βρίσκεται σε κάποιο όχημα", + + -- Commands + ["command_bring"] = "Φέρτε τον παίκτη σε εσάς", + ["command_car"] = "Κλήση οχήματος", + ["command_car_car"] = "Μοντέλο ή κωδικός οχήματος", + ["command_cardel"] = "Κατάργηση οχημάτων κοντά", + ["command_cardel_radius"] = "Καταργεί όλα τα οχήματα εντός της καθορισμένης ακτίνας", + ["command_repair"] = "Επισκέυασε το όχημα σου", + ["command_repair_success"] = "Το όχημα σου επισκευάστηκε", + ["command_repair_success_target"] = "Ένας διαχειριστής επισκεύασε το όχημα σου", + ["command_clear"] = "Καθαρισμός κειμένου στο chat", + ["command_clearall"] = "Καθαρισμός κειμένου στο chat για όλους τους παίκτες", + ["command_clearinventory"] = "Κατάργηση όλων των αντικειμένων από την αποθήκη των παικτών", + ["command_clearloadout"] = "Κατάργηση όλων των όπλων από την εξάρτηση των παικτών", + ["command_freeze"] = "Πάγωμα ενός παίκτη", + ["command_unfreeze"] = "Ξεπάγωμα ενός παίκτη", + ["command_giveaccountmoney"] = "Δώστε χρήματα σε καθορισμένο λογαριασμό", + ["command_giveaccountmoney_account"] = "Λογαριασμός προς προσθήκη", + ["command_giveaccountmoney_amount"] = "Ποσό προς προσθήκη", + ["command_giveaccountmoney_invalid"] = "Μη έγκυρο όνομα λογαριασμού", + ["command_removeaccountmoney"] = "Κατάργηση χρημάτων από καθορισμένο λογαριασμό", + ["command_removeaccountmoney_account"] = "Λογαριασμός από τον οποίο θα καταργηθούν τα χρήματα", + ["command_removeaccountmoney_amount"] = "Ποσό προς αφαίρεση", + ["command_removeaccountmoney_invalid"] = "Μη έγκυρο όνομα λογαριασμού", + ["command_giveitem"] = "Δώστε σε έναν παίκτη ένα αντικείμενο", + ["command_giveitem_item"] = "Όνομα αντικειμένου", + ["command_giveitem_count"] = "Ποσότητα", + ["command_giveweapon"] = "Δώστε σε έναν παίκτη ένα όπλο", + ["command_giveweapon_weapon"] = "Όνομα όπλου", + ["command_giveweapon_ammo"] = "Ποσότητα πυρομαχικών", + ["command_giveweapon_hasalready"] = "Ο παίκτης έχει ήδη αυτό το όπλο", + ["command_giveweaponcomponent"] = "Δώστε σε έναν παίκτη μια εξάρτηση όπλου", + ["command_giveweaponcomponent_component"] = "Όνομα εξάρτησης", + ["command_giveweaponcomponent_invalid"] = "Μη έγκυρη εξάρτηση όπλου", + ["command_giveweaponcomponent_hasalready"] = "Ο παίκτης έχει ήδη αυτήν την εξάρτηση όπλου", + ["command_giveweaponcomponent_missingweapon"] = "Ο παίκτης δεν έχει αυτό το όπλο", + ["command_goto"] = "Τηλεμεταφέρεστε σε έναν παίκτη", + ["command_kill"] = "Σκοτώστε έναν παίκτη", + ["command_save"] = "Εξαναγκαστική αποθήκευση δεδομένων ενός παίκτη", + ["command_saveall"] = "Εξαναγκαστική αποθήκευση όλων των δεδομένων των παικτών", + ["command_setaccountmoney"] = "Ορίστε τα χρήματα σε έναν καθορισμένο λογαριασμό", + ["command_setaccountmoney_amount"] = "Ποσό", + ["command_setcoords"] = "Τηλεμεταφερθείτε σε καθορισμένες συντεταγμένες", + ["command_setcoords_x"] = "Τιμή X", + ["command_setcoords_y"] = "Τιμή Y", + ["command_setcoords_z"] = "Τιμή Z", + ["command_setjob"] = "Ορίστε το επάγγελμα ενός παίκτη", + ["command_setjob_job"] = "Όνομα", + ["command_setjob_grade"] = "Βαθμός επαγγέλματος", + ["command_setjob_invalid"] = "Το επάγγελμα, ο βαθμός ή και οι δύο είναι μη έγκυρα", + ["command_setgroup"] = "Ορίστε την ομάδα δικαιωμάτων ενός παίκτη", + ["command_setgroup_group"] = "Όνομα Ομάδας", + ["commanderror_argumentmismatch"] = "Μη έγκυρος αριθμός ορισμάτων (δόθηκαν %s, αναμενόμενα %s)", + ["commanderror_argumentmismatch_number"] = "Μη έγκυρος τύπος δεδομένων για το όρισμα #%s (δόθηκε συμβολοσειρά, αναμενόμενος αριθμός)", + ["commanderror_argumentmismatch_string"] = "Μη έγκυρος τύπος δεδομένων για το όρισμα #%s (δόθηκε αριθμός, αναμενόμενη συμβολοσειρά)", + ["commanderror_argumentmismatch_positive_number"] = "Μη έγκυρος τύπος δεδομένων για το όρισμα #%s (δόθηκε αρνητικός/μηδέν, αναμενόμενος θετικός αριθμός)", + ["commanderror_invaliditem"] = "Μη έγκυρο αντικείμενο", + ["commanderror_invalidweapon"] = "Μη έγκυρο όπλο", + ["commanderror_console"] = "Η εντολή δεν μπορεί να εκτελεστεί από την κονσόλα", + ["commanderror_invalidcommand"] = "Μη έγκυρη εντολή - /%s", + ["commanderror_invalidplayerid"] = "Ο καθορισμένος παίκτης δεν είναι συνδεδεμένος", + ["commandgeneric_playerid"] = "Αναγνωριστικό διακομιστή του παίκτη", + ["command_giveammo_noweapon_found"] = "Ο %s δεν έχει αυτό το όπλο", + ["command_giveammo_weapon"] = "Όνομα όπλου", + ["command_giveammo_ammo"] = "Ποσότητα πυρομαχικών", + ["tpm_nowaypoint"] = "Δεν έχει οριστεί σημείο προορισμού.", + ["tpm_success"] = "Επιτυχής τηλεμεταφορά", + + ["noclip_message"] = "Το Noclip έχει %s", + ["enabled"] = "~g~ενεργοποιήθηκε~s~", + ["disabled"] = "~r~απενεργοποιήθηκε~s~", + + -- Ρυθμίσεις τοπικής γλώσσας + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "£%s", + + -- Όπλα + + -- Χειροποίητα + ["weapon_dagger"] = "Στιλέτο", + ["weapon_bat"] = "Μπαστούνι", + ["weapon_battleaxe"] = "Πολεμική σείρα", + ["weapon_bottle"] = "Μπουκάλι", + ["weapon_crowbar"] = "Ροπαλάκι", + ["weapon_flashlight"] = "Φακός", + ["weapon_golfclub"] = "Γκολφ", + ["weapon_hammer"] = "Σφυρί", + ["weapon_hatchet"] = "Πέλεκυς", + ["weapon_knife"] = "Μαχαίρι", + ["weapon_knuckle"] = "Χειροπέδες", + ["weapon_machete"] = "Μαχαίρι μαχαιροπίρουνου", + ["weapon_nightstick"] = "Ρόπαλο νυχτερίδας", + ["weapon_wrench"] = "Ροκανίδι", + ["weapon_poolcue"] = "Καστήλα", + ["weapon_stone_hatchet"] = "Πέλεκυς από πέτρα", + ["weapon_switchblade"] = "Ξυραφάκι", + + -- Πιστόλια + ["weapon_appistol"] = "AP Πιστόλι", + ["weapon_ceramicpistol"] = "Κεραμικό πιστόλι", + ["weapon_combatpistol"] = "Πολεμικό πιστόλι", + ["weapon_doubleaction"] = "Διπλής δράσης Ριβόλβερ", + ["weapon_navyrevolver"] = "Ναυτικό Ρεβόλβερ", + ["weapon_flaregun"] = "Πιστόλι αστραπών", + ["weapon_gadgetpistol"] = "Πιστόλι συσκευών", + ["weapon_heavypistol"] = "Βαρύ πιστόλι", + ["weapon_revolver"] = "Βαρύ Ρεβόλβερ", + ["weapon_revolver_mk2"] = "Βαρύ Ρεβόλβερ MK2", + ["weapon_marksmanpistol"] = "Πιστόλι μονομάχου", + ["weapon_pistol"] = "Πιστόλι", + ["weapon_pistol_mk2"] = "Πιστόλι MK2", + ["weapon_pistol50"] = "Πιστόλι .50", + ["weapon_snspistol"] = "Πιστόλι SNS", + ["weapon_snspistol_mk2"] = "Πιστόλι SNS MK2", + ["weapon_stungun"] = "Ηλεκτροπληξία", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Βιομηχανικό πιστόλι", + + -- Καραμπίνες + ["weapon_assaultshotgun"] = "Πολεμική Καραμπίνα", + ["weapon_autoshotgun"] = "Αυτόματη Καραμπίνα", + ["weapon_bullpupshotgun"] = "Bullpup Καραμπίνα", + ["weapon_combatshotgun"] = "Καραμπίνα πολέμου", + ["weapon_dbshotgun"] = "Διπλής κάννης Καραμπίνα", + ["weapon_heavyshotgun"] = "Βαριά Καραμπίνα", + ["weapon_musket"] = "Μουσκέτα", + ["weapon_pumpshotgun"] = "Καραμπίνα αντλίας", + ["weapon_pumpshotgun_mk2"] = "Καραμπίνα αντλίας MK2", + ["weapon_sawnoffshotgun"] = "Καραμπίνα με κοντά κάννη", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Πολεμικό SMG", + ["weapon_combatmg"] = "Πολεμικό MG", + ["weapon_combatmg_mk2"] = "Πολεμικό MG MK2", + ["weapon_combatpdw"] = "Πολεμικό PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Πιστόλι Αυτόματης Καραμπίνας", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Μικρό SMG", + ["weapon_minismg"] = "Μικρό SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Ανεξίτηλο Hellbringer", + + -- Καραμπίνες + ["weapon_advancedrifle"] = "Προηγμένη Καραμπίνα", + ["weapon_assaultrifle"] = "Καραμπίνα Επίθεσης", + ["weapon_assaultrifle_mk2"] = "Καραμπίνα Επίθεσης MK2", + ["weapon_bullpuprifle"] = "Bullpup Καραμπίνα", + ["weapon_bullpuprifle_mk2"] = "Bullpup Καραμπίνα MK2", + ["weapon_carbinerifle"] = "Καραμπίνα", + ["weapon_carbinerifle_mk2"] = "Καραμπίνα MK2", + ["weapon_compactrifle"] = "Συμπαγής Καραμπίνα", + ["weapon_militaryrifle"] = "Στρατιωτική Καραμπίνα", + ["weapon_specialcarbine"] = "Ειδική Καραμπίνα", + ["weapon_specialcarbine_mk2"] = "Ειδική Καραμπίνα MK2", + + -- Κυνηγετικά + ["weapon_heavysniper"] = "Βαρύ Κυνηγετικό Ρίφλε", + ["weapon_heavysniper_mk2"] = "Βαρύ Κυνηγετικό Ρίφλε MK2", + ["weapon_marksmanrifle"] = "Ρίφλε Επαγγελματία Σκοπευτή", + ["weapon_marksmanrifle_mk2"] = "Ρίφλε Επαγγελματία Σκοπευτή MK2", + ["weapon_sniperrifle"] = "Κυνηγετικό Ρίφλε", + ["weapon_heavyrifle"] = "βαρύ τουφέκι", + + -- Βαριά / Εκτοξευτές + ["weapon_compactlauncher"] = "Συμπαγής Εκτοξευτής", + ["weapon_firework"] = "Εκτοξευτής Πυροτεχνημάτων", + ["weapon_grenadelauncher"] = "Εκτοξευτής Γρανατών", + ["weapon_hominglauncher"] = "Εκτοξευτής Εξόρυξης", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Εκτοξευτής Πυραύλων", + ["weapon_rayminigun"] = "Widowmaker", + + -- Επιπλέον Όπλα από το Criminal Enterprises DLC + ["weapon_metaldetector"] = "Ανιχνευτής Μετάλλων", + ["weapon_precisionrifle"] = "Όπλο Ακρίβειας", + ["weapon_tactilerifle"] = "Όπλο Εξυπηρέτησης", + + -- Drug wars dlc + ["weapon_candycane"] = "Candycane", + ["weapon_acidpackage"] = "Acid Package", + ["weapon_pistolxm3"] = "Pistol8 x3m", + ["weapon_railgunxm3"] = "Railgun", + + -- Ρίψεις + ["weapon_ball"] = "Μπάλα", + ["weapon_bzgas"] = "BZ Gas", + ["weapon_flare"] = "Πυροτεχνήματα", + ["weapon_grenade"] = "Χειροβομβίδα", + ["weapon_petrolcan"] = "Κανέλα Βενζίνης", + ["weapon_hazardcan"] = "Κανέλα Επικίνδυνης Υλικότητας", + ["weapon_molotov"] = "Μολότοφ", + ["weapon_proxmine"] = "Νάρκη Εγγύτητας", + ["weapon_pipebomb"] = "Βόμβα Σωλήνα", + ["weapon_snowball"] = "Χιονόμπαλα", + ["weapon_stickybomb"] = "Κολλητή Βόμβα", + ["weapon_smokegrenade"] = "Δακρυγόνο", + + -- Ειδικά + ["weapon_fireextinguisher"] = "Πυροσβεστήρας", + ["weapon_digiscanner"] = "Ψηφιακός Σαρωτής", + ["weapon_garbagebag"] = "Σακούλα Απορριμμάτων", + ["weapon_handcuffs"] = "Χειροπέδες", + ["gadget_nightvision"] = "Νυχτερινή Όραση", + ["gadget_parachute"] = "Αλεξίπτωτο", + + -- Συστατικά Όπλων + ["component_knuckle_base"] = "Βασικό Μοντέλο", + ["component_knuckle_pimp"] = "Ο Φιλότιμος", + ["component_knuckle_ballas"] = "Οι Ballas", + ["component_knuckle_dollar"] = "Ο Εξαπατητής", + ["component_knuckle_diamond"] = "Η Ρόκα", + ["component_knuckle_hate"] = "Ο Μισητός", + ["component_knuckle_love"] = "Ο Εραστής", + ["component_knuckle_player"] = "Ο Παίκτης", + ["component_knuckle_king"] = "Ο Βασιλιάς", + ["component_knuckle_vagos"] = "Οι Vagos", + + ["component_luxary_finish"] = "Πολυτελές Φινίρισμα Όπλου", + + ["component_handle_default"] = "Προεπιλεγμένη Χειρολαβή", + ["component_handle_vip"] = "Χειρολαβή VIP", + ["component_handle_bodyguard"] = "Χειρολαβή Σωματοφύλακα", + + ["component_vip_finish"] = "Πολυτελές Φινίρισμα VIP", + ["component_bodyguard_finish"] = "Πολυτελές Φινίρισμα Σωματοφύλακα", + + ["component_camo_finish"] = "Ψηφιακό Καμουφλάζ", + ["component_camo_finish2"] = "Καμουφλάζ Πινελίου", + ["component_camo_finish3"] = "Καμουφλάζ Δάσους", + ["component_camo_finish4"] = "Καμουφλάζ Κρανίου", + ["component_camo_finish5"] = "Καμουφλάζ Sessanta Nove", + ["component_camo_finish6"] = "Καμουφλάζ Perseus", + ["component_camo_finish7"] = "Καμουφλάζ Λεοπάρδαλης", + ["component_camo_finish8"] = "Καμουφλάζ Ζέβρας", + ["component_camo_finish9"] = "Γεωμετρικό Καμουφλάζ", + ["component_camo_finish10"] = "Καμουφλάζ Boom", + ["component_camo_finish11"] = "Πατριωτικό Καμουφλάζ", + + ["component_camo_slide_finish"] = "Ψηφιακό Καμουφλάζ Slide", + ["component_camo_slide_finish2"] = "Καμουφλάζ Πινελίου Slide", + ["component_camo_slide_finish3"] = "Καμουφλάζ Δάσους Slide", + ["component_camo_slide_finish4"] = "Καμουφλάζ Κρανίου Slide", + ["component_camo_slide_finish5"] = "Καμουφλάζ Sessanta Nove Slide", + ["component_camo_slide_finish6"] = "Καμουφλάζ Perseus Slide", + ["component_camo_slide_finish7"] = "Καμουφλάζ Λεοπάρδαλης Slide", + ["component_camo_slide_finish8"] = "Καμουφλάζ Ζέβρας Slide", + ["component_camo_slide_finish9"] = "Γεωμετρικό Καμουφλάζ Slide", + ["component_camo_slide_finish10"] = "Καμουφλάζ Boom Slide", + ["component_camo_slide_finish11"] = "Πατριωτικό Καμουφλάζ Slide", + + ["component_clip_default"] = "Προεπιλεγμένο Περιοδικό", + ["component_clip_extended"] = "Επέκταση Περιοδικού", + ["component_clip_drum"] = "Περιοδικό Κάδος", + ["component_clip_box"] = "Περιοδικό Κιβώτιο", + + ["component_scope_holo"] = "Ολογραφική Σκοπευτική Συσκευή", + ["component_scope_small"] = "Μικρή Σκοπευτική Συσκευή", + ["component_scope_medium"] = "Μεσαία Σκοπευτική Συσκευή", + ["component_scope_large"] = "Μεγάλη Σκοπευτική Συσκευή", + ["component_scope"] = "Σκοπευτική Συσκευή Εγκατεστημένη", + ["component_scope_advanced"] = "Προηγμένη Σκοπευτική Συσκευή", + ["component_ironsights"] = "Σκοπευτικά Σιδερά", + + ["component_suppressor"] = "Καταστεναγματοποιητής", + ["component_compensator"] = "Αποζημιωτής", + + ["component_muzzle_flat"] = "Επίπεδο Φρένο Αέρα", + ["component_muzzle_tactical"] = "Τακτικό Φρένο Αέρα", + ["component_muzzle_fat"] = "Φρένο Αέρα Παχύ Άκρο", + ["component_muzzle_precision"] = "Φρένο Αέρα Ακρίβειας", + ["component_muzzle_heavy"] = "Φρένο Αέρα Βαρέως Τύπου", + ["component_muzzle_slanted"] = "Φρένο Αέρα Ανοιγοκλειστό", + ["component_muzzle_split"] = "Φρένο Αέρα Υποκλιμακούμενο", + ["component_muzzle_squared"] = "Φρένο Αέρα Τετραγωνισμένο", + + ["component_flashlight"] = "Φακός", + ["component_grip"] = "Λαβή", + + ["component_barrel_default"] = "Προεπιλεγμένο Κάννα", + ["component_barrel_heavy"] = "Βαριά Κάννα", + + ["component_ammo_tracer"] = "Σφαίρες με Ιχνηθέν Φωτός", + ["component_ammo_incendiary"] = "Σφαίρες Φωτιάς", + ["component_ammo_hollowpoint"] = "Σφαίρες Κενές Άκρες", + ["component_ammo_fmj"] = "Σφαίρες FMJ", + ["component_ammo_armor"] = "Σφαίρες Διάτρησης Θωράκισης", + ["component_ammo_explosive"] = "Εκρηκτικές Σφαίρες Διάτρησης Θωράκισης", + + ["component_shells_default"] = "Προεπιλεγμένες Φυσίγγια", + ["component_shells_incendiary"] = "Φυσίγγια Διαμαντινών", + ["component_shells_armor"] = "Φυσίγγια Θωράκισης Χάλυβα", + ["component_shells_hollowpoint"] = "Φυσίγγια Κενών Άκρων", + ["component_shells_explosive"] = "Φυσίγγια Εκρηκτικών", + + -- Πυρομαχικά Όπλων + ["ammo_rounds"] = "σφαιρίδιο(α)", + ["ammo_shells"] = "φυσίγγιο(α)", + ["ammo_charge"] = "φορτίο", + ["ammo_petrol"] = "γαλόνια καυσίμου", + ["ammo_firework"] = "πυροτεχνήματο(α)", + ["ammo_rockets"] = "πύραυλο(ι)", + ["ammo_grenadelauncher"] = "χειροβομβίδα(ες)", + ["ammo_grenade"] = "χειροβομβίδα(ες)", + ["ammo_stickybomb"] = "βόμβα(ες)", + ["ammo_pipebomb"] = "βόμβα(ες)", + ["ammo_smokebomb"] = "βόμβα(ες) καπνού", + ["ammo_molotov"] = "κοκτέιλ μολότοφ(α)", + ["ammo_proxmine"] = "μίνα(ες) εγγύτητας", + ["ammo_bzgas"] = "κανίστρα(ες)", + ["ammo_ball"] = "μπάλα(ες)", + ["ammo_snowball"] = "χιονόμπαλα(ες)", + ["ammo_flare"] = "φλογοβολίδα(ες)", + ["ammo_flaregun"] = "φλογοβολίδα(ες)", + + -- Επιστρώσεις Όπλων + ["tint_default"] = "προεπιλεγμένο δέρμα", + ["tint_green"] = "πράσινο δέρμα", + ["tint_gold"] = "χρυσό δέρμα", + ["tint_pink"] = "ροζ δέρμα", + ["tint_army"] = "στρατιωτικό δέρμα", + ["tint_lspd"] = "μπλε δέρμα", + ["tint_orange"] = "πορτοκαλί δέρμα", + ["tint_platinum"] = "πλατίνενο δέρμα", + -- MK2 Weapon Tints + ["tint_classic_black"] = "κλασικό μαύρο", + ["tint_classic_gray"] = "κλασικό γκρι", + ["tint_classic_two_tone"] = "κλασικό δίχρωμο", + ["tint_classic_white"] = "κλασικό λευκό", + ["tint_classic_beige"] = "κλασικό μπεζ", + ["tint_classic_green"] = "κλασικό πράσινο", + ["tint_classic_blue"] = "κλασικό μπλε", + ["tint_classic_earth"] = "κλασική γή", + ["tint_classic_brown_black"] = "κλασικό καφέ-μαύρο", + ["tint_contrast_red"] = "αντίθεση κόκκινο", + ["tint_contrast_blue"] = "αντίθεση μπλε", + ["tint_contrast_yellow"] = "αντίθεση κίτρινο", + ["tint_contrast_orange"] = "αντίθεση πορτοκαλί", + ["tint_bold_pink"] = "τολμηρό ροζ", + ["tint_bold_purple_yellow"] = "τολμηρό μοβ-κίτρινο", + ["tint_bold_orange"] = "τολμηρό πορτοκαλί", + ["tint_bold_green_purple"] = "τολμηρό πράσινο-μοβ", + ["tint_bold_red_feat"] = "τολμηρό κόκκινο feat", + ["tint_bold_green_feat"] = "τολμηρό πράσινο feat", + ["tint_bold_cyan_feat"] = "τολμηρό κυανό feat", + ["tint_bold_yellow_feat"] = "τολμηρό κίτρινο feat", + ["tint_bold_red_white"] = "τολμηρό κόκκινο λευκό", + ["tint_bold_blue_white"] = "τολμηρό μπλε λευκό", + ["tint_metallic_gold"] = "μεταλλικό χρυσό", + ["tint_metallic_platinum"] = "μεταλλικό πλατίνα", + ["tint_metallic_gray_lilac"] = "μεταλλικό γκρι λιλά", + ["tint_metallic_purple_lime"] = "μεταλλικό μοβ-λάιμ", + ["tint_metallic_red"] = "μεταλλικό κόκκινο", + ["tint_metallic_green"] = "μεταλλικό πράσινο", + ["tint_metallic_blue"] = "μεταλλικό μπλε", + ["tint_metallic_white_aqua"] = "μεταλλικό λευκό aqua", + ["tint_metallic_red_yellow"] = "μεταλλικό κόκκινο-κίτρινο", +} diff --git a/resources/[core]/es_extended/locales/en.lua b/resources/[core]/es_extended/locales/en.lua new file mode 100644 index 0000000..d951354 --- /dev/null +++ b/resources/[core]/es_extended/locales/en.lua @@ -0,0 +1,428 @@ +return { + -- Inventory + ["inventory"] = "Inventory ( Weight %s / %s )", + ["use"] = "Use", + ["give"] = "Give", + ["remove"] = "Throw", + ["return"] = "Return", + ["give_to"] = "Give to", + ["amount"] = "Amount", + ["giveammo"] = "Give ammo", + ["amountammo"] = "Ammo Amount", + ["noammo"] = "Not Enough!", + ["gave_item"] = "Giving %sx %s to %s", + ["received_item"] = "Received %sx %s from %s", + ["gave_weapon"] = "Giving %s to %s", + ["gave_weapon_ammo"] = "Giving ~o~%sx %s for %s to %s", + ["gave_weapon_withammo"] = "Giving %s with ~o~%sx %s to %s", + ["gave_weapon_hasalready"] = "%s already has a %s", + ["gave_weapon_noweapon"] = "%s does not have that weapon", + ["received_weapon"] = "Received %s from %s", + ["received_weapon_ammo"] = "Received ~o~%sx %s for your %s from %s", + ["received_weapon_withammo"] = "Received %s with ~o~%sx %s from %s", + ["received_weapon_hasalready"] = "%s has attempted to give you a %s, but you already this weapon", + ["received_weapon_noweapon"] = "%s has attempted to give you ammo for a %s, but you do not have this weapon", + ["gave_account_money"] = "Giving $%s (%s) to %s", + ["received_account_money"] = "Received $%s (%s) from %s", + ["amount_invalid"] = "Invalid quantity", + ["players_nearby"] = "No nearby Players", + ["ex_inv_lim"] = "Cannot perfom action,exceeding max weight of %s", + ["imp_invalid_quantity"] = "Cannot perfom action, the quantity is invalid", + ["imp_invalid_amount"] = "Cannot perfom action, the amount is invalid", + ["threw_standard"] = "Throwing %sx %s", + ["threw_account"] = "Throwing $%s %s", + ["threw_weapon"] = "Throwing %s", + ["threw_weapon_ammo"] = "Throwing %s with ~o~%sx %s", + ["threw_weapon_already"] = "You already have this weapon", + ["threw_cannot_pickup"] = "Inventory is full, Cannot Pickup!", + ["threw_pickup_prompt"] = "Press E to Pickup", + + -- Key mapping + ["keymap_showinventory"] = "Show Inventory", + + -- Salary related + ["received_salary"] = "You have been paid: $%s", + ["received_help"] = "You have been paid your welfare check: $%s", + ["company_nomoney"] = "the company you're employeed at is too poor to pay out your salary", + ["received_paycheck"] = "received paycheck", + ["bank"] = "Maze Bank", + ["account_bank"] = "Bank", + ["account_black_money"] = "Dirty Money", + ["account_money"] = "Cash", + + ["act_imp"] = "Cannot Perform Action", + ["in_vehicle"] = "Cannot Perform Action, Player is in a vehicle", + ["not_in_vehicle"] = "Cannot Perform Action, Player isn't in a vehicle", + + -- Commands + ["command_bring"] = "Bring player to you", + ["command_car"] = "Spawn a vehicle", + ["command_car_car"] = "Vehicle model or hash", + ["command_cardel"] = "Remove vehicles in proximity", + ["command_cardel_radius"] = "Removes all vehicles within the specified radius", + ["command_repair"] = "Repair your vehicle", + ["command_repair_success"] = "Successfully repaired vehicle", + ["command_repair_success_target"] = "An admin repaired your vehicle", + ["command_clear"] = "Clear chat Text", + ["command_clearall"] = "Clear chat Text for all players", + ["command_refreshitems"] = "Reload all items from the database.", + ["command_refreshitems_success"] = "Successfully reloaded %d items.", + ["command_clearinventory"] = "Remove All items from the Players Inventory", + ["command_clearloadout"] = "Remove All weapons from the Players Loadout", + ["command_freeze"] = "Freeze a player", + ["command_unfreeze"] = "Unfreeze a player", + ["command_giveaccountmoney"] = "Give Money to a specified Account", + ["command_giveaccountmoney_account"] = "Account to add to", + ["command_giveaccountmoney_amount"] = "Amount to add", + ["command_giveaccountmoney_invalid"] = "Account Name Invalid", + ["command_removeaccountmoney"] = "Remove Money from a specified Account", + ["command_removeaccountmoney_account"] = "Account to remove from", + ["command_removeaccountmoney_amount"] = "Amount to remove", + ["command_removeaccountmoney_invalid"] = "Account Name Invalid", + ["command_giveitem"] = "Give Player an item", + ["command_giveitem_item"] = "Item name", + ["command_giveitem_count"] = "Quantity", + ["command_giveweapon"] = "Give player a weapon", + ["command_giveweapon_weapon"] = "Weapon name", + ["command_giveweapon_ammo"] = "Ammo Quantity", + ["command_giveweapon_hasalready"] = "Player already has this weapon", + ["command_giveweaponcomponent"] = "Give weapon component to player", + ["command_giveweaponcomponent_component"] = "Component name", + ["command_giveweaponcomponent_invalid"] = "Invalid weapon component", + ["command_giveweaponcomponent_hasalready"] = "Player already has this weapon component", + ["command_giveweaponcomponent_missingweapon"] = "Player does not have this weapon", + ["command_goto"] = "Teleport yourself to a player", + ["command_kill"] = "Kill a player", + ["command_save"] = "Force Save a player`s Data", + ["command_saveall"] = "Force Save all player data", + ["command_setaccountmoney"] = "Set the money within a specified account", + ["command_setaccountmoney_amount"] = "Amount", + ["command_setcoords"] = "Teleport to specified Coordinates", + ["command_setcoords_x"] = "X value", + ["command_setcoords_y"] = "Y value", + ["command_setcoords_z"] = "Z value", + ["command_setjob"] = "Set a player`s job", + ["command_setjob_job"] = "Name", + ["command_setjob_grade"] = "Job grade", + ["command_setjob_invalid"] = "the job, grade or both are invalid", + ["command_setgroup"] = "Set a players permission group", + ["command_setgroup_group"] = "Name of Group", + ["commanderror_argumentmismatch"] = "Invalid Argument Count (passed %s, wanted %s)", + ["commanderror_argumentmismatch_number"] = "Invalid Argument #%s data type (passed string, wanted number)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (passed number, wanted string)", + ["commanderror_argumentmismatch_positive_number"] = "Invalid Argument #%s data type (passed negative/zero, wanted positive number)", + ["commanderror_invaliditem"] = "Invalid item", + ["commanderror_invalidweapon"] = "Invalid weapon", + ["commanderror_console"] = "Command Cannot be executed from console", + ["commanderror_invalidcommand"] = "Invalid Command - /%s", + ["commanderror_invalidplayerid"] = "Specified Player is not online", + ["commandgeneric_playerid"] = "Player`s Server Id", + ["commandgeneric_dimension"] = "Target Dimension", + ["command_giveammo_noweapon_found"] = "%s does not have that weapon", + ["command_giveammo_weapon"] = "Weapon name", + ["command_giveammo_ammo"] = "Ammo Quantity", + ["command_setdim"] = "Set a players dimension", + ["tpm_nowaypoint"] = "No Waypoint Set.", + ["tpm_success"] = "Successfully Teleported", + + ["noclip_message"] = "Noclip has been %s", + ["enabled"] = "~g~enabled~s~", + ["disabled"] = "~r~disabled~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "£%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dagger", + ["weapon_bat"] = "Bat", + ["weapon_battleaxe"] = "Battle Axe", + ["weapon_bottle"] = "Bottle", + ["weapon_crowbar"] = "Crowbar", + ["weapon_flashlight"] = "Flashlight", + ["weapon_golfclub"] = "Golf Club", + ["weapon_hammer"] = "Hammer", + ["weapon_hatchet"] = "Hatchet", + ["weapon_knife"] = "Knife", + ["weapon_knuckle"] = "Knuckledusters", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Nightstick", + ["weapon_wrench"] = "Pipe Wrench", + ["weapon_poolcue"] = "Pool Cue", + ["weapon_stone_hatchet"] = "Stone Hatchet", + ["weapon_switchblade"] = "Switchblade", + + -- Handguns + ["weapon_appistol"] = "AP Pistol", + ["weapon_ceramicpistol"] = "Ceramic Pistol", + ["weapon_combatpistol"] = "Combat Pistol", + ["weapon_doubleaction"] = "Double-Action Revolver", + ["weapon_navyrevolver"] = "Navy Revolver", + ["weapon_flaregun"] = "Flaregun", + ["weapon_gadgetpistol"] = "Gadget Pistol", + ["weapon_heavypistol"] = "Heavy Pistol", + ["weapon_revolver"] = "Heavy Revolver", + ["weapon_revolver_mk2"] = "Heavy Revolver MK2", + ["weapon_marksmanpistol"] = "Marksman Pistol", + ["weapon_pistol"] = "Pistol", + ["weapon_pistol_mk2"] = "Pistol MK2", + ["weapon_pistol50"] = "Pistol .50", + ["weapon_snspistol"] = "SNS Pistol", + ["weapon_snspistol_mk2"] = "SNS Pistol MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Vintage Pistol", + + -- Shotguns + ["weapon_assaultshotgun"] = "Assault Shotgun", + ["weapon_autoshotgun"] = "Auto Shotgun", + ["weapon_bullpupshotgun"] = "Bullpup Shotgun", + ["weapon_combatshotgun"] = "Combat Shotgun", + ["weapon_dbshotgun"] = "Double Barrel Shotgun", + ["weapon_heavyshotgun"] = "Heavy Shotgun", + ["weapon_musket"] = "Musket", + ["weapon_pumpshotgun"] = "Pump Shotgun", + ["weapon_pumpshotgun_mk2"] = "Pump Shotgun MK2", + ["weapon_sawnoffshotgun"] = "Sawed Off Shotgun", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Assault SMG", + ["weapon_combatmg"] = "Combat MG", + ["weapon_combatmg_mk2"] = "Combat MG MK2", + ["weapon_combatpdw"] = "Combat PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Machine Pistol", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Unholy Hellbringer", + ["weapon_tecpistol"] = "Tactical SMG", + + -- Rifles + ["weapon_advancedrifle"] = "Advanced Rifle", + ["weapon_assaultrifle"] = "Assault Rifle", + ["weapon_assaultrifle_mk2"] = "Assault Rifle MK2", + ["weapon_bullpuprifle"] = "Bullpup Rifle", + ["weapon_bullpuprifle_mk2"] = "Bullpup Rifle MK2", + ["weapon_carbinerifle"] = "Carbine Rifle", + ["weapon_carbinerifle_mk2"] = "Carbine Rifle MK2", + ["weapon_compactrifle"] = "Compact Rifle", + ["weapon_militaryrifle"] = "Military Rifle", + ["weapon_specialcarbine"] = "Special Carbine", + ["weapon_specialcarbine_mk2"] = "Special Carbine MK2", + ["weapon_heavyrifle"] = "Heavy Rifle", + ["weapon_battlerifle"] = "Battle Rifle", + + -- Sniper + ["weapon_heavysniper"] = "Heavy Sniper", + ["weapon_heavysniper_mk2"] = "Heavy Sniper MK2", + ["weapon_marksmanrifle"] = "Marksman Rifle", + ["weapon_marksmanrifle_mk2"] = "Marksman Rifle MK2", + ["weapon_sniperrifle"] = "Sniper Rifle", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Compact Launcher", + ["weapon_firework"] = "Firework Launcher", + ["weapon_grenadelauncher"] = "Grenade Launcher", + ["weapon_hominglauncher"] = "Homing Launcher", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Rocket Launcher", + ["weapon_rayminigun"] = "Widowmaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Metal Detector", + ["weapon_precisionrifle"] = "Precision Rifle", + ["weapon_tactilerifle"] = "Service Carbine", + + -- Drug wars dlc + ["weapon_candycane"] = "Candycane", + ["weapon_acidpackage"] = "Acid Package", + ["weapon_pistolxm3"] = "Pistol8 x3m", + ["weapon_railgunxm3"] = "Railgun", + + -- Chop Shop DLC + ["weapon_snowlauncher"] = "Snow Launcher", + ["weapon_hackingdevice"] = "Hacking Device", + + -- Bottom Dollar Bounties DLC + ["weapon_stunrod"] = "The Shocker", + + -- Thrown + ["weapon_ball"] = "Baseball", + ["weapon_bzgas"] = "BZ Gas", + ["weapon_flare"] = "Flare", + ["weapon_grenade"] = "Grenade", + ["weapon_petrolcan"] = "Jerrycan", + ["weapon_hazardcan"] = "Hazardous Jerrycan", + ["weapon_molotov"] = "Molotov Cocktail", + ["weapon_proxmine"] = "Proximity Mine", + ["weapon_pipebomb"] = "Pipe Bomb", + ["weapon_snowball"] = "Snowball", + ["weapon_stickybomb"] = "Sticky Bomb", + ["weapon_smokegrenade"] = "Tear Gas", + + -- Special + ["weapon_fireextinguisher"] = "Fire Extinguisher", + ["weapon_digiscanner"] = "Digital Scanner", + ["weapon_garbagebag"] = "Garbage Bag", + ["weapon_handcuffs"] = "Handcuffs", + ["gadget_nightvision"] = "Night Vision", + ["gadget_parachute"] = "parachute", + + -- Weapon Components + ["component_knuckle_base"] = "base Model", + ["component_knuckle_pimp"] = "the Pimp", + ["component_knuckle_ballas"] = "the Ballas", + ["component_knuckle_dollar"] = "the Hustler", + ["component_knuckle_diamond"] = "the Rock", + ["component_knuckle_hate"] = "the Hater", + ["component_knuckle_love"] = "the Lover", + ["component_knuckle_player"] = "the Player", + ["component_knuckle_king"] = "the King", + ["component_knuckle_vagos"] = "the Vagos", + + ["component_luxary_finish"] = "luxary Weapon Finish", + + ["component_handle_default"] = "default Handle", + ["component_handle_vip"] = "vIP Handle", + ["component_handle_bodyguard"] = "bodyguard Handle", + + ["component_vip_finish"] = "vIP Finish", + ["component_bodyguard_finish"] = "bodyguard Finish", + + ["component_camo_finish"] = "digital Camo", + ["component_camo_finish2"] = "brushstroke Camo", + ["component_camo_finish3"] = "woodland Camo", + ["component_camo_finish4"] = "skull Camo", + ["component_camo_finish5"] = "sessanta Nove Camo", + ["component_camo_finish6"] = "perseus Camo", + ["component_camo_finish7"] = "leopard Camo", + ["component_camo_finish8"] = "zebra Camo", + ["component_camo_finish9"] = "geometric Camo", + ["component_camo_finish10"] = "boom Camo", + ["component_camo_finish11"] = "patriotic Camo", + + ["component_camo_slide_finish"] = "digital Slide Camo", + ["component_camo_slide_finish2"] = "brushstroke Slide Camo", + ["component_camo_slide_finish3"] = "woodland Slide Camo", + ["component_camo_slide_finish4"] = "skull Slide Camo", + ["component_camo_slide_finish5"] = "sessanta Nove Slide Camo", + ["component_camo_slide_finish6"] = "perseus Slide Camo", + ["component_camo_slide_finish7"] = "leopard Slide Camo", + ["component_camo_slide_finish8"] = "zebra Slide Camo", + ["component_camo_slide_finish9"] = "geometric Slide Camo", + ["component_camo_slide_finish10"] = "boom Slide Camo", + ["component_camo_slide_finish11"] = "patriotic Slide Camo", + + ["component_clip_default"] = "default Magazine", + ["component_clip_extended"] = "extended Magazine", + ["component_clip_drum"] = "drum Magazine", + ["component_clip_box"] = "box Magazine", + + ["component_scope_holo"] = "holographic Scope", + ["component_scope_small"] = "small Scope", + ["component_scope_medium"] = "medium Scope", + ["component_scope_large"] = "large Scope", + ["component_scope"] = "mounted Scope", + ["component_scope_advanced"] = "advanced Scope", + ["component_ironsights"] = "ironsights", + + ["component_suppressor"] = "suppressor", + ["component_compensator"] = "compensator", + + ["component_muzzle_flat"] = "flat Muzzle Brake", + ["component_muzzle_tactical"] = "tactical Muzzle Brake", + ["component_muzzle_fat"] = "fat-End Muzzle Brake", + ["component_muzzle_precision"] = "precision Muzzle Brake", + ["component_muzzle_heavy"] = "heavy Duty Muzzle Brake", + ["component_muzzle_slanted"] = "slanted Muzzle Brake", + ["component_muzzle_split"] = "split-End Muzzle Brake", + ["component_muzzle_squared"] = "squared Muzzle Brake", + + ["component_flashlight"] = "flashlight", + ["component_grip"] = "grip", + + ["component_barrel_default"] = "default Barrel", + ["component_barrel_heavy"] = "heavy Barrel", + + ["component_ammo_tracer"] = "tracer Ammo", + ["component_ammo_incendiary"] = "incendiary Ammo", + ["component_ammo_hollowpoint"] = "hollowpoint Ammo", + ["component_ammo_fmj"] = "fMJ Ammo", + ["component_ammo_armor"] = "armor Piercing Ammo", + ["component_ammo_explosive"] = "armor Piercing Incendiary Ammo", + + ["component_shells_default"] = "default Shells", + ["component_shells_incendiary"] = "dragons Breath Shells", + ["component_shells_armor"] = "steel Buckshot Shells", + ["component_shells_hollowpoint"] = "flechette Shells", + ["component_shells_explosive"] = "explosive Slug Shells", + + -- Weapon Ammo + ["ammo_rounds"] = "round(s)", + ["ammo_shells"] = "shell(s)", + ["ammo_charge"] = "charge", + ["ammo_petrol"] = "gallons of fuel", + ["ammo_firework"] = "firework(s)", + ["ammo_rockets"] = "rocket(s)", + ["ammo_grenadelauncher"] = "grenade(s)", + ["ammo_grenade"] = "grenade(s)", + ["ammo_stickybomb"] = "bomb(s)", + ["ammo_pipebomb"] = "bomb(s)", + ["ammo_smokebomb"] = "bomb(s)", + ["ammo_molotov"] = "cocktail(s)", + ["ammo_proxmine"] = "mine(s)", + ["ammo_bzgas"] = "can(s)", + ["ammo_ball"] = "ball(s)", + ["ammo_snowball"] = "snowball(s)", + ["ammo_flare"] = "flare(s)", + ["ammo_flaregun"] = "flare(s)", + + -- Weapon Tints + ["tint_default"] = "default skin", + ["tint_green"] = "green skin", + ["tint_gold"] = "gold skin", + ["tint_pink"] = "pink skin", + ["tint_army"] = "army skin", + ["tint_lspd"] = "blue skin", + ["tint_orange"] = "orange skin", + ["tint_platinum"] = "platinum skin", + -- MK2 Weapon Tints + ["tint_classic_black"] = "classic black", + ["tint_classic_gray"] = "classic gray", + ["tint_classic_two_tone"] = "classic two-tone", + ["tint_classic_white"] = "classic white", + ["tint_classic_beige"] = "classic beige", + ["tint_classic_green"] = "classic green", + ["tint_classic_blue"] = "classic blue", + ["tint_classic_earth"] = "classic earth", + ["tint_classic_brown_black"] = "classic brown-black", + ["tint_contrast_red"] = "contrast red", + ["tint_contrast_blue"] = "contrast blue", + ["tint_contrast_yellow"] = "contrast yellow", + ["tint_contrast_orange"] = "contrast orange", + ["tint_bold_pink"] = "bold pink", + ["tint_bold_purple_yellow"] = "bold purple-yellow", + ["tint_bold_orange"] = "bold orange", + ["tint_bold_green_purple"] = "bold green-purple", + ["tint_bold_red_feat"] = "bold red feat", + ["tint_bold_green_feat"] = "bold green feat", + ["tint_bold_cyan_feat"] = "bold cyan feat", + ["tint_bold_yellow_feat"] = "bold yellow feat", + ["tint_bold_red_white"] = "bold red-white", + ["tint_bold_blue_white"] = "bold blue-white", + ["tint_metallic_gold"] = "metallic gold", + ["tint_metallic_platinum"] = "metallic platinum", + ["tint_metallic_gray_lilac"] = "metallic gray-lilac", + ["tint_metallic_purple_lime"] = "metallic purple-lime", + ["tint_metallic_red"] = "metallic red", + ["tint_metallic_green"] = "metallic green", + ["tint_metallic_blue"] = "metallic blue", + ["tint_metallic_white_aqua"] = "metallic white-aqua", + ["tint_metallic_red_yellow"] = "metallic red-yellow", +} diff --git a/resources/[core]/es_extended/locales/es.lua b/resources/[core]/es_extended/locales/es.lua new file mode 100644 index 0000000..5750812 --- /dev/null +++ b/resources/[core]/es_extended/locales/es.lua @@ -0,0 +1,426 @@ +return { + -- Inventory + ["inventory"] = "Inventario (Peso %s / %s)", + ["use"] = "Usar", + ["give"] = "Dar", + ["remove"] = "Tirar", + ["return"] = "Devolver", + ["give_to"] = "Dar a", + ["amount"] = "Cantidad", + ["giveammo"] = "Dar munición", + ["amountammo"] = "Cantidad de munición", + ["noammo"] = "¡Insuficiente!", + ["gave_item"] = "Dando %sx %s a %s", + ["received_item"] = "Recibido %sx %s de %s", + ["gave_weapon"] = "Dando %s a %s", + ["gave_weapon_ammo"] = "Dando ~o~%sx %s para %s a %s", + ["gave_weapon_withammo"] = "Dando %s con ~o~%sx %s a %s", + ["gave_weapon_hasalready"] = "%s ya tiene un %s", + ["gave_weapon_noweapon"] = "%s no tiene esa arma", + ["received_weapon"] = "Recibido %s de %s", + ["received_weapon_ammo"] = "Recibido ~o~%sx %s para tu %s de %s", + ["received_weapon_withammo"] = "Recibido %s con ~o~%sx %s de %s", + ["received_weapon_hasalready"] = "%s ha intentado darte un %s, pero ya tienes esta arma", + ["received_weapon_noweapon"] = "%s ha intentado darte munición para un %s, pero no tienes esta arma", + ["gave_account_money"] = "Dando $%s (%s) a %s", + ["received_account_money"] = "Recibido $%s (%s) de %s", + ["amount_invalid"] = "Cantidad inválida", + ["players_nearby"] = "No hay jugadores cerca", + ["ex_inv_lim"] = "No se puede realizar la acción, se excede el peso máximo de %s", + ["imp_invalid_quantity"] = "No se puede realizar la acción, la cantidad es inválida", + ["imp_invalid_amount"] = "No se puede realizar la acción, la cantidad es inválida", + ["threw_standard"] = "Tirando %sx %s", + ["threw_account"] = "Tirando $%s %s", + ["threw_weapon"] = "Tirando %s", + ["threw_weapon_ammo"] = "Tirando %s con ~o~%sx %s", + ["threw_weapon_already"] = "Ya tienes esta arma", + ["threw_cannot_pickup"] = "¡Inventario lleno, no se puede recoger!", + ["threw_pickup_prompt"] = "Pulsa E para recoger", + + -- Key mapping + ["keymap_showinventory"] = "Mostrar inventario", + + -- Salary related + ["received_salary"] = "Has cobrado: $%s", + ["received_help"] = "Has cobrado tu subsidio: $%s", + ["company_nomoney"] = "La empresa para la que trabajas es demasiado pobre para pagarte el sueldo", + ["received_paycheck"] = "Nómina recibida", + ["bank"] = "Maze Bank", + ["account_bank"] = "Banco", + ["account_black_money"] = "Dinero negro", + ["account_money"] = "Efectivo", + + ["act_imp"] = "No se puede realizar la acción", + ["in_vehicle"] = "No se puede realizar la acción, el jugador está en un vehículo", + ["not_in_vehicle"] = "No se puede realizar la acción, el jugador no está en un vehículo", + + -- Commands + ["command_bring"] = "Traer jugador hacia ti", + ["command_car"] = "Generar un vehículo", + ["command_car_car"] = "Modelo o hash del vehículo", + ["command_cardel"] = "Eliminar vehículos cercanos", + ["command_cardel_radius"] = "Elimina todos los vehículos dentro del radio especificado", + ["command_repair"] = "Reparar tu vehículo", + ["command_repair_success"] = "Vehículo reparado con éxito", + ["command_repair_success_target"] = "Un administrador reparó tu vehículo", + ["command_clear"] = "Limpiar texto del chat", + ["command_clearall"] = "Limpiar texto del chat para todos los jugadores", + ["command_clearinventory"] = "Eliminar todos los objetos del inventario del jugador", + ["command_clearloadout"] = "Eliminar todas las armas del equipamiento del jugador", + ["command_freeze"] = "Congelar a un jugador", + ["command_unfreeze"] = "Descongelar a un jugador", + ["command_giveaccountmoney"] = "Dar dinero a una cuenta específica", + ["command_giveaccountmoney_account"] = "Cuenta a la que añadir", + ["command_giveaccountmoney_amount"] = "Cantidad a añadir", + ["command_giveaccountmoney_invalid"] = "Nombre de cuenta inválido", + ["command_removeaccountmoney"] = "Quitar dinero de una cuenta específica", + ["command_removeaccountmoney_account"] = "Cuenta de la que quitar", + ["command_removeaccountmoney_amount"] = "Cantidad a quitar", + ["command_removeaccountmoney_invalid"] = "Nombre de cuenta inválido", + ["command_giveitem"] = "Dar un objeto al jugador", + ["command_giveitem_item"] = "Nombre del objeto", + ["command_giveitem_count"] = "Cantidad", + ["command_giveweapon"] = "Dar un arma al jugador", + ["command_giveweapon_weapon"] = "Nombre del arma", + ["command_giveweapon_ammo"] = "Cantidad de munición", + ["command_giveweapon_hasalready"] = "El jugador ya tiene esta arma", + ["command_giveweaponcomponent"] = "Dar componente de arma al jugador", + ["command_giveweaponcomponent_component"] = "Nombre del componente", + ["command_giveweaponcomponent_invalid"] = "Componente de arma inválido", + ["command_giveweaponcomponent_hasalready"] = "El jugador ya tiene este componente de arma", + ["command_giveweaponcomponent_missingweapon"] = "El jugador no tiene esta arma", + ["command_goto"] = "Teletransportarte a un jugador", + ["command_kill"] = "Matar a un jugador", + ["command_save"] = "Forzar guardado de datos de un jugador", + ["command_saveall"] = "Forzar guardado de todos los datos de los jugadores", + ["command_setaccountmoney"] = "Establecer el dinero en una cuenta específica", + ["command_setaccountmoney_amount"] = "Cantidad", + ["command_setcoords"] = "Teletransportar a coordenadas específicas", + ["command_setcoords_x"] = "Valor X", + ["command_setcoords_y"] = "Valor Y", + ["command_setcoords_z"] = "Valor Z", + ["command_setjob"] = "Establecer el trabajo de un jugador", + ["command_setjob_job"] = "Nombre", + ["command_setjob_grade"] = "Rango del trabajo", + ["command_setjob_invalid"] = "El trabajo, el rango o ambos son inválidos", + ["command_setgroup"] = "Establecer el grupo de permisos de un jugador", + ["command_setgroup_group"] = "Nombre del grupo", + ["commanderror_argumentmismatch"] = "Número de argumentos inválido (pasados %s, esperados %s)", + ["commanderror_argumentmismatch_number"] = "Tipo de datos del argumento #%s inválido (pasado string, esperado número)", + ["commanderror_argumentmismatch_string"] = "Tipo de datos del argumento #%s inválido (pasado número, esperado string)", + ["commanderror_argumentmismatch_positive_number"] = "Argumento inválido #%s tipo de datos (pasado negativo/cero, se requiere número positivo)", + ["commanderror_invaliditem"] = "Objeto inválido", + ["commanderror_invalidweapon"] = "Arma inválida", + ["commanderror_console"] = "El comando no se puede ejecutar desde la consola", + ["commanderror_invalidcommand"] = "Comando inválido - /%s", + ["commanderror_invalidplayerid"] = "El jugador especificado no está en línea", + ["commandgeneric_playerid"] = "ID del servidor del jugador", + ["commandgeneric_dimension"] = "Dimensión de destino", + ["command_giveammo_noweapon_found"] = "%s no tiene esa arma", + ["command_giveammo_weapon"] = "Nombre del arma", + ["command_giveammo_ammo"] = "Cantidad de munición", + ["command_setdim"] = "Establecer la dimensión de un jugador", + ["tpm_nowaypoint"] = "No hay punto de ruta establecido.", + ["tpm_success"] = "Teletransportado con éxito", + + ["noclip_message"] = "Noclip ha sido %s", + ["enabled"] = "~g~activado~s~", + ["disabled"] = "~r~desactivado~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ".", + ["locale_currency"] = "%s€", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Daga", + ["weapon_bat"] = "Bate", + ["weapon_battleaxe"] = "Hacha de guerra", + ["weapon_bottle"] = "Botella", + ["weapon_crowbar"] = "Palanca", + ["weapon_flashlight"] = "Linterna", + ["weapon_golfclub"] = "Palo de golf", + ["weapon_hammer"] = "Martillo", + ["weapon_hatchet"] = "Hachuela", + ["weapon_knife"] = "Cuchillo", + ["weapon_knuckle"] = "Puño americano", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Porra", + ["weapon_wrench"] = "Llave inglesa", + ["weapon_poolcue"] = "Taco de billar", + ["weapon_stone_hatchet"] = "Hacha de piedra", + ["weapon_switchblade"] = "Navaja automática", + + -- Handguns + ["weapon_appistol"] = "Pistola PA", + ["weapon_ceramicpistol"] = "Pistola de cerámica", + ["weapon_combatpistol"] = "Pistola de combate", + ["weapon_doubleaction"] = "Revólver de doble acción", + ["weapon_navyrevolver"] = "Revólver de la Marina", + ["weapon_flaregun"] = "Pistola de bengalas", + ["weapon_gadgetpistol"] = "Pistola de Cayo Perico", + ["weapon_heavypistol"] = "Pistola pesada", + ["weapon_revolver"] = "Revólver pesado", + ["weapon_revolver_mk2"] = "Revólver pesado Mk2", + ["weapon_marksmanpistol"] = "Pistola de tirador", + ["weapon_pistol"] = "Pistola", + ["weapon_pistol_mk2"] = "Pistola Mk2", + ["weapon_pistol50"] = "Pistola .50", + ["weapon_snspistol"] = "Pistola SNS", + ["weapon_snspistol_mk2"] = "Pistola SNS Mk2", + ["weapon_stungun"] = "Pistola eléctrica", + ["weapon_raypistol"] = "Pistola de Rayos", + ["weapon_vintagepistol"] = "Pistola vintage", + + -- Shotguns + ["weapon_assaultshotgun"] = "Escopeta de asalto", + ["weapon_autoshotgun"] = "Escopeta automática", + ["weapon_bullpupshotgun"] = "Escopeta bullpup", + ["weapon_combatshotgun"] = "Escopeta de combate", + ["weapon_dbshotgun"] = "Escopeta de dos cañones", + ["weapon_heavyshotgun"] = "Escopeta pesada", + ["weapon_musket"] = "Mosquete", + ["weapon_pumpshotgun"] = "Escopeta de corredera", + ["weapon_pumpshotgun_mk2"] = "Escopeta de corredera Mk2", + ["weapon_sawnoffshotgun"] = "Escopeta recortada", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Subfusil de asalto", + ["weapon_combatmg"] = "Ametralladora de combate", + ["weapon_combatmg_mk2"] = "Ametralladora de combate Mk2", + ["weapon_combatpdw"] = "PDW de combate", + ["weapon_gusenberg"] = "Subfusil Gusenberg", + ["weapon_machinepistol"] = "Pistola ametralladora", + ["weapon_mg"] = "Ametralladora", + ["weapon_microsmg"] = "Microsubfusil", + ["weapon_minismg"] = "Minisubfusil", + ["weapon_smg"] = "Subfusil", + ["weapon_smg_mk2"] = "Subfusil Mk2", + ["weapon_raycarbine"] = "Carabina de Rayos", + ["weapon_tecpistol"] = "Subfusil táctico", + + -- Rifles + ["weapon_advancedrifle"] = "Fusil avanzado", + ["weapon_assaultrifle"] = "Fusil de asalto", + ["weapon_assaultrifle_mk2"] = "Fusil de asalto Mk2", + ["weapon_bullpuprifle"] = "Fusil bullpup", + ["weapon_bullpuprifle_mk2"] = "Fusil bullpup Mk2", + ["weapon_carbinerifle"] = "Carabina", + ["weapon_carbinerifle_mk2"] = "Carabina Mk2", + ["weapon_compactrifle"] = "Fusil compacto", + ["weapon_militaryrifle"] = "Fusil militar", + ["weapon_specialcarbine"] = "Carabina especial", + ["weapon_specialcarbine_mk2"] = "Carabina especial Mk2", + ["weapon_heavyrifle"] = "Fusil pesado", + ["weapon_battlerifle"] = "Fusil de combate", + + -- Sniper + ["weapon_heavysniper"] = "Francotirador pesado", + ["weapon_heavysniper_mk2"] = "Francotirador pesado Mk2", + ["weapon_marksmanrifle"] = "Fusil de tirador", + ["weapon_marksmanrifle_mk2"] = "Fusil de tirador Mk2", + ["weapon_sniperrifle"] = "Fusil de francotirador", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Lanzagranadas compacto", + ["weapon_firework"] = "Lanzador de pirotecnia", + ["weapon_grenadelauncher"] = "Lanzagranadas", + ["weapon_hominglauncher"] = "Lanzacohetes teledirigido", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Cañón de riel", + ["weapon_rpg"] = "Lanzacohetes", + ["weapon_rayminigun"] = "Ametralladora de rayos", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Detector de metales", + ["weapon_precisionrifle"] = "Fusil de precisión", + ["weapon_tactilerifle"] = "Carabina de servicio", + + -- Drug wars dlc + ["weapon_candycane"] = "Bastón de caramelo", + ["weapon_acidpackage"] = "Paquete de ácido", + ["weapon_pistolxm3"] = "Pistola WM 29", + ["weapon_railgunxm3"] = "Cañón de riel", + + -- Chop Shop DLC + ["weapon_snowlauncher"] = "Lanzador de nieve", + ["weapon_hackingdevice"] = "Dispositivo de hackeo", + + -- Bottom Dollar Bounties DLC + ["weapon_stunrod"] = "Porra eléctrica", + + -- Thrown + ["weapon_ball"] = "Pelota de béisbol", + ["weapon_bzgas"] = "Gas BZ", + ["weapon_flare"] = "Bengala", + ["weapon_grenade"] = "Granada", + ["weapon_petrolcan"] = "Bidón de gasolina", + ["weapon_hazardcan"] = "Bidón de material peligroso", + ["weapon_molotov"] = "Cóctel molotov", + ["weapon_proxmine"] = "Mina de proximidad", + ["weapon_pipebomb"] = "Bomba casera", + ["weapon_snowball"] = "Bola de nieve", + ["weapon_stickybomb"] = "Bomba lapa", + ["weapon_smokegrenade"] = "Granada de humo", + + -- Special + ["weapon_fireextinguisher"] = "Extintor", + ["weapon_digiscanner"] = "Escáner digital", + ["weapon_garbagebag"] = "Bolsa de basura", + ["weapon_handcuffs"] = "Esposas", + ["gadget_nightvision"] = "Visión nocturna", + ["gadget_parachute"] = "Paracaídas", + + -- Weapon Components + ["component_knuckle_base"] = "Modelo base", + ["component_knuckle_pimp"] = "El Chulo", + ["component_knuckle_ballas"] = "Los Ballas", + ["component_knuckle_dollar"] = "El Buscavidas", + ["component_knuckle_diamond"] = "La Roca", + ["component_knuckle_hate"] = "El Odiador", + ["component_knuckle_love"] = "El Amante", + ["component_knuckle_player"] = "El Jugador", + ["component_knuckle_king"] = "El Rey", + ["component_knuckle_vagos"] = "Los Vagos", + + ["component_luxary_finish"] = "Acabado de arma de lujo", + + ["component_handle_default"] = "Empuñadura por defecto", + ["component_handle_vip"] = "Empuñadura VIP", + ["component_handle_bodyguard"] = "Empuñadura de guardaespaldas", + + ["component_vip_finish"] = "Acabado VIP", + ["component_bodyguard_finish"] = "Acabado de guardaespaldas", + + ["component_camo_finish"] = "Camuflaje digital", + ["component_camo_finish2"] = "Camuflaje pincelada", + ["component_camo_finish3"] = "Camuflaje boscoso", + ["component_camo_finish4"] = "Camuflaje calavera", + ["component_camo_finish5"] = "Camuflaje Sessanta Nove", + ["component_camo_finish6"] = "Camuflaje Perseo", + ["component_camo_finish7"] = "Camuflaje leopardo", + ["component_camo_finish8"] = "Camuflaje cebra", + ["component_camo_finish9"] = "Camuflaje geométrico", + ["component_camo_finish10"] = "Camuflaje Boom", + ["component_camo_finish11"] = "Camuflaje patriótico", + + ["component_camo_slide_finish"] = "Camuflaje digital (corredera)", + ["component_camo_slide_finish2"] = "Camuflaje pincelada (corredera)", + ["component_camo_slide_finish3"] = "Camuflaje boscoso (corredera)", + ["component_camo_slide_finish4"] = "Camuflaje calavera (corredera)", + ["component_camo_slide_finish5"] = "Camuflaje Sessanta Nove (corredera)", + ["component_camo_slide_finish6"] = "Camuflaje Perseo (corredera)", + ["component_camo_slide_finish7"] = "Camuflaje leopardo (corredera)", + ["component_camo_slide_finish8"] = "Camuflaje cebra (corredera)", + ["component_camo_slide_finish9"] = "Camuflaje geométrico (corredera)", + ["component_camo_slide_finish10"] = "Camuflaje Boom (corredera)", + ["component_camo_slide_finish11"] = "Camuflaje patriótico (corredera)", + + ["component_clip_default"] = "Cargador por defecto", + ["component_clip_extended"] = "Cargador ampliado", + ["component_clip_drum"] = "Cargador de tambor", + ["component_clip_box"] = "Cargador de caja", + + ["component_scope_holo"] = "Mira holográfica", + ["component_scope_small"] = "Mira pequeña", + ["component_scope_medium"] = "Mira mediana", + ["component_scope_large"] = "Mira telescópica", + ["component_scope"] = "Mira óptica", + ["component_scope_advanced"] = "Mira avanzada", + ["component_ironsights"] = "Miras de hierro", + + ["component_suppressor"] = "Silenciador", + ["component_compensator"] = "Compensador", + + ["component_muzzle_flat"] = "Freno de boca plano", + ["component_muzzle_tactical"] = "Freno de boca táctico", + ["component_muzzle_fat"] = "Freno de boca grueso", + ["component_muzzle_precision"] = "Freno de boca de precisión", + ["component_muzzle_heavy"] = "Freno de boca pesado", + ["component_muzzle_slanted"] = "Freno de boca inclinado", + ["component_muzzle_split"] = "Freno de boca dividido", + ["component_muzzle_squared"] = "Freno de boca cuadrado", + + ["component_flashlight"] = "Linterna", + ["component_grip"] = "Empuñadura", + + ["component_barrel_default"] = "Cañón por defecto", + ["component_barrel_heavy"] = "Cañón pesado", + + ["component_ammo_tracer"] = "Munición trazadora", + ["component_ammo_incendiary"] = "Munición incendiaria", + ["component_ammo_hollowpoint"] = "Munición de punta hueca", + ["component_ammo_fmj"] = "Munición FMJ", + ["component_ammo_armor"] = "Munición perforante", + ["component_ammo_explosive"] = "Munición explosiva perforante", + + ["component_shells_default"] = "Cartuchos por defecto", + ["component_shells_incendiary"] = "Cartuchos Aliento de dragón", + ["component_shells_armor"] = "Cartuchos de postas de acero", + ["component_shells_hollowpoint"] = "Cartuchos de perdigones expansivos", + ["component_shells_explosive"] = "Cartuchos de postas explosivas", + + -- Weapon Ammo + ["ammo_rounds"] = "proyectil(es)", + ["ammo_shells"] = "cartucho(s)", + ["ammo_charge"] = "carga(s)", + ["ammo_petrol"] = "litros de combustible", + ["ammo_firework"] = "cohete(s) de pirotecnia", + ["ammo_rockets"] = "cohete(s)", + ["ammo_grenadelauncher"] = "granada(s)", + ["ammo_grenade"] = "granada(s)", + ["ammo_stickybomb"] = "bomba(s) lapa", + ["ammo_pipebomb"] = "bomba(s) casera", + ["ammo_smokebomb"] = "bomba(s) de humo", + ["ammo_molotov"] = "cóctel(es) molotov", + ["ammo_proxmine"] = "mina(s) de proximidad", + ["ammo_bzgas"] = "bote(s) de gas", + ["ammo_ball"] = "pelota(s)", + ["ammo_snowball"] = "bola(s) de nieve", + ["ammo_flare"] = "bengala(s)", + ["ammo_flaregun"] = "bengala(s)", + + -- Weapon Tints + ["tint_default"] = "Diseño por defecto", + ["tint_green"] = "Diseño verde", + ["tint_gold"] = "Diseño dorado", + ["tint_pink"] = "Diseño rosa", + ["tint_army"] = "Diseño militar", + ["tint_lspd"] = "Diseño LSPD", + ["tint_orange"] = "Diseño naranja", + ["tint_platinum"] = "Diseño platino", + -- MK2 Weapon Tints + ["tint_classic_black"] = "Negro clásico", + ["tint_classic_gray"] = "Gris clásico", + ["tint_classic_two_tone"] = "Dos tonos clásico", + ["tint_classic_white"] = "Blanco clásico", + ["tint_classic_beige"] = "Beige clásico", + ["tint_classic_green"] = "Verde clásico", + ["tint_classic_blue"] = "Azul clásico", + ["tint_classic_earth"] = "Tierra clásico", + ["tint_classic_brown_black"] = "Marrón y negro clásico", + ["tint_contrast_red"] = "Rojo contraste", + ["tint_contrast_blue"] = "Azul contraste", + ["tint_contrast_yellow"] = "Amarillo contraste", + ["tint_contrast_orange"] = "Naranja contraste", + ["tint_bold_pink"] = "Rosa intenso", + ["tint_bold_purple_yellow"] = "Morado y amarillo intenso", + ["tint_bold_orange"] = "Naranja intenso", + ["tint_bold_green_purple"] = "Verde y morado intenso", + ["tint_bold_red_feat"] = "Rojo intenso especial", + ["tint_bold_green_feat"] = "Verde intenso especial", + ["tint_bold_cyan_feat"] = "Cian intenso especial", + ["tint_bold_yellow_feat"] = "Amarillo intenso especial", + ["tint_bold_red_white"] = "Rojo y blanco intenso", + ["tint_bold_blue_white"] = "Azul y blanco intenso", + ["tint_metallic_gold"] = "Dorado metálico", + ["tint_metallic_platinum"] = "Platino metálico", + ["tint_metallic_gray_lilac"] = "Gris lila metálico", + ["tint_metallic_purple_lime"] = "Morado lima metálico", + ["tint_metallic_red"] = "Rojo metálico", + ["tint_metallic_green"] = "Verde metálico", + ["tint_metallic_blue"] = "Azul metálico", + ["tint_metallic_white_aqua"] = "Blanco aguamarina metálico", + ["tint_metallic_red_yellow"] = "Rojo y amarillo metálico", +} diff --git a/resources/[core]/es_extended/locales/fi.lua b/resources/[core]/es_extended/locales/fi.lua new file mode 100644 index 0000000..6cf69f3 --- /dev/null +++ b/resources/[core]/es_extended/locales/fi.lua @@ -0,0 +1,274 @@ +return { + -- Inventory + ["inventory"] = "Reppu %s / %s", + ["use"] = "Käytä", + ["give"] = "Anna", + ["remove"] = "Poista", + ["return"] = "Takaisin", + ["give_to"] = "Anna henkilölle", + ["amount"] = "Määrä", + ["giveammo"] = "Anna ammuksia", + ["amountammo"] = "Ammusten määrä", + ["noammo"] = "Sinulla ei ole ammuksia!", + ["gave_item"] = "Sinä annoit %sx %s henkilölle %s", + ["received_item"] = "Sinä sait %sx %s henkilöltä %s", + ["gave_weapon"] = "Sinä annoit 1x %s henkilölle %s", + ["gave_weapon_ammo"] = "Annoit ~o~%sx %s kohteelle %s henkilölle %s", + ["gave_weapon_withammo"] = "Sinä annoit 1x %s ammuksella ~o~%sx %s henkilölle %s", + ["gave_weapon_hasalready"] = "%s omistaa jo %s", + ["gave_weapon_noweapon"] = "%s ei ole kyseistä asetta", + ["received_weapon"] = "Vastaanotit 1x %s henkilöltä %s", + ["received_weapon_ammo"] = "Sinä sait ~o~%sx %s sinun %s varten henkilöltä %s", + ["received_weapon_withammo"] = "Sinä sait 1x %s ammuksella ~o~%sx %s henkilöltä %s", + ["received_weapon_hasalready"] = "%s yritti antaa sinulle %s, mutta sinulla on jo sellainen", + ["received_weapon_noweapon"] = "%s yritti antaa sinulle ammuksia %s:lle, mutta sinulla ei ole sellaista", + ["gave_account_money"] = "Sinä annoit $%s (%s) henkilölle %s", + ["received_account_money"] = "Sinä sait $%s (%s) henkilöltä %s", + ["amount_invalid"] = "Virheellinen määrä", + ["players_nearby"] = "Ei pelaajia lähettyvillä", + ["ex_inv_lim"] = "Toiminto mahdoton, reppu alkaa olla täysi %s", + ["imp_invalid_quantity"] = "Toiminto mahdoton, virheellinen määrä", + ["imp_invalid_amount"] = "Toiminto mahdoton, virhellinen summa", + ["threw_standard"] = "Sinä heitit %sx %s", + ["threw_account"] = "Sinä heitit $%s %s", + ["threw_weapon"] = "Sinä heitit 1x %s", + ["threw_weapon_ammo"] = "Heitit 1x %s ammuksella ~o~%sx %s", + ["threw_weapon_already"] = "Sinulla on jo sama ase", + ["threw_cannot_pickup"] = "Et voi kerätä sitä, koska reppusi on täynnä", + ["threw_pickup_prompt"] = "Paina E kerätäksesi", + + -- Key mapping + ["keymap_showinventory"] = "Avaa reppu", + + -- Salary related + ["received_salary"] = "Vastaanotit palkkaa: $%s", + ["received_help"] = "Vastaanotit valtion tukea: $%s", + ["company_nomoney"] = "Yrityksellä jolle teet töitä ei ole varaa maksaa palkkaasi", + ["received_paycheck"] = "Sait palkan", + ["bank"] = "Pankki", + ["account_bank"] = "Pankki", + ["account_black_money"] = "Likainen raha", + ["account_money"] = "Käteinen", + + ["act_imp"] = "Toiminto mahdoton", + ["in_vehicle"] = "Et voi antaa ajoneuvossa olevalle mitään", + ["not_in_vehicle"] = "Toimintoa ei voida suorittaa, pelaaja ei ole ajoneuvossa", + + -- Commands + ["command_car"] = "Luo ajoneuvo", + ["command_car_car"] = "Ajoneuvon nimi tai hash", + ["command_cardel"] = "Poistaa ajoneuvon läheltä", + ["command_cardel_radius"] = "Valinnainen, poista kaikki ajoneuvot määritetyllä säteellä", + ["command_repair"] = "Repair your vehicle", + ["command_repair_success"] = "Successfully repaired vehicle", + ["command_repair_success_target"] = "An admin repaired your vehicle", + ["command_clear"] = "Tyhjennä keskustelu", + ["command_clearall"] = "Tyhjennä keskustelu kaikilta pelaajilta", + ["command_clearinventory"] = "Tyhjennä pelaajan reppu", + ["command_clearloadout"] = "Tyhjennä pelaajan varustus", + ["command_giveaccountmoney"] = "Anna tilirahaa", + ["command_giveaccountmoney_account"] = "Kelvollinen tilin nimi", + ["command_giveaccountmoney_amount"] = "Lisättävä määrä", + ["command_giveaccountmoney_invalid"] = "Virheellinen tili nimi", + ["command_giveitem"] = "Anna pelaajalle esine", + ["command_giveitem_item"] = "Esineen nimi", + ["command_giveitem_count"] = "Esineiden määrä", + ["command_giveweapon"] = "Anna pelaajalle ase", + ["command_giveweapon_weapon"] = "Aseen nimi", + ["command_giveweapon_ammo"] = "Ammusten määrä", + ["command_giveweapon_hasalready"] = "Pelaajalla on jo kyseinen ase", + ["command_giveweaponcomponent"] = "Anna aseen komponentti", + ["command_giveweaponcomponent_component"] = "Komponentin nimi", + ["command_giveweaponcomponent_invalid"] = "Virheellinen aseen komponentti", + ["command_giveweaponcomponent_hasalready"] = "Pelaajalla on jo kyseinen asekomponentti", + ["command_giveweaponcomponent_missingweapon"] = "Pelaajalla ei ole kyseistä asetta", + ["command_save"] = "Talenna pelaaja tietokantaan", + ["command_saveall"] = "Tallenna kaikki pelaajat tietokantaan", + ["command_setaccountmoney"] = "Aseta tilirahaa pelaajalle", + ["command_setaccountmoney_amount"] = "Asetettava rahamäärä", + ["command_setcoords"] = "Teleporttaa koordinaatteihin", + ["command_setcoords_x"] = "x akseli", + ["command_setcoords_y"] = "y akseli", + ["command_setcoords_z"] = "z akseli", + ["command_setjob"] = "Aseta pelaajalle ammatti", + ["command_setjob_job"] = "Ammatti", + ["command_setjob_grade"] = "Arvo", + ["command_setjob_invalid"] = "Ammatti ja arvo tai molemmat ovat virheellisiä", + ["command_setgroup"] = "Aseta pelaajan ryhmä", + ["command_setgroup_group"] = "Ryhmän nimi", + ["commanderror_argumentmismatch"] = "Argumenttien määrä ei täsmää (hyväksytty %s, haluttu %s)", + ["commanderror_argumentmismatch_number"] = "Argumentin #%s tyyppi ei täsmää (syötetty merkkijono, haluttu numero)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (passed number, wanted string)", + ["commanderror_argumentmismatch_positive_number"] = "Virheellinen argumentti #%s tietotyyppi (annettu negatiivinen/nolla, haluttu positiivinen luku)", + ["commanderror_invaliditem"] = "Virheellinen esineen nimi", + ["commanderror_invalidweapon"] = "Virheellinen ase", + ["commanderror_console"] = "Komentoa ei voi suorittaa konsolissa", + ["commanderror_invalidcommand"] = "/%s ei ole kelvollinen komento!", + ["commanderror_invalidplayerid"] = "Palvelimella ei ole pelaajaa, joka vastaa annetua ID", + ["commandgeneric_playerid"] = "Pelaajan ID", + ["command_giveammo_noweapon_found"] = "%s ei ole sitä asetta", + ["command_giveammo_weapon"] = "Aseen nimi", + ["command_giveammo_ammo"] = "Ammusten määrä", + + -- Locale settings + ["locale_digit_grouping_symbol"] = "", + ["locale_currency"] = "€%s", + + -- Drug Wars DLC + ["weapon_candycane"] = "Karkkitanko", + ["weapon_acidpackage"] = "Happo pakkaus", + ["weapon_pistolxm3"] = "WM 29 Pistooli", + ["weapon_railgunxm3"] = "Raidetykki", + + -- Weapons + ["weapon_knife"] = "Veitsi", + ["weapon_nightstick"] = "Pamppu", + ["weapon_hammer"] = "Vasara", + ["weapon_bat"] = "Pesäpallomaila", + ["weapon_golfclub"] = "Golf maila", + ["weapon_crowbar"] = "Sorkkarauta", + ["weapon_pistol"] = "Pistooli", + ["weapon_combatpistol"] = "Taistelu pistooli", + ["weapon_appistol"] = "Automaatti pistooli", + ["weapon_pistol50"] = "50 kaliiperinen pistooli", + ["weapon_microsmg"] = "Mikro konepistooli", + ["weapon_smg"] = "Konepistooli", + ["weapon_assaultsmg"] = "Rynnäkkö konepistooli", + ["weapon_assaultrifle"] = "Rynnäkkökivääri", + ["weapon_carbinerifle"] = "Karbiini kivääri", + ["weapon_advancedrifle"] = "Edistynyt kivääri", + ["weapon_mg"] = "Konekivääri", + ["weapon_combatmg"] = "Rynnäkkö konekivääri", + ["weapon_pumpshotgun"] = "Pumppu haulikko", + ["weapon_sawnoffshotgun"] = "Katkaistuhaulikko", + ["weapon_assaultshotgun"] = "Hyökkäyshaulikko", + ["weapon_bullpupshotgun"] = "Bullpup haulikko", + ["weapon_stungun"] = "Tainutusase", + ["weapon_sniperrifle"] = "Tarkkuuskivääri", + ["weapon_heavysniper"] = "Raskas tarkkuuskivääri", + ["weapon_grenadelauncher"] = "Kranaatinheitin", + ["weapon_rpg"] = "Raketinheitin", + ["weapon_minigun"] = "Minigun", + ["weapon_grenade"] = "Kranaatti", + ["weapon_stickybomb"] = "Tahma pommi", + ["weapon_smokegrenade"] = "Savukranaatti", + ["weapon_bzgas"] = "Bz-kaasu", + ["weapon_molotov"] = "Polttopullo", + ["weapon_fireextinguisher"] = "Palosammutin", + ["weapon_petrolcan"] = "Jerrykannu", + ["weapon_ball"] = "Pallo", + ["weapon_snspistol"] = "Pienpistooli", + ["weapon_bottle"] = "Pullo", + ["weapon_gusenberg"] = "Thompson-konepistooli", + ["weapon_specialcarbine"] = "G86C", + ["weapon_heavypistol"] = "Raskas pistooli", + ["weapon_bullpuprifle"] = "Bullpup kivääri", + ["weapon_dagger"] = "Tikari", + ["weapon_vintagepistol"] = "Vanha pistooli", + ["weapon_firework"] = "Ilotulite", + ["weapon_musket"] = "Musketti", + ["weapon_heavyshotgun"] = "Raskas haulikko", + ["weapon_marksmanrifle"] = "Marksman kivääri", + ["weapon_hominglauncher"] = "Ohjautuva raketinheitin", + ["weapon_proxmine"] = "Lähellä räjähtävä miina", + ["weapon_snowball"] = "Lumipallo", + ["weapon_flaregun"] = "Valopistooli", + ["weapon_combatpdw"] = "Rynnäkkö pdw", + ["weapon_marksmanpistol"] = "Marksman pistooli", + ["weapon_knuckle"] = "Nyrkkirauta", + ["weapon_hatchet"] = "Kirves", + ["weapon_railgun"] = "Raidetykki", + ["weapon_machete"] = "Viidakkoveitsi", + ["weapon_machinepistol"] = "Konepistooli", + ["weapon_switchblade"] = "Stiletti", + ["weapon_revolver"] = "Raskas revolveri", + ["weapon_dbshotgun"] = "Kaksipiippunen haulikko", + ["weapon_compactrifle"] = "Pikku AK", + ["weapon_autoshotgun"] = "Automaattinen haulikko", + ["weapon_battleaxe"] = "Taistelukirves", + ["weapon_compactlauncher"] = "Pien kranaatinheitin", + ["weapon_minismg"] = "Mini konepistooli", + ["weapon_pipebomb"] = "Putkipommi", + ["weapon_poolcue"] = "Biljardimaila", + ["weapon_wrench"] = "Putkipihdit", + ["weapon_flashlight"] = "Taskulamppu", + ["gadget_parachute"] = "Laskuvarjo", + ["weapon_flare"] = "Hätäraketti", + ["weapon_doubleaction"] = "Double action revolveri", + ["weapon_heavyrifle"] = "Raskas kivääri", + + -- Weapon Components + ["component_clip_default"] = "Oletus lipas", + ["component_clip_extended"] = "Paranneltu lipas", + ["component_clip_drum"] = "Rumpulipas", + ["component_clip_box"] = "Laatikkolipas", + ["component_flashlight"] = "Taskulamppu", + ["component_scope"] = "Tähtäin", + ["component_scope_advanced"] = "Paranneltu tähtäin", + ["component_suppressor"] = "Äänenvaimennin", + ["component_grip"] = "Kahva", + ["component_luxary_finish"] = "Luksus ulkokuori", + + -- Weapon Ammo + ["ammo_rounds"] = "Ammukset(s)", + ["ammo_shells"] = "Hylsy(s)", + ["ammo_charge"] = "Lataa", + ["ammo_petrol"] = "Gallonaa polttoainetta", + ["ammo_firework"] = "Ilotulite(s)", + ["ammo_rockets"] = "Raketti(s)", + ["ammo_grenadelauncher"] = "Kranaatti(s)", + ["ammo_grenade"] = "Kranaatti(s)", + ["ammo_stickybomb"] = "Pommi(s)", + ["ammo_pipebomb"] = "Pommi(s)", + ["ammo_smokebomb"] = "Pommi(s)", + ["ammo_molotov"] = "Polttopullo(s)", + ["ammo_proxmine"] = "Miina(s)", + ["ammo_bzgas"] = "Tölkki(s)", + ["ammo_ball"] = "Pallo(s)", + ["ammo_snowball"] = "Lumipallo(s)", + ["ammo_flare"] = "Valoraketti(s)", + ["ammo_flaregun"] = "Valoraketti(s)", + + -- Weapon Tints + ["tint_default"] = "Oletus ulkokuori", + ["tint_green"] = "Vihreä ulkokuori", + ["tint_gold"] = "Kultainen ulkokuori", + ["tint_pink"] = "Vaaleanpunainen ulkokuori", + ["tint_army"] = "Armeija ulkokuori", + ["tint_lspd"] = "Sininen ulkokuori", + ["tint_orange"] = "Oranssi ulkokuori", + ["tint_platinum"] = "Platina ulkokuori", + -- MK2 Weapon Tints + ["tint_classic_black"] = "klassinen musta", + ["tint_classic_gray"] = "klassinen harmaa", + ["tint_classic_two_tone"] = "klassinen kaksivärinen", + ["tint_classic_white"] = "klassinen valkoinen", + ["tint_classic_beige"] = "klassinen beessi", + ["tint_classic_green"] = "klassinen vihreä", + ["tint_classic_blue"] = "klassinen sininen", + ["tint_classic_earth"] = "klassinen maa", + ["tint_classic_brown_black"] = "klassinen ruskea-musta", + ["tint_contrast_red"] = "kontrastinen punainen", + ["tint_contrast_blue"] = "kontrastinen sininen", + ["tint_contrast_yellow"] = "kontrastinen keltainen", + ["tint_contrast_orange"] = "kontrastinen oranssi", + ["tint_bold_pink"] = "rohkea vaaleanpunainen", + ["tint_bold_purple_yellow"] = "rohkea violetti-keltainen", + ["tint_bold_orange"] = "rohkea oranssi", + ["tint_bold_green_purple"] = "rohkea vihreä-violetti", + ["tint_bold_red_feat"] = "rohkea punainen feat", + ["tint_bold_green_feat"] = "rohkea vihreä feat", + ["tint_bold_cyan_feat"] = "rohkea syaani feat", + ["tint_bold_yellow_feat"] = "rohkea keltainen feat", + ["tint_bold_red_white"] = "rohkea punainen valkoinen", + ["tint_bold_blue_white"] = "rohkea sininen valkoinen", + ["tint_metallic_gold"] = "metallinen kulta", + ["tint_metallic_platinum"] = "metallinen platina", + ["tint_metallic_gray_lilac"] = "metallinen harmaa lila", + ["tint_metallic_purple_lime"] = "metallinen violetti limetti", + ["tint_metallic_red"] = "metallinen punainen", + ["tint_metallic_green"] = "metallinen vihreä", + ["tint_metallic_blue"] = "metallinen sininen", + ["tint_metallic_white_aqua"] = "metallinen valkoinen aqua", + ["tint_metallic_red_yellow"] = "metallinen punainen keltainen", +} diff --git a/resources/[core]/es_extended/locales/fr.lua b/resources/[core]/es_extended/locales/fr.lua new file mode 100644 index 0000000..47e6dcc --- /dev/null +++ b/resources/[core]/es_extended/locales/fr.lua @@ -0,0 +1,417 @@ +return { + -- Inventory + ["inventory"] = "Inventaire ( Poids %s / %s )", + ["use"] = "Utiliser", + ["give"] = "Donner", + ["remove"] = "Jeter", + ["return"] = "Retour", + ["give_to"] = "Donner à", + ["amount"] = "Quantité", + ["giveammo"] = "Donner des munitions", + ["amountammo"] = "Nombre de munitions", + ["noammo"] = "Vous n'avez pas autant de munitions!", + ["gave_item"] = "Vous avez donné %sx %s à %s", + ["received_item"] = "Vous avez reçu %sx %s de %s", + ["gave_weapon"] = "Vous avez donné 1x %s à %s", + ["gave_weapon_ammo"] = "Vous avez donné ~o~%sx %s pour %s à %s", + ["gave_weapon_withammo"] = "Vous avez donné 1x %s avec ~o~%sx %s à %s", + ["gave_weapon_hasalready"] = "%s a déjà 1x %s", + ["gave_weapon_noweapon"] = "%s n'a pas cette arme", + ["received_weapon"] = "Vous avez reçu 1x %s de %s", + ["received_weapon_ammo"] = "Vous avez reçu ~o~%sx %s pour votre %s de %s", + ["received_weapon_withammo"] = "Vous avez reçu 1x %s avec ~o~%sx %s de %s", + ["received_weapon_hasalready"] = "%s a tenté de vous donner 1x %s, mais vous en aviez déjà un exemplaire", + ["received_weapon_noweapon"] = "%s a tenté de vous donner des munitions pour %s, mais vous n'avez pas cette arme", + ["gave_account_money"] = "Vous avez donné $%s (%s) à %s", + ["received_account_money"] = "Vous avez reçu $%s (%s) de %s", + ["amount_invalid"] = "Le montant est invalide", + ["players_nearby"] = "Aucun joueur n'est à proximité", + ["ex_inv_lim"] = "Action impossible, dépassement du poids maximum de %s", + ["imp_invalid_quantity"] = "Action impossible, la quantité est invalide", + ["imp_invalid_amount"] = "Action impossible, le montant est invalide", + ["threw_standard"] = "Vous avez jeté %sx %s", + ["threw_account"] = "Vous avez jeté $%s %s", + ["threw_weapon"] = "Vous avez jeté 1x %s", + ["threw_weapon_ammo"] = "Vous avez jeté 1x %s avec ~o~%sx %s", + ["threw_weapon_already"] = "Vous avez déjà cette arme", + ["threw_cannot_pickup"] = "Votre inventaire est plein, vous ne pouvez donc pas ramasser cela!", + ["threw_pickup_prompt"] = "Appuyez sur E pour ramasser", + + -- Key mapping + ["keymap_showinventory"] = "Afficher l'inventaire", + + -- Salary related + ["received_salary"] = "Vous avez reçu votre salaire: $%s", + ["received_help"] = "Vous avez reçu une aide de l'état: $%s", + ["company_nomoney"] = "Votre entreprise n'a pas assez d'argent pour vous payer", + ["received_paycheck"] = "Paiement reçu", + ["bank"] = "Banque", + ["account_bank"] = "Banque", + ["account_black_money"] = "Argent sale", + ["account_money"] = "Espèces", + + ["act_imp"] = "Action impossible", + ["in_vehicle"] = "Action impossible, le joueur est dans un véhicule", + ["not_in_vehicle"] = "Action impossible, le joueur n'est pas dans un véhicule", + + -- Commands + ["command_bring"] = "Téléporter un joueur sur vous", + ["command_car"] = "Faire appaitre un véhicule", + ["command_car_car"] = "Nom ou hash du véhicule", + ["command_cardel"] = "Supprimer les véhicules à proximité", + ["command_cardel_radius"] = "Supprime tous les véhicules dans un rayon spécifié", + ["command_repair"] = "Réparer votre véhicule", + ["command_repair_success"] = "Véhicule réparé avec succès", + ["command_repair_success_target"] = "Votre véhicule a été réparé par un membre du staff", + ["command_clear"] = "Effacer le chat", + ["command_clearall"] = "Effacer le chat de tous les joueurs", + ["command_clearinventory"] = "Retirer tous les objets de l'inventaire du joueur", + ["command_clearloadout"] = "Retirer toutes les armes du joueur", + ["command_freeze"] = "Geler un joueur sur place", + ["command_unfreeze"] = "Dégeler un joueur", + ["command_giveaccountmoney"] = "Donner de l'argent à un compte spécifique", + ["command_giveaccountmoney_account"] = "Compte à créditer", + ["command_giveaccountmoney_amount"] = "Quantité d'argent à créditer", + ["command_giveaccountmoney_invalid"] = "Le nom de compte spécifié est invalide", + ["command_removeaccountmoney"] = "Retirer de l'argent d'un compte spécifique", + ["command_removeaccountmoney_account"] = "Compte à débiter", + ["command_removeaccountmoney_amount"] = "Quantité d'argent à débiter", + ["command_removeaccountmoney_invalid"] = "Le nom de compte spécifié est invalide", + ["command_giveitem"] = "Donner un objet à un joueur", + ["command_giveitem_item"] = "Nom de l'objet à donner", + ["command_giveitem_count"] = "Quantité à donner", + ["command_giveweapon"] = "Donner une arme à un joueur", + ["command_giveweapon_weapon"] = "Nom de l'arme à donner", + ["command_giveweapon_ammo"] = "Quantité de munitions à donner", + ["command_giveweapon_hasalready"] = "Le joueur a déjà cette arme", + ["command_giveweaponcomponent"] = "Donner un accessoire d'arme à un joueur", + ["command_giveweaponcomponent_component"] = "Nom de l'accessoire à donner", + ["command_giveweaponcomponent_invalid"] = "Le nom de l'accessoire d'arme spécifié est invalide", + ["command_giveweaponcomponent_hasalready"] = "Le joueur a déjà cet accessoire", + ["command_giveweaponcomponent_missingweapon"] = "Le joueur n'a pas l'arme associée à cet accessoire", + ["command_goto"] = "Se téléporter vers un joueur", + ["command_kill"] = "Tuer un joueur", + ["command_save"] = "Forcer la sauvegarde des données d'un joueur", + ["command_saveall"] = "Forcer la sauvegarde des données de tous les joueurs", + ["command_setaccountmoney"] = "Définir le montant d'argent d'un compte spécifique", + ["command_setaccountmoney_amount"] = "Montant d'argent à définir", + ["command_setcoords"] = "Se téléporter à des coordonnées spécifiques", + ["command_setcoords_x"] = "Valeur de l'axe X", + ["command_setcoords_y"] = "Valeur de l'axe Y", + ["command_setcoords_z"] = "Valeur de l'axe Z", + ["command_setjob"] = "Définir le métier d'un joueur", + ["command_setjob_job"] = "Nom du métier à définir", + ["command_setjob_grade"] = "Grade du métier", + ["command_setjob_invalid"] = "Le métier, le grade, ou les deux sont invalides", + ["command_setgroup"] = "Définir le groupe de permissions d'un joueur", + ["command_setgroup_group"] = "Nom du groupe à définir", + ["commanderror_argumentmismatch"] = "Le nombre d'arguments est invalide (Argument·s donné·s: %s, Argument·s demandé·s: %s)", + ["commanderror_argumentmismatch_number"] = "Type de données de l'argument #%s invalide (Type donné: texte, Type demandé: nombre)", + ["commanderror_argumentmismatch_string"] = "Type de données de l'argument #%s invalide (Type donné: nombre, Type demandé: texte)", + ["commanderror_argumentmismatch_positive_number"] = "Argument invalide #%s type de données (passé négatif/zéro, nombre positif requis)", + ["commanderror_invaliditem"] = "Le nom de l'objet est invalide", + ["commanderror_invalidweapon"] = "Le nom de l'arme est invalide", + ["commanderror_console"] = "Cette commande ne peut pas être éxécutée depuis la console", + ["commanderror_invalidcommand"] = "Commande invalide - /%s", + ["commanderror_invalidplayerid"] = "Le joueur spécifié n'est pas connecté", + ["commandgeneric_playerid"] = "Identifiant serveur du joueur", + ["commandgeneric_dimension"] = "Dimension de la cible", + ["command_giveammo_noweapon_found"] = "%s n'a pas cette arme", + ["command_giveammo_weapon"] = "Nom de l'arme", + ["command_giveammo_ammo"] = "Quantité de munitions", + ["command_setdim"] = "Définir la dimension d'un joueur", + ["tpm_nowaypoint"] = "Aucun point n'est défini sur la carte", + ["tpm_success"] = "Vous avez bien été téléporté", + + ["noclip_message"] = "Le mode noclip a été %s", + ["enabled"] = "~g~activé~s~", + ["disabled"] = "~r~désactivé~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = " ", + ["locale_currency"] = "$%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dague", + ["weapon_bat"] = "Batte", + ["weapon_battleaxe"] = "Hache de combat", + ["weapon_bottle"] = "Bouteille", + ["weapon_crowbar"] = "Pied de biche", + ["weapon_flashlight"] = "Lampte torche", + ["weapon_golfclub"] = "Club de golf", + ["weapon_hammer"] = "Marteau", + ["weapon_hatchet"] = "Hachette", + ["weapon_knife"] = "Couteau", + ["weapon_knuckle"] = "Poing américain", + ["weapon_machete"] = "Machette", + ["weapon_nightstick"] = "Matraque", + ["weapon_wrench"] = "Clé à pipe", + ["weapon_poolcue"] = "Queue de billard", + ["weapon_stone_hatchet"] = "Hachette en pierre", + ["weapon_switchblade"] = "Couteau à cran d'arrêt", + + -- Handguns + ["weapon_appistol"] = "Pistolet automatique", + ["weapon_ceramicpistol"] = "Pistolet en céramique", + ["weapon_combatpistol"] = "Pistolet de combat", + ["weapon_doubleaction"] = "Revolver à double action", + ["weapon_navyrevolver"] = "Revolver de marine", + ["weapon_flaregun"] = "Pistolet de détresse", + ["weapon_gadgetpistol"] = "Pistolet gadget", + ["weapon_heavypistol"] = "Pistolet lourd", + ["weapon_revolver"] = "Revolver lourd", + ["weapon_revolver_mk2"] = "Revolver lourd MK2", + ["weapon_marksmanpistol"] = "Pistolet Marksman", + ["weapon_pistol"] = "Pistolet", + ["weapon_pistol_mk2"] = "Pistolet MK2", + ["weapon_pistol50"] = "Pistolet .50", + ["weapon_snspistol"] = "Pistolet SNS", + ["weapon_snspistol_mk2"] = "Pistolet SNS MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Atomiseur", + ["weapon_vintagepistol"] = "Pistolet vintage", + + -- Shotguns + ["weapon_assaultshotgun"] = "Fusil d'assaut", + ["weapon_autoshotgun"] = "Fusil à pompe automatique", + ["weapon_bullpupshotgun"] = "Fusil à pompe Bullpup", + ["weapon_combatshotgun"] = "Fusil de combat", + ["weapon_dbshotgun"] = "Fusil à pompe à double canon", + ["weapon_heavyshotgun"] = "Fusil à pompe lourd", + ["weapon_musket"] = "Mousquet", + ["weapon_pumpshotgun"] = "Fusil à pompe", + ["weapon_pumpshotgun_mk2"] = "Fusil à pompe MK2", + ["weapon_sawnoffshotgun"] = "Fusil à canon scié", + + -- SMG & LMG + ["weapon_assaultsmg"] = "SMG s'assaut", + ["weapon_combatmg"] = "MG de combat", + ["weapon_combatmg_mk2"] = "MG de combat MK2", + ["weapon_combatpdw"] = "PDW de combat", + ["weapon_gusenberg"] = "Balayeuse Gusenberg", + ["weapon_machinepistol"] = "Pistolet-mitrailleur", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Carabine à rayons", + + -- Rifles + ["weapon_advancedrifle"] = "Fusil avancé", + ["weapon_assaultrifle"] = "Fusil d'assaut", + ["weapon_assaultrifle_mk2"] = "Fusil d'assaut MK2", + ["weapon_bullpuprifle"] = "Fusil Bullpup", + ["weapon_bullpuprifle_mk2"] = "Fusil Bullpup MK2", + ["weapon_carbinerifle"] = "Fusil carabine", + ["weapon_carbinerifle_mk2"] = "Fusil carabine MK2", + ["weapon_compactrifle"] = "Fusil compacte", + ["weapon_militaryrifle"] = "Fusil militaire", + ["weapon_specialcarbine"] = "Carabine spéciale", + ["weapon_specialcarbine_mk2"] = "Carabine spéciale MK2", + ["weapon_heavyrifle"] = "Fusil lourd", + + -- Sniper + ["weapon_heavysniper"] = "Sniper lourd", + ["weapon_heavysniper_mk2"] = "Sniper lourd MK2", + ["weapon_marksmanrifle"] = "Fusil Marksman", + ["weapon_marksmanrifle_mk2"] = "Fusil Marksman MK2", + ["weapon_sniperrifle"] = "Fusil sniper", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Lanceur compacte", + ["weapon_firework"] = "Lanceur de feu d'artifice", + ["weapon_grenadelauncher"] = "Lanceur de grenade", + ["weapon_hominglauncher"] = "Lanceur de tête chercheuse", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Fusil à rail", + ["weapon_rpg"] = "Lanceur de rockette", + ["weapon_rayminigun"] = "Exterminateur", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Détecteur de métaux", + ["weapon_precisionrifle"] = "Fusil de précision", + ["weapon_tactilerifle"] = "Carabine tactique", + + -- Drug wars dlc + ["weapon_candycane"] = "Sucre d'orge", + ["weapon_acidpackage"] = "Paquet d'acide", + ["weapon_pistolxm3"] = "Pistolet 8 x3m", + ["weapon_railgunxm3"] = "Fusil électro-magnétique", + + -- Thrown + ["weapon_ball"] = "Base-ball", + ["weapon_bzgas"] = "Gaz BZ", + ["weapon_flare"] = "Fusée éclairante", + ["weapon_grenade"] = "Grenade", + ["weapon_petrolcan"] = "Jerrycan", + ["weapon_hazardcan"] = "Jerrycan dangereux", + ["weapon_molotov"] = "Cocktail Molotov", + ["weapon_proxmine"] = "Mine de proximité", + ["weapon_pipebomb"] = "Bombe tuyau", + ["weapon_snowball"] = "Boule de neige", + ["weapon_stickybomb"] = "Bombe collante", + ["weapon_smokegrenade"] = "Gaz lacrymogène", + + -- Special + ["weapon_fireextinguisher"] = "Extincteur", + ["weapon_digiscanner"] = "Scanner", + ["weapon_garbagebag"] = "Sac d'ordures", + ["weapon_handcuffs"] = "Menottes", + ["gadget_nightvision"] = "Vision nocturne", + ["gadget_parachute"] = "Parachute", + + -- Weapon Components + ["component_knuckle_base"] = "Modèle par défaut", + ["component_knuckle_pimp"] = "le Pimp", + ["component_knuckle_ballas"] = "le Ballas", + ["component_knuckle_dollar"] = "le Hustler", + ["component_knuckle_diamond"] = "le Rock", + ["component_knuckle_hate"] = "le Hater", + ["component_knuckle_love"] = "le Lover", + ["component_knuckle_player"] = "le Joueur", + ["component_knuckle_king"] = "le Roi", + ["component_knuckle_vagos"] = "le Vagos", + + ["component_luxary_finish"] = "Finition d'arme de luxe", + + ["component_handle_default"] = "Poignée par défaut", + ["component_handle_vip"] = "Poignée VIP", + ["component_handle_bodyguard"] = "Poignée bodyguard", + + ["component_vip_finish"] = "Finition VIP", + ["component_bodyguard_finish"] = "Finition bodyguard", + + ["component_camo_finish"] = "Camouflage numérique", + ["component_camo_finish2"] = "Camouflage pinceau", + ["component_camo_finish3"] = "Camouflage des bois", + ["component_camo_finish4"] = "Camouflage crâne", + ["component_camo_finish5"] = "Camouflage sessanta Nove", + ["component_camo_finish6"] = "Camouflage perseus", + ["component_camo_finish7"] = "Camouflage léopard", + ["component_camo_finish8"] = "Camouflage zèbre", + ["component_camo_finish9"] = "Camouflage géométrique", + ["component_camo_finish10"] = "Camouflage explosif", + ["component_camo_finish11"] = "Camouflage patriotique", + + ["component_camo_slide_finish"] = "Finitions slide à camouflage numérique", + ["component_camo_slide_finish2"] = "Finitions slide à camouflage pinceau", + ["component_camo_slide_finish3"] = "Finitions slide à camouflage des bois", + ["component_camo_slide_finish4"] = "Finitions slide à camouflage crâne", + ["component_camo_slide_finish5"] = "Finitions slide à camouflage sessanta Nove", + ["component_camo_slide_finish6"] = "Finitions slide à camouflage perseus", + ["component_camo_slide_finish7"] = "Finitions slide à camouflage léopard", + ["component_camo_slide_finish8"] = "Finitions slide à camouflage zèbre", + ["component_camo_slide_finish9"] = "Finitions slide à camouflage géométrique", + ["component_camo_slide_finish10"] = "Finitions slide à camouflage explosive", + ["component_camo_slide_finish11"] = "Finitions slide à camouflage patriotique", + + ["component_clip_default"] = "Chargeur par défaut", + ["component_clip_extended"] = "Chargeur à grande capacité", + ["component_clip_drum"] = "Chargeur à tambour", + ["component_clip_box"] = "Chargeur à très grande capacité", + + ["component_scope_holo"] = "Viseur holographique", + ["component_scope_small"] = "Viseur de petite taille", + ["component_scope_medium"] = "Viseur de taille moyenne", + ["component_scope_large"] = "Viseur de grande taille", + ["component_scope"] = "Viseur monté", + ["component_scope_advanced"] = "Viseur avancé", + ["component_ironsights"] = "Viseur à marqueurs alignés", + + ["component_suppressor"] = "silencieux", + ["component_compensator"] = "compensateur", + + ["component_muzzle_flat"] = "Frein plat", + ["component_muzzle_tactical"] = "Frein tactique", + ["component_muzzle_fat"] = "Frein large", + ["component_muzzle_precision"] = "Frein de précision", + ["component_muzzle_heavy"] = "Frein polyvalent", + ["component_muzzle_slanted"] = "Frein incliné", + ["component_muzzle_split"] = "Frein fendu", + ["component_muzzle_squared"] = "Frein carré", + + ["component_flashlight"] = "lampe torche", + ["component_grip"] = "poignée", + + ["component_barrel_default"] = "Canon par défaut", + ["component_barrel_heavy"] = "Canon lourd", + + ["component_ammo_tracer"] = "Munition traceuse", + ["component_ammo_incendiary"] = "Munition incendiaire", + ["component_ammo_hollowpoint"] = "Munition à pointe creuse", + ["component_ammo_fmj"] = "Munition fMJ", + ["component_ammo_armor"] = "Munition perforante", + ["component_ammo_explosive"] = "Munition perforante et Munition incendiaire", + + ["component_shells_default"] = "Coque par défaut", + ["component_shells_incendiary"] = "Coque souffle de dragon", + ["component_shells_armor"] = "Coque à chevrotine en acier", + ["component_shells_hollowpoint"] = "Coque à fléchettes", + ["component_shells_explosive"] = "Coque à limaces explosives", + + -- Weapon Ammo + ["ammo_rounds"] = "cartouche(s)", + ["ammo_shells"] = "obus", + ["ammo_charge"] = "charge·s", + ["ammo_petrol"] = "jerrican d'essence", + ["ammo_firework"] = "feu·x d'artifice", + ["ammo_rockets"] = "roquette·s", + ["ammo_grenadelauncher"] = "grenade·s", + ["ammo_grenade"] = "grenade·s", + ["ammo_stickybomb"] = "bombe·s", + ["ammo_pipebomb"] = "bombe·s", + ["ammo_smokebomb"] = "bombe·s", + ["ammo_molotov"] = "cocktail·s", + ["ammo_proxmine"] = "mine·s", + ["ammo_bzgas"] = "grenade·s", + ["ammo_ball"] = "balle·s", + ["ammo_snowball"] = "boule·s de neige", + ["ammo_flare"] = "fusée·s éclairante·s", + ["ammo_flaregun"] = "fusée·s", + + -- Weapon Tints + ["tint_default"] = "skin par défaut", + ["tint_green"] = "skin vert", + ["tint_gold"] = "skin doré", + ["tint_pink"] = "skin rose", + ["tint_army"] = "skin militaire", + ["tint_lspd"] = "skin bleu", + ["tint_orange"] = "skin orange", + ["tint_platinum"] = "skin platine", + -- MK2 Weapon Tints + ["tint_classic_black"] = "noir classique", + ["tint_classic_gray"] = "gris classique", + ["tint_classic_two_tone"] = "deux tons classiques", + ["tint_classic_white"] = "blanc classique", + ["tint_classic_beige"] = "beige classique", + ["tint_classic_green"] = "vert classique", + ["tint_classic_blue"] = "bleu classique", + ["tint_classic_earth"] = "terre classique", + ["tint_classic_brown_black"] = "marron noir classique", + ["tint_contrast_red"] = "rouge contrasté", + ["tint_contrast_blue"] = "bleu contrasté", + ["tint_contrast_yellow"] = "jaune contrasté", + ["tint_contrast_orange"] = "orange contrasté", + ["tint_bold_pink"] = "rose audacieux", + ["tint_bold_purple_yellow"] = "violet jaune audacieux", + ["tint_bold_orange"] = "orange audacieux", + ["tint_bold_green_purple"] = "vert violet audacieux", + ["tint_bold_red_feat"] = "rouge audacieux feat", + ["tint_bold_green_feat"] = "vert audacieux feat", + ["tint_bold_cyan_feat"] = "cyan audacieux feat", + ["tint_bold_yellow_feat"] = "jaune audacieux feat", + ["tint_bold_red_white"] = "rouge blanc audacieux", + ["tint_bold_blue_white"] = "bleu blanc audacieux", + ["tint_metallic_gold"] = "or métallique", + ["tint_metallic_platinum"] = "platine métallique", + ["tint_metallic_gray_lilac"] = "gris lilas métallique", + ["tint_metallic_purple_lime"] = "violet lime métallique", + ["tint_metallic_red"] = "rouge métallique", + ["tint_metallic_green"] = "vert métallique", + ["tint_metallic_blue"] = "bleu métallique", + ["tint_metallic_white_aqua"] = "blanc aqua métallique", + ["tint_metallic_red_yellow"] = "rouge jaune métallique", +} diff --git a/resources/[core]/es_extended/locales/he.lua b/resources/[core]/es_extended/locales/he.lua new file mode 100644 index 0000000..e103e8b --- /dev/null +++ b/resources/[core]/es_extended/locales/he.lua @@ -0,0 +1,409 @@ +return { + -- Inventory + ["inventory"] = "מלאי ( משקל %s / %s )", + ["use"] = "השתמש", + ["give"] = "תן", + ["remove"] = "זרוק", + ["return"] = "חזור", + ["give_to"] = "תן ל", + ["amount"] = "כמות", + ["giveammo"] = "תן תחמושת", + ["amountammo"] = "כמות תחמושת", + ["noammo"] = "לא מספיק!", + ["gave_item"] = "ניתן %sx %s ל %s", + ["received_item"] = "קיבלת %sx %s מ %s", + ["gave_weapon"] = "ניתן %s ל %s", + ["gave_weapon_ammo"] = "ניתן ~o~%sx %s ל %s ל %s", + ["gave_weapon_withammo"] = "ניתן %s עם ~o~%sx %s ל %s", + ["gave_weapon_hasalready"] = "%s כבר יש לו %s", + ["gave_weapon_noweapon"] = "%s אין לו את הנשק הזה", + ["received_weapon"] = "קיבלת %s מ %s", + ["received_weapon_ammo"] = "קיבלת ~o~%sx %s ל %s שלך מ %s", + ["received_weapon_withammo"] = "קיבלת %s עם ~o~%sx %s מ %s", + ["received_weapon_hasalready"] = "%s ניסה לתת לך %s, אך יש לך כבר נשק זה", + ["received_weapon_noweapon"] = "%s ניסה לתת לך תחמושת ל %s, אך אין לך נשק זה", + ["gave_account_money"] = "ניתן $%s (%s) ל %s", + ["received_account_money"] = "קיבלת $%s (%s) מ %s", + ["amount_invalid"] = "כמות לא חוקית", + ["players_nearby"] = "אין שחקנים קרובים", + ["ex_inv_lim"] = "לא ניתן לבצע פעולה, חורג מהמשקל המרבי של %s", + ["imp_invalid_quantity"] = "לא ניתן לבצע פעולה, הכמות אינה חוקית", + ["imp_invalid_amount"] = "לא ניתן לבצע פעולה, הסכום אינו חוקי", + ["threw_standard"] = "זורק %sx %s", + ["threw_account"] = "זורק $%s %s", + ["threw_weapon"] = "זורק %s", + ["threw_weapon_ammo"] = "זורק %s עם ~o~%sx %s", + ["threw_weapon_already"] = "כבר יש לך נשק זה", + ["threw_cannot_pickup"] = "המלאי מלא, לא ניתן לאסוף!", + ["threw_pickup_prompt"] = "לחץ E כדי לאסוף", + -- Key mapping + ["keymap_showinventory"] = "הצג מלאי", + + -- Salary related + ["received_salary"] = "קיבלת שכר: $%s", + ["received_help"] = "קיבלת הטבה: $%s", + ["company_nomoney"] = "החברה בה אתה עובד אינה יכולה לשלם לך את השכר", + ["received_paycheck"] = "קיבלת תלוש", + ["bank"] = "בנק מעץ", + ["account_bank"] = "בנק", + ["account_black_money"] = "כסף מטונף", + ["account_money"] = "מזומן", + + ["act_imp"] = "לא ניתן לבצע פעולה", + ["in_vehicle"] = "לא ניתן לבצע פעולה, השחקן ברכב", + ["not_in_vehicle"] = "לא ניתן לבצע פעולה, השחקן לא ברכב", + + -- Commands + ["command_bring"] = "הבא שחקן אליך", + ["command_car"] = "צור רכב", + ["command_car_car"] = "דגם הרכב או האש", + ["command_cardel"] = "הסר רכבים בקרבת מקום", + ["command_cardel_radius"] = "הסר את כל הרכבים ברדיוס המצוין", + ["command_repair"] = "תקן את הרכב שלך", + ["command_repair_success"] = "רכב תוקן בהצלחה", + ["command_repair_success_target"] = "אדמין תיקן לך את הרכב", + ["command_clear"] = 'נקה טקסט צ"אט', + ["command_clearall"] = 'נקה טקסט צ"אט לכל השחקנים', + ["command_clearinventory"] = "הסר את כל הפריטים מהמלאי של השחקן", + ["command_clearloadout"] = "הסר את כל הנשקים מהשחקן", + ["command_freeze"] = "הקפא שחקן", + ["command_unfreeze"] = "בטל הקפאה של שחקן", + ["command_giveaccountmoney"] = "תן כסף לחשבון מסוים", + ["command_giveaccountmoney_account"] = "חשבון להוספה", + ["command_giveaccountmoney_amount"] = "כמות להוספה", + ["command_giveaccountmoney_invalid"] = "שם חשבון לא חוקי", + ["command_removeaccountmoney"] = "הסר כסף מחשבון מסוים", + ["command_removeaccountmoney_account"] = "חשבון להסרה ממנו", + ["command_removeaccountmoney_amount"] = "כמות להסרה", + ["command_removeaccountmoney_invalid"] = "שם חשבון לא חוקי", + ["command_giveitem"] = "תן לשחקן פריט", + ["command_giveitem_item"] = "שם הפריט", + ["command_giveitem_count"] = "כמות", + ["command_giveweapon"] = "תן לשחקן נשק", + ["command_giveweapon_weapon"] = "שם הנשק", + ["command_giveweapon_ammo"] = "כמות תחמושת", + ["command_giveweapon_hasalready"] = "לשחקן כבר יש נשק זה", + ["command_giveweaponcomponent"] = "תן רכיב נשק לשחקן", + ["command_giveweaponcomponent_component"] = "שם הרכיב", + ["command_giveweaponcomponent_invalid"] = "רכיב נשק לא חוקי", + ["command_giveweaponcomponent_hasalready"] = "לשחקן כבר יש רכיב נשק זה", + ["command_giveweaponcomponent_missingweapon"] = "לשחקן אין נשק זה", + ["command_goto"] = "התעבר אל שחקן", + ["command_kill"] = "הרוג שחקן", + ["command_save"] = "שמור נתונים של שחקן בכפיה", + ["command_saveall"] = "שמור נתונים של כל השחקנים", + ["command_setaccountmoney"] = "קבע כמות כסף בחשבון מסוים", + ["command_setaccountmoney_amount"] = "כמות כסף להגדרה", + ["command_setcoords"] = "התעבר לקואורדינטות מסוימות", + ["command_setcoords_x"] = "ערך x", + ["command_setcoords_y"] = "ערך y", + ["command_setcoords_z"] = "ערך z", + ["command_setjob"] = "קבע משרה לשחקן", + ["command_setjob_job"] = "שם המשרה", + ["command_setjob_grade"] = "דרגת המשרה", + ["command_setjob_invalid"] = "המשרה, הדרגה או שניהם אינם חוקיים", + ["command_setgroup"] = "קבע קבוצת הרשאות לשחקן", + ["command_setgroup_group"] = "שם קבוצת הפקודות", + ["commanderror_argumentmismatch"] = "כמות וסוגי הארגומנטים אינם תואמים (נשלח %s, נדרש %s)", + ["commanderror_argumentmismatch_number"] = "טיפוס ארגומנט #%s לא תקין (נשלח מחרוזת, נדרש מספר)", + ["commanderror_argumentmismatch_string"] = "טיפוס ארגומנט #%s לא תקין (נשלח מספר, נדרש מחרוזת)", + ["commanderror_argumentmismatch_positive_number"] = "טיפוס ארגומנט #%s לא תקין (נשלח שלילי/אפס, נדרש מספר חיובי)", + ["commanderror_invaliditem"] = "שם פריט לא חוקי", + ["commanderror_invalidweapon"] = "נשק לא חוקי", + ["commanderror_console"] = "לא ניתן להפעיל פקודה מהקונסול", + ["commanderror_invalidcommand"] = "פקודה לא חוקית - /%s", + ["commanderror_invalidplayerid"] = "אין שחקן עם מזהה זה מחובר", + ["commandgeneric_playerid"] = "מזהה השחקן בשרת", + ["command_giveammo_noweapon_found"] = "ל-%s אין נשק כזה", + ["command_giveammo_weapon"] = "שם הנשק", + ["command_giveammo_ammo"] = "כמות תחמושת", + ["tpm_nowaypoint"] = "אין נקודת דרך מוגדרת", + ["tpm_success"] = "הועברת בהצלחה", + + ["noclip_message"] = "מצב Noclip %s", + ["enabled"] = "~g~מאופשר~s~", + ["disabled"] = "~r~מנוטרל~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "₪%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "סכין", + ["weapon_bat"] = "כותרת", + ["weapon_battleaxe"] = "גרזן קרב", + ["weapon_bottle"] = "בקבוק", + ["weapon_crowbar"] = "מפתח ברזל", + ["weapon_flashlight"] = "פנס יד", + ["weapon_golfclub"] = "מקל גולף", + ["weapon_hammer"] = "פטיש", + ["weapon_hatchet"] = "גרזן", + ["weapon_knife"] = "סכין", + ["weapon_knuckle"] = "עצמאות", + ["weapon_machete"] = 'מאצ"טה', + ["weapon_nightstick"] = "מקל לילה", + ["weapon_wrench"] = "מפתח אינגליזי", + ["weapon_poolcue"] = "מקל בריכה", + ["weapon_stone_hatchet"] = "גרזן אבן", + ["weapon_switchblade"] = "סכין קפיצית", + -- Handguns + ["weapon_appistol"] = "אקדח AP", + ["weapon_ceramicpistol"] = "אקדח קרמי", + ["weapon_combatpistol"] = "אקדח קרב", + ["weapon_doubleaction"] = "רבולבר פעולה כפולה", + ["weapon_navyrevolver"] = "רבולבר צי", + ["weapon_flaregun"] = "אקדח זיקוקים", + ["weapon_gadgetpistol"] = "אקדח חומרה", + ["weapon_heavypistol"] = "אקדח כבד", + ["weapon_revolver"] = "רבולבר כבד", + ["weapon_revolver_mk2"] = "רבולבר כבד MK2", + ["weapon_marksmanpistol"] = "אקדח צלף", + ["weapon_pistol"] = "אקדח", + ["weapon_pistol_mk2"] = "אקדח MK2", + ["weapon_pistol50"] = "אקדח .50", + ["weapon_snspistol"] = "אקדח SNS", + ["weapon_snspistol_mk2"] = "אקדח SNS MK2", + ["weapon_stungun"] = "טייזר", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "אקדח וינטג", + + -- Shotguns + ["weapon_assaultshotgun"] = "רובה סטורם", + ["weapon_autoshotgun"] = "רובה אוטומטי", + ["weapon_bullpupshotgun"] = "רובה Bullpup", + ["weapon_combatshotgun"] = "רובה קרב", + ["weapon_dbshotgun"] = "רובה קנה כפול", + ["weapon_heavyshotgun"] = "רובה כבד", + ["weapon_musket"] = "רובה חלילי", + ["weapon_pumpshotgun"] = "רובה פומפה", + ["weapon_pumpshotgun_mk2"] = "רובה פומפה MK2", + ["weapon_sawnoffshotgun"] = "רובה חתוך", + + -- SMG & LMG + ["weapon_assaultsmg"] = "רובה סטורם SMG", + ["weapon_combatmg"] = "רובה סטורם MG", + ["weapon_combatmg_mk2"] = "רובה סטורם MG MK2", + ["weapon_combatpdw"] = "רובה סטורם PDW", + ["weapon_gusenberg"] = "רובה גוזנברג", + ["weapon_machinepistol"] = "אקדח מכונה", + ["weapon_mg"] = "רובה מכונה", + ["weapon_microsmg"] = "רובה מכונה מיקרו", + ["weapon_minismg"] = "רובה מכונה מיני", + ["weapon_smg"] = "רובה מכונה", + ["weapon_smg_mk2"] = "רובה מכונה MK2", + ["weapon_raycarbine"] = "רובה אור", + -- Rifles + ["weapon_advancedrifle"] = "רובה מתקדם", + ["weapon_assaultrifle"] = "רובה סטורם", + ["weapon_assaultrifle_mk2"] = "רובה סטורם MK2", + ["weapon_bullpuprifle"] = "רובה Bullpup", + ["weapon_bullpuprifle_mk2"] = "רובה Bullpup MK2", + ["weapon_carbinerifle"] = "רובה קרבין", + ["weapon_carbinerifle_mk2"] = "רובה קרבין MK2", + ["weapon_compactrifle"] = "רובה קומפקטי", + ["weapon_militaryrifle"] = "רובה צבאי", + ["weapon_specialcarbine"] = "רובה קרבין מיוחד", + ["weapon_specialcarbine_mk2"] = "רובה קרבין מיוחד MK2", + ["weapon_heavyrifle"] = "רובה כבד", + + -- Sniper + ["weapon_heavysniper"] = "רובה צלפים כבד", + ["weapon_heavysniper_mk2"] = "רובה צלפים כבד MK2", + ["weapon_marksmanrifle"] = "רובה צלפים", + ["weapon_marksmanrifle_mk2"] = "רובה צלפים MK2", + ["weapon_sniperrifle"] = "רובה צלפים", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "משגר קומפקטי", + ["weapon_firework"] = "משגר זיקוקים", + ["weapon_grenadelauncher"] = "משגר רימונים", + ["weapon_hominglauncher"] = "משגר חפצים", + ["weapon_minigun"] = "מיניגן", + ["weapon_railgun"] = "רובה רכבת", + ["weapon_rpg"] = "משגר רקטות", + ["weapon_rayminigun"] = "Widowmaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "גלאי מתכות", + ["weapon_precisionrifle"] = "רובה דיוק", + ["weapon_tactilerifle"] = "רובה טקטילי", + + -- Drug wars dlc + ["weapon_candycane"] = "מקל סוכר", + ["weapon_acidpackage"] = "חומצה", + ["weapon_pistolxm3"] = "אקדח xm3", + ["weapon_railgunxm3"] = "רובה רכבת xm3", + -- Thrown + ["weapon_ball"] = "כדור בייסבול", + ["weapon_bzgas"] = "גז BZ", + ["weapon_flare"] = "זיקוק", + ["weapon_grenade"] = "רימון", + ["weapon_petrolcan"] = "גררון דלק", + ["weapon_hazardcan"] = "גררון מסוכן", + ["weapon_molotov"] = "קוקטייל מולוטוב", + ["weapon_proxmine"] = "מוקש קרבה", + ["weapon_pipebomb"] = "פצצת צינור", + ["weapon_snowball"] = "כדור שלג", + ["weapon_stickybomb"] = "פצצה דביקה", + ["weapon_smokegrenade"] = "גז דמעות", + + -- Special + ["weapon_fireextinguisher"] = "מטף כיבוי", + ["weapon_digiscanner"] = "סורק דיגיטלי", + ["weapon_garbagebag"] = "שקית זבל", + ["weapon_handcuffs"] = "כפפות", + ["gadget_nightvision"] = "ראיה לילית", + ["gadget_parachute"] = "צניחה", + + -- Weapon Components + ["component_knuckle_base"] = "דגם בסיסי", + ["component_knuckle_pimp"] = "הפימפ", + ["component_knuckle_ballas"] = "הבאלס", + ["component_knuckle_dollar"] = "ההאסטלר", + ["component_knuckle_diamond"] = "הרוק", + ["component_knuckle_hate"] = "השונא", + ["component_knuckle_love"] = "האוהב", + ["component_knuckle_player"] = "השחקן", + ["component_knuckle_king"] = "המלך", + ["component_knuckle_vagos"] = "הואגוס", + ["component_luxary_finish"] = "גימור מפואר", + + ["component_handle_default"] = "ידית רגילה", + ["component_handle_vip"] = "ידית VIP", + ["component_handle_bodyguard"] = "ידית שומר גוף", + + ["component_vip_finish"] = "גימור VIP", + ["component_bodyguard_finish"] = "גימור שומר גוף", + + ["component_camo_finish"] = "צפיעה דיגיטלית", + ["component_camo_finish2"] = "צפיעה צבעים מעורבים", + ["component_camo_finish3"] = "צפיעה יערותית", + ["component_camo_finish4"] = "צפיעה גולגולת", + ["component_camo_finish5"] = "צפיעה Sessanta Nove", + ["component_camo_finish6"] = "צפיעה Perseus", + ["component_camo_finish7"] = "צפיעה נמרים", + ["component_camo_finish8"] = "צפיעה זברה", + ["component_camo_finish9"] = "צפיעה גיאומטרית", + ["component_camo_finish10"] = "צפיעה Boom", + ["component_camo_finish11"] = "צפיעה פטריוטית", + + ["component_camo_slide_finish"] = "צפיעה דיגיטלית למחצלה", + ["component_camo_slide_finish2"] = "צפיעה צבעים מעורבים למחצלה", + ["component_camo_slide_finish3"] = "צפיעה יערותית למחצלה", + ["component_camo_slide_finish4"] = "צפיעה גולגולת למחצלה", + ["component_camo_slide_finish5"] = "צפיעה Sessanta Nove למחצלה", + ["component_camo_slide_finish6"] = "צפיעה Perseus למחצלה", + ["component_camo_slide_finish7"] = "צפיעה נמרים למחצלה", + ["component_camo_slide_finish8"] = "צפיעה זברה למחצלה", + ["component_camo_slide_finish9"] = "צפיעה גיאומטרית למחצלה", + ["component_camo_slide_finish10"] = "צפיעה Boom למחצלה", + ["component_camo_slide_finish11"] = "צפיעה פטריוטית למחצלה", + ["component_clip_default"] = "מחצירה רגילה", + ["component_clip_extended"] = "מחצירה מורחבת", + ["component_clip_drum"] = "מחצירה תוף", + ["component_clip_box"] = "מחצירה קופסה", + + ["component_scope_holo"] = "כוונת הולוגרפית", + ["component_scope_small"] = "כוונת קטנה", + ["component_scope_medium"] = "כוונת בינונית", + ["component_scope_large"] = "כוונת גדולה", + ["component_scope"] = "כוונת מותקנת", + ["component_scope_advanced"] = "כוונת מתקדמת", + ["component_ironsights"] = "כוונת ברזל", + + ["component_suppressor"] = "מרגיע", + ["component_compensator"] = "פיצוי", + + ["component_muzzle_flat"] = "מרסור שטוח", + ["component_muzzle_tactical"] = "מרסור טקטי", + ["component_muzzle_fat"] = "מרסור עגלגל", + ["component_muzzle_precision"] = "מרסור מדויק", + ["component_muzzle_heavy"] = "מרסור כבד", + ["component_muzzle_slanted"] = "מרסור מוטה", + ["component_muzzle_split"] = "מרסור פצול", + ["component_muzzle_squared"] = "מרסור מרובע", + + ["component_flashlight"] = "פנס", + ["component_grip"] = "אחיזה", + + ["component_barrel_default"] = "עצם רגיל", + ["component_barrel_heavy"] = "עצם כבד", + + ["component_ammo_tracer"] = "כדורים עקובים", + ["component_ammo_incendiary"] = "כדורים מדליקים", + ["component_ammo_hollowpoint"] = "כדורים חדים", + ["component_ammo_fmj"] = "כדורים FMJ", + ["component_ammo_armor"] = "כדורים חודרי משרוע", + ["component_ammo_explosive"] = "כדורים חודרי משרוע מדליקים", + + ["component_shells_default"] = "גלעינים רגילים", + ["component_shells_incendiary"] = "גלעינים מדליקים", + ["component_shells_armor"] = "גלעינים פלדלים", + ["component_shells_hollowpoint"] = "גלעינים חדים", + ["component_shells_explosive"] = "גלעינים מתפוצצים", + + -- Weapon Ammo + ["ammo_rounds"] = "כדור(ים)", + ["ammo_shells"] = "גלעין(ים)", + ["ammo_charge"] = "טעינה", + ["ammo_petrol"] = "גלונים של דלק", + ["ammo_firework"] = "זיקוק(ים)", + ["ammo_rockets"] = "טיל(ים)", + ["ammo_grenadelauncher"] = "רימון(ים)", + ["ammo_grenade"] = "רימון(ים)", + ["ammo_stickybomb"] = "פצצה/ות", + ["ammo_pipebomb"] = "פצצה/ות", + ["ammo_smokebomb"] = "פצצה/ות", + ["ammo_molotov"] = "קוקטייל(ים)", + ["ammo_proxmine"] = "מוקש/ים", + ["ammo_bzgas"] = "פח/ית", + ["ammo_ball"] = "כדור/ים", + ["ammo_snowball"] = "כדור/ים שלג", + ["ammo_flare"] = "זיקוק/ים", + ["ammo_flaregun"] = "זיקוק/ים", + + -- Weapon Tints + ["tint_default"] = "צבע רגיל", + ["tint_green"] = "צבע ירוק", + ["tint_gold"] = "צבע זהב", + ["tint_pink"] = "צבע ורוד", + ["tint_army"] = "צבע צבאי", + ["tint_lspd"] = "צבע כחול", + ["tint_orange"] = "צבע כתום", + ["tint_platinum"] = "צבע פלטינה", + -- MK2 Weapon Tints + ["tint_classic_black"] = "שחור קלאסי", + ["tint_classic_gray"] = "אפור קלאסי", + ["tint_classic_two_tone"] = "קלאסי דו-גוני", + ["tint_classic_white"] = "לבן קלאסי", + ["tint_classic_beige"] = "בז' קלאסי", + ["tint_classic_green"] = "ירוק קלאסי", + ["tint_classic_blue"] = "כחול קלאסי", + ["tint_classic_earth"] = "אדמה קלאסית", + ["tint_classic_brown_black"] = "חום שחור קלאסי", + ["tint_contrast_red"] = "אדום קונטרסט", + ["tint_contrast_blue"] = "כחול קונטרסט", + ["tint_contrast_yellow"] = "צהוב קונטרסט", + ["tint_contrast_orange"] = "כתום קונטרסט", + ["tint_bold_pink"] = "ורוד נועז", + ["tint_bold_purple_yellow"] = "סגול צהוב נועז", + ["tint_bold_orange"] = "כתום נועז", + ["tint_bold_green_purple"] = "ירוק סגול נועז", + ["tint_bold_red_feat"] = "אדום נועז feat", + ["tint_bold_green_feat"] = "ירוק נועז feat", + ["tint_bold_cyan_feat"] = "סיאן נועז feat", + ["tint_bold_yellow_feat"] = "צהוב נועז feat", + ["tint_bold_red_white"] = "אדום לבן נועז", + ["tint_bold_blue_white"] = "כחול לבן נועז", + ["tint_metallic_gold"] = "זהב מתכתי", + ["tint_metallic_platinum"] = "פלטינה מתכתית", + ["tint_metallic_gray_lilac"] = "אפור לילך מתכתי", + ["tint_metallic_purple_lime"] = "סגול ליים מתכתי", + ["tint_metallic_red"] = "אדום מתכתי", + ["tint_metallic_green"] = "ירוק מתכתי", + ["tint_metallic_blue"] = "כחול מתכתי", + ["tint_metallic_white_aqua"] = "לבן aqua מתכתי", + ["tint_metallic_red_yellow"] = "אדום צהוב מתכתי", +} diff --git a/resources/[core]/es_extended/locales/hu.lua b/resources/[core]/es_extended/locales/hu.lua new file mode 100644 index 0000000..c515932 --- /dev/null +++ b/resources/[core]/es_extended/locales/hu.lua @@ -0,0 +1,411 @@ +return { + -- Inventory + ["inventory"] = "Inventory ( Súly %s / %s )", + ["use"] = "Használ", + ["give"] = "Átad", + ["remove"] = "Eldob", + ["return"] = "Visszatérés", + ["give_to"] = "Adni valakinek", + ["amount"] = "Mennyiség", + ["giveammo"] = "Lőszer adás", + ["amountammo"] = "Lőszer mennyiség", + ["noammo"] = "Nincsen több lövedéked!", + ["gave_item"] = "Átadtál: %sx %s neki: %s", + ["received_item"] = "Kaptál: %sx %s töle: %s", + ["gave_weapon"] = "Átadtál: %s neki: %s", + ["gave_weapon_ammo"] = "Átadtál ~o~%sx %s %s neki: %s", + ["gave_weapon_withammo"] = "Átadtál %s ~o~%sx %s neki: %s", + ["gave_weapon_hasalready"] = "%s már rendelkezik %s", + ["gave_weapon_noweapon"] = "%s nincsen ilyen fegyere", + ["received_weapon"] = "Kaptál: %s töle: %s", + ["received_weapon_ammo"] = "Kaptál ~o~%sx %s %s töle: %s", + ["received_weapon_withammo"] = "Kaptál %s ~o~%sx %s töle: %s", + ["received_weapon_hasalready"] = "%s megpróbálta átadni a következöt: %s, nem már van rendelkezel egy ilyennel", + ["received_weapon_noweapon"] = "%s átakart adni %s, de nincsen ilyen fegyvered", + ["gave_account_money"] = "Átadtál: $%s (%s) neki: %s", + ["received_account_money"] = "Kaptál: $%s (%s) töle: %s", + ["amount_invalid"] = "Érvénytelen mennyiség", + ["players_nearby"] = "Nincsen játékos a közeledben", + ["ex_inv_lim"] = "Nincsen elég szabad helyed %s", + ["imp_invalid_quantity"] = "Érvénytelen mennyiség", + ["imp_invalid_amount"] = "Érvénytelen összeg", + ["threw_standard"] = "Kidobtál: %sx %s", + ["threw_account"] = "Kidobtál: $%s %s", + ["threw_weapon"] = "Kidobtál: %s", + ["threw_weapon_ammo"] = "Kidobtál: %s ~o~%sx %s", + ["threw_weapon_already"] = "Van már ilyen fegyvered", + ["threw_cannot_pickup"] = "Nincsen elég szabad helyed", + ["threw_pickup_prompt"] = "E hogy felvedd", + + -- Key mapping + ["keymap_showinventory"] = "Leltár mutatása", + + -- Salary related + ["received_salary"] = "Megkaptad a fizetésed: $%s", + ["received_help"] = "Megkaptad a segélyt: $%s", + ["company_nomoney"] = "Nem kaptál fizetést, mert a frakciónak nincs elég pénze!", + ["received_paycheck"] = "Fizetésed érkezett!", + ["bank"] = "maze Bank", + ["account_bank"] = "bank", + ["account_black_money"] = "Piszkos pénz", + ["account_money"] = "Készpénz", + + ["act_imp"] = "Érvénytelen mennyiség", + ["in_vehicle"] = "Nem tudod átadni, mivel benne ül a jármüben", + ["not_in_vehicle"] = "Cannot Perform Action, Player isn't in a vehicle", + + -- Commands + ["command_bring"] = "Játékos magadhoz teleportálása", + ["command_car"] = "Jármű lehívása", + ["command_car_car"] = "Jármű név vagy hash", + ["command_cardel"] = "Közeli járművek törlése", + ["command_cardel_radius"] = "Megadott radiusban lévő járművek törlése", + ["command_repair"] = "Repair your vehicle", + ["command_repair_success"] = "Successfully repaired vehicle", + ["command_repair_success_target"] = "An admin repaired your vehicle", + ["command_clear"] = "Chat ürítése", + ["command_clearall"] = "Chat ürítése minden játékosnál", + ["command_clearinventory"] = "Minden tárgy törlése a játékos inventoryból", + ["command_clearloadout"] = "Minden fegyver elvétele a játékostól", + ["command_freeze"] = "Játékos fagyasztása", + ["command_unfreeze"] = "Játékos kiolvasztása", + ["command_giveaccountmoney"] = "Pénz adás a megadott típusban", + ["command_giveaccountmoney_account"] = "Típus", + ["command_giveaccountmoney_amount"] = "Mennyiség", + ["command_giveaccountmoney_invalid"] = "Megadott típus hibás", + ["command_giveitem"] = "Tárgy adás a játékosnak", + ["command_giveitem_item"] = "Tárgy neve", + ["command_giveitem_count"] = "Mennyiség", + ["command_giveweapon"] = "Fegyver adás játékosnak", + ["command_giveweapon_weapon"] = "Fegyver neve", + ["command_giveweapon_ammo"] = "Lőszer mennyiség", + ["command_giveweapon_hasalready"] = "Játékosnak már van ilyen fegyvere", + ["command_giveweaponcomponent"] = "Fegyver kiegészítő adás a játékosnak", + ["command_giveweaponcomponent_component"] = "Kiegészítő neve", + ["command_giveweaponcomponent_invalid"] = "Érvénytelen fegyver kiegészítő", + ["command_giveweaponcomponent_hasalready"] = "Játékosnak már van ilyen fegyver kiegészítője", + ["command_giveweaponcomponent_missingweapon"] = "Játékosnak nincs ilyen fegyvere", + ["command_goto"] = "Teleportálás játékoshoz", + ["command_kill"] = "Játékos megölése", + ["command_save"] = "Játékos adatainak mentése", + ["command_saveall"] = "Összes játékos adatainak mentése", + ["command_setaccountmoney"] = "Játékos pénzének beállítása megadott típusban", + ["command_setaccountmoney_amount"] = "Mennyiség", + ["command_setcoords"] = "Teleportálás megadott kordinátára", + ["command_setcoords_x"] = "X érték", + ["command_setcoords_y"] = "Y érték", + ["command_setcoords_z"] = "Z érték", + ["command_setjob"] = "Játékos munkájának beállítása", + ["command_setjob_job"] = "Munka neve", + ["command_setjob_grade"] = "Rang", + ["command_setjob_invalid"] = "Munka név vagy rang érvénytelen", + ["command_setgroup"] = "Játékos jogosultsági csoportjának beállítása", + ["command_setgroup_group"] = "Csoport neve", + ["commanderror_argumentmismatch"] = "Érvénytelen argumentumszám (%s megadva, %s szükséges)", + ["commanderror_argumentmismatch_number"] = "Érvénytelen argumentum #%s adat típus (szöveg megadva, szám szükséges)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (passed number, wanted string)", + ["commanderror_argumentmismatch_positive_number"] = "Érvénytelen argumentum #%s adattípus (negatív/nulla átadva, pozitív szám szükséges)", + ["commanderror_invaliditem"] = "Érvénytelen tárgy", + ["commanderror_invalidweapon"] = "Érvénytelen fegyver", + ["commanderror_console"] = "Parancs nem használható konzolból", + ["commanderror_invalidcommand"] = "Érvénytelen parancs - /%s", + ["commanderror_invalidplayerid"] = "Megadott játékos nem online.", + ["commandgeneric_playerid"] = "Játékos Szerver Id", + ["command_giveammo_noweapon_found"] = "Nincs ilyen fegyvered: %s", + ["command_giveammo_weapon"] = "Fegyver név", + ["command_giveammo_ammo"] = "Lőszer mennyiség", + ["tpm_nowaypoint"] = "Nincs kijelölve pozíció!", + ["tpm_success"] = "Sikeres teleportálás", + + ["noclip_message"] = "Noclip %s", + ["enabled"] = "~g~engedélyezve~s~", + ["disabled"] = "~r~letiltva~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "$%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dagger", + ["weapon_bat"] = "Bat", + ["weapon_battleaxe"] = "Battle Axe", + ["weapon_bottle"] = "Bottle", + ["weapon_crowbar"] = "Crowbar", + ["weapon_flashlight"] = "Flashlight", + ["weapon_golfclub"] = "Golf Club", + ["weapon_hammer"] = "Hammer", + ["weapon_hatchet"] = "Hatchet", + ["weapon_knife"] = "Knife", + ["weapon_knuckle"] = "Knuckledusters", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Nightstick", + ["weapon_wrench"] = "Pipe Wrench", + ["weapon_poolcue"] = "Pool Cue", + ["weapon_stone_hatchet"] = "Stone Hatchet", + ["weapon_switchblade"] = "Switchblade", + + -- Handguns + ["weapon_appistol"] = "AP Pistol", + ["weapon_ceramicpistol"] = "Ceramic Pistol", + ["weapon_combatpistol"] = "Combat Pistol", + ["weapon_doubleaction"] = "Double-Action Revolver", + ["weapon_navyrevolver"] = "Navy Revolver", + ["weapon_flaregun"] = "Flaregun", + ["weapon_gadgetpistol"] = "Gadget Pistol", + ["weapon_heavypistol"] = "Heavy Pistol", + ["weapon_revolver"] = "Heavy Revolver", + ["weapon_revolver_mk2"] = "Heavy Revolver MK2", + ["weapon_marksmanpistol"] = "Marksman Pistol", + ["weapon_pistol"] = "Pistol", + ["weapon_pistol_mk2"] = "Pistol MK2", + ["weapon_pistol50"] = "Pistol .50", + ["weapon_snspistol"] = "SNS Pistol", + ["weapon_snspistol_mk2"] = "SNS Pistol MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Vintage Pistol", + + -- Shotguns + ["weapon_assaultshotgun"] = "Assault Shotgun", + ["weapon_autoshotgun"] = "Auto Shotgun", + ["weapon_bullpupshotgun"] = "Bullpup Shotgun", + ["weapon_combatshotgun"] = "Combat Shotgun", + ["weapon_dbshotgun"] = "Double Barrel Shotgun", + ["weapon_heavyshotgun"] = "Heavy Shotgun", + ["weapon_musket"] = "Musket", + ["weapon_pumpshotgun"] = "Pump Shotgun", + ["weapon_pumpshotgun_mk2"] = "Pump Shotgun MK2", + ["weapon_sawnoffshotgun"] = "Sawed Off Shotgun", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Assault SMG", + ["weapon_combatmg"] = "Combat MG", + ["weapon_combatmg_mk2"] = "Combat MG MK2", + ["weapon_combatpdw"] = "Combat PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Machine Pistol", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Unholy Hellbringer", + + -- Rifles + ["weapon_advancedrifle"] = "Advanced Rifle", + ["weapon_assaultrifle"] = "Assault Rifle", + ["weapon_assaultrifle_mk2"] = "Assault Rifle MK2", + ["weapon_bullpuprifle"] = "Bullpup Rifle", + ["weapon_bullpuprifle_mk2"] = "Bullpup Rifle MK2", + ["weapon_carbinerifle"] = "Carbine Rifle", + ["weapon_carbinerifle_mk2"] = "Carbine Rifle MK2", + ["weapon_compactrifle"] = "Compact Rifle", + ["weapon_militaryrifle"] = "Military Rifle", + ["weapon_specialcarbine"] = "Special Carbine", + ["weapon_specialcarbine_mk2"] = "Special Carbine MK2", + ["weapon_heavyrifle"] = "Heavy Rifle", -- Not Translated + + -- Sniper + ["weapon_heavysniper"] = "Heavy Sniper", + ["weapon_heavysniper_mk2"] = "Heavy Sniper MK2", + ["weapon_marksmanrifle"] = "Marksman Rifle", + ["weapon_marksmanrifle_mk2"] = "Marksman Rifle MK2", + ["weapon_sniperrifle"] = "Sniper Rifle", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Compact Launcher", + ["weapon_firework"] = "Firework Launcher", + ["weapon_grenadelauncher"] = "Grenade Launcher", + ["weapon_hominglauncher"] = "Homing Launcher", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Rocket Launcher", + ["weapon_rayminigun"] = "Widowmaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Fémkereső", + ["weapon_precisionrifle"] = "Precision Rifle", + ["weapon_tactilerifle"] = "Service Carbine", + + -- Drug Wars DLC + ["weapon_candycane"] = "Candy Cane", -- not translated + ["weapon_acidpackage"] = "Acid Package", -- not translated + ["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated + ["weapon_railgunxm3"] = "Railgun", -- not translated + + -- Thrown + ["weapon_ball"] = "Baseball", + ["weapon_bzgas"] = "BZ Gas", + ["weapon_flare"] = "Flare", + ["weapon_grenade"] = "Grenade", + ["weapon_petrolcan"] = "Jerrycan", + ["weapon_hazardcan"] = "Hazardous Jerrycan", + ["weapon_molotov"] = "Molotov Cocktail", + ["weapon_proxmine"] = "Proximity Mine", + ["weapon_pipebomb"] = "Pipe Bomb", + ["weapon_snowball"] = "Snowball", + ["weapon_stickybomb"] = "Sticky Bomb", + ["weapon_smokegrenade"] = "Tear Gas", + + -- Special + ["weapon_fireextinguisher"] = "Fire Extinguisher", + ["weapon_digiscanner"] = "Digital Scanner", + ["weapon_garbagebag"] = "Garbage Bag", + ["weapon_handcuffs"] = "Handcuffs", + ["gadget_nightvision"] = "Night Vision", + ["gadget_parachute"] = "parachute", + + -- Weapon Components + ["component_knuckle_base"] = "base Model", + ["component_knuckle_pimp"] = "the Pimp", + ["component_knuckle_ballas"] = "the Ballas", + ["component_knuckle_dollar"] = "the Hustler", + ["component_knuckle_diamond"] = "the Rock", + ["component_knuckle_hate"] = "the Hater", + ["component_knuckle_love"] = "the Lover", + ["component_knuckle_player"] = "the Player", + ["component_knuckle_king"] = "the King", + ["component_knuckle_vagos"] = "the Vagos", + + ["component_luxary_finish"] = "luxary Weapon Finish", + + ["component_handle_default"] = "default Handle", + ["component_handle_vip"] = "vIP Handle", + ["component_handle_bodyguard"] = "bodyguard Handle", + + ["component_vip_finish"] = "vIP Finish", + ["component_bodyguard_finish"] = "bodyguard Finish", + + ["component_camo_finish"] = "digital Camo", + ["component_camo_finish2"] = "brushstroke Camo", + ["component_camo_finish3"] = "woodland Camo", + ["component_camo_finish4"] = "skull Camo", + ["component_camo_finish5"] = "sessanta Nove Camo", + ["component_camo_finish6"] = "perseus Camo", + ["component_camo_finish7"] = "leopard Camo", + ["component_camo_finish8"] = "zebra Camo", + ["component_camo_finish9"] = "geometric Camo", + ["component_camo_finish10"] = "boom Camo", + ["component_camo_finish11"] = "patriotic Camo", + + ["component_camo_slide_finish"] = "digital Slide Camo", + ["component_camo_slide_finish2"] = "brushstroke Slide Camo", + ["component_camo_slide_finish3"] = "woodland Slide Camo", + ["component_camo_slide_finish4"] = "skull Slide Camo", + ["component_camo_slide_finish5"] = "sessanta Nove Slide Camo", + ["component_camo_slide_finish6"] = "perseus Slide Camo", + ["component_camo_slide_finish7"] = "leopard Slide Camo", + ["component_camo_slide_finish8"] = "zebra Slide Camo", + ["component_camo_slide_finish9"] = "geometric Slide Camo", + ["component_camo_slide_finish10"] = "boom Slide Camo", + ["component_camo_slide_finish11"] = "patriotic Slide Camo", + + ["component_clip_default"] = "default Magazine", + ["component_clip_extended"] = "extended Magazine", + ["component_clip_drum"] = "drum Magazine", + ["component_clip_box"] = "box Magazine", + + ["component_scope_holo"] = "holographic Scope", + ["component_scope_small"] = "small Scope", + ["component_scope_medium"] = "medium Scope", + ["component_scope_large"] = "large Scope", + ["component_scope"] = "mounted Scope", + ["component_scope_advanced"] = "advanced Scope", + ["component_ironsights"] = "ironsights", + + ["component_suppressor"] = "suppressor", + ["component_compensator"] = "compensator", + + ["component_muzzle_flat"] = "flat Muzzle Brake", + ["component_muzzle_tactical"] = "tactical Muzzle Brake", + ["component_muzzle_fat"] = "fat-End Muzzle Brake", + ["component_muzzle_precision"] = "precision Muzzle Brake", + ["component_muzzle_heavy"] = "heavy Duty Muzzle Brake", + ["component_muzzle_slanted"] = "slanted Muzzle Brake", + ["component_muzzle_split"] = "split-End Muzzle Brake", + ["component_muzzle_squared"] = "squared Muzzle Brake", + + ["component_flashlight"] = "flashlight", + ["component_grip"] = "grip", + + ["component_barrel_default"] = "default Barrel", + ["component_barrel_heavy"] = "heavy Barrel", + + ["component_ammo_tracer"] = "tracer Ammo", + ["component_ammo_incendiary"] = "incendiary Ammo", + ["component_ammo_hollowpoint"] = "hollowpoint Ammo", + ["component_ammo_fmj"] = "fMJ Ammo", + ["component_ammo_armor"] = "armor Piercing Ammo", + ["component_ammo_explosive"] = "armor Piercing Incendiary Ammo", + + ["component_shells_default"] = "default Shells", + ["component_shells_incendiary"] = "dragons Breath Shells", + ["component_shells_armor"] = "steel Buckshot Shells", + ["component_shells_hollowpoint"] = "flechette Shells", + ["component_shells_explosive"] = "explosive Slug Shells", + + -- Weapon Ammo + ["ammo_rounds"] = "round(s)", + ["ammo_shells"] = "shell(s)", + ["ammo_charge"] = "charge", + ["ammo_petrol"] = "gallons of fuel", + ["ammo_firework"] = "firework(s)", + ["ammo_rockets"] = "rocket(s)", + ["ammo_grenadelauncher"] = "grenade(s)", + ["ammo_grenade"] = "grenade(s)", + ["ammo_stickybomb"] = "bomb(s)", + ["ammo_pipebomb"] = "bomb(s)", + ["ammo_smokebomb"] = "bomb(s)", + ["ammo_molotov"] = "cocktail(s)", + ["ammo_proxmine"] = "mine(s)", + ["ammo_bzgas"] = "can(s)", + ["ammo_ball"] = "ball(s)", + ["ammo_snowball"] = "snowball(s)", + ["ammo_flare"] = "flare(s)", + ["ammo_flaregun"] = "flare(s)", + + -- Weapon Tints + ["tint_default"] = "default skin", + ["tint_green"] = "green skin", + ["tint_gold"] = "gold skin", + ["tint_pink"] = "pink skin", + ["tint_army"] = "army skin", + ["tint_lspd"] = "blue skin", + ["tint_orange"] = "orange skin", + ["tint_platinum"] = "platinum skin", + -- MK2 Weapon Tints + ["tint_classic_black"] = "klasszikus fekete", + ["tint_classic_gray"] = "klasszikus szürke", + ["tint_classic_two_tone"] = "klasszikus két szín", + ["tint_classic_white"] = "klasszikus fehér", + ["tint_classic_beige"] = "klasszikus bézs", + ["tint_classic_green"] = "klasszikus zöld", + ["tint_classic_blue"] = "klasszikus kék", + ["tint_classic_earth"] = "klasszikus föld", + ["tint_classic_brown_black"] = "klasszikus barna-fekete", + ["tint_contrast_red"] = "kontraszt piros", + ["tint_contrast_blue"] = "kontraszt kék", + ["tint_contrast_yellow"] = "kontraszt sárga", + ["tint_contrast_orange"] = "kontraszt narancs", + ["tint_bold_pink"] = "merész rózsaszín", + ["tint_bold_purple_yellow"] = "merész lila-sárga", + ["tint_bold_orange"] = "merész narancs", + ["tint_bold_green_purple"] = "merész zöld-lila", + ["tint_bold_red_feat"] = "merész piros feat", + ["tint_bold_green_feat"] = "merész zöld feat", + ["tint_bold_cyan_feat"] = "merész cián feat", + ["tint_bold_yellow_feat"] = "merész sárga feat", + ["tint_bold_red_white"] = "merész piros fehér", + ["tint_bold_blue_white"] = "merész kék fehér", + ["tint_metallic_gold"] = "metál arany", + ["tint_metallic_platinum"] = "metál platina", + ["tint_metallic_gray_lilac"] = "metál szürke lila", + ["tint_metallic_purple_lime"] = "metál lila lime", + ["tint_metallic_red"] = "metál piros", + ["tint_metallic_green"] = "metál zöld", + ["tint_metallic_blue"] = "metál kék", + ["tint_metallic_white_aqua"] = "metál fehér aqua", + ["tint_metallic_red_yellow"] = "metál piros sárga", +} diff --git a/resources/[core]/es_extended/locales/id.lua b/resources/[core]/es_extended/locales/id.lua new file mode 100644 index 0000000..17c1332 --- /dev/null +++ b/resources/[core]/es_extended/locales/id.lua @@ -0,0 +1,415 @@ +return { + -- Inventory + ["inventory"] = "Inventaris ( Berat %s / %s )", + ["use"] = "Gunakan", + ["give"] = "Beri", + ["remove"] = "Buang", + ["return"] = "Kembali", + ["give_to"] = "Beri ke", + ["amount"] = "Jumlah", + ["giveammo"] = "Beri amunisi", + ["amountammo"] = "Jumlah Amunisi", + ["noammo"] = "Tidak cukup!", + ["gave_item"] = "Memberi %sx %s ke %s", + ["received_item"] = "Menerima %sx %s dari %s", + ["gave_weapon"] = "Memberi %s ke %s", + ["gave_weapon_ammo"] = "Memberi ~o~%sx %s untuk %s ke %s", + ["gave_weapon_withammo"] = "Memberi %s dengan ~o~%sx %s ke %s", + ["gave_weapon_hasalready"] = "%s sudah memiliki %s", + ["gave_weapon_noweapon"] = "%s tidak memiliki senjata tersebut", + ["received_weapon"] = "Menerima %s dari %s", + ["received_weapon_ammo"] = "Menerima ~o~%sx %s untuk %s Anda dari %s", + ["received_weapon_withammo"] = "Menerima %s dengan ~o~%sx %s dari %s", + ["received_weapon_hasalready"] = "%s mencoba memberimu %s, tapi kamu sudah memiliki senjata ini", + ["received_weapon_noweapon"] = "%s mencoba memberimu amunisi untuk %s, tapi kamu tidak memiliki senjata ini", + ["gave_account_money"] = "Memberi $%s (%s) ke %s", + ["received_account_money"] = "Menerima $%s (%s) dari %s", + ["amount_invalid"] = "Jumlah salah", + ["players_nearby"] = "Tidak ada Player di sekitar", + ["ex_inv_lim"] = "Tidak dapat melakukan aksi, melebihi batas berat dari %s", + ["imp_invalid_quantity"] = "Tidak dapat melakukan aksi, jumlah salah", + ["imp_invalid_amount"] = "Tidak dapat melakukan aksi, jumlah salah", + ["threw_standard"] = "Membuang %sx %s", + ["threw_account"] = "Membuang $%s %s", + ["threw_weapon"] = "Membuang %s", + ["threw_weapon_ammo"] = "Membuang %s dengan ~o~%sx %s", + ["threw_weapon_already"] = "Kamu sudah memiliki senjata ini", + ["threw_cannot_pickup"] = "Inventaris penuh, Tidak dapat mengambil!", + ["threw_pickup_prompt"] = "Tekan E untuk Mengambil", + + -- Key mapping + ["keymap_showinventory"] = "Buka Inventaris", + + -- Salary related + ["received_salary"] = "Anda telah dibayar: $%s", + ["received_help"] = "Anda telah menerima dana kesejahteraan: $%s", + ["company_nomoney"] = "perusahaan tempat Anda bekerja terlalu miskin untuk membayar gaji Anda", + ["received_paycheck"] = "menerima gaji", + ["bank"] = "Maze Bank", + ["account_bank"] = "Bank", + ["account_black_money"] = "Dirty Money", + ["account_money"] = "Cash", + + ["act_imp"] = "Tidak dapat melakukan aksi", + ["in_vehicle"] = "Tidak dapat melakukan aksi, Player di dalam kendaraan", + ["not_in_vehicle"] = "Tidak dapat melakukan aksi, Player tidak di dalam kendaraan", + + -- Commands + ["command_bring"] = "Bawa player kepadamu", + ["command_car"] = "Munculkan kendaraan", + ["command_car_car"] = "Model atau hash kendaraan", + ["command_cardel"] = "Menghilangkan kendaraan di sekitar", + ["command_cardel_radius"] = "Menghilangkan semua kendaraan dalam radius yang ditentukan", + ["command_repair"] = "Perbaiki kendaraanmu", + ["command_repair_success"] = "Berhasil memperbaiki kendaraan", + ["command_repair_success_target"] = "Admin memperbaiki kendaraanmu", + ["command_clear"] = "Bersihkan teks chat", + ["command_clearall"] = "Bersihkan teks chat untuk semua player", + ["command_clearinventory"] = "Hilangkan semua barang dari Inventaris Player", + ["command_clearloadout"] = "Hilangkan semua senjata dari Loadout Player", + ["command_freeze"] = "Bekukan player", + ["command_unfreeze"] = "Kembalikan player", + ["command_giveaccountmoney"] = "Beri uang ke rekening tertentu", + ["command_giveaccountmoney_account"] = "Rekening untuk ditambahkan", + ["command_giveaccountmoney_amount"] = "Jumlah untuk ditambahkan", + ["command_giveaccountmoney_invalid"] = "Nama Rekening Salah", + ["command_removeaccountmoney"] = "Hilangkan uang dari rekening tertentu", + ["command_removeaccountmoney_account"] = "Rekening yang akan dihapus", + ["command_removeaccountmoney_amount"] = "Jumlah yang dihapus", + ["command_removeaccountmoney_invalid"] = "Nama Rekening Salah", + ["command_giveitem"] = "Beri Player barang", + ["command_giveitem_item"] = "Nama Barang", + ["command_giveitem_count"] = "Jumlah", + ["command_giveweapon"] = "Beri player senjata", + ["command_giveweapon_weapon"] = "Nama Senjata", + ["command_giveweapon_ammo"] = "Jumlah Amunisi", + ["command_giveweapon_hasalready"] = "Player telah memiliki senjata ini", + ["command_giveweaponcomponent"] = "Beri komponen senjata ke player", + ["command_giveweaponcomponent_component"] = "Nama Komponen", + ["command_giveweaponcomponent_invalid"] = "Komponen Senjata Salah", + ["command_giveweaponcomponent_hasalready"] = "Player telah memiliki komponen senjata ini", + ["command_giveweaponcomponent_missingweapon"] = "Player tidak memiliki senjata ini", + ["command_goto"] = "Teleportasi dirimu ke player", + ["command_kill"] = "Bunuh player", + ["command_save"] = "Paksa Simpan Data player", + ["command_saveall"] = "Paksa Simpan Data semua player", + ["command_setaccountmoney"] = "Atur uang dalam rekening tertentu", + ["command_setaccountmoney_amount"] = "Jumlah", + ["command_setcoords"] = "Teleportasi ke koordinat tertentu", + ["command_setcoords_x"] = "Posisi X", + ["command_setcoords_y"] = "Posisi Y", + ["command_setcoords_z"] = "Posisi Z", + ["command_setjob"] = "Beri player pekerjaan", + ["command_setjob_job"] = "Nama", + ["command_setjob_grade"] = "Jabatan pekerjaan", + ["command_setjob_invalid"] = "pekerjaan, jabatan atau keduanya salah", + ["command_setgroup"] = "Atur izn grup player", + ["command_setgroup_group"] = "Nama Grup", + ["commanderror_argumentmismatch"] = "Jumlah Argument Salah (passed %s, wanted %s)", + ["commanderror_argumentmismatch_number"] = "Argument #%s salah tipe data (passed string, wanted number)", + ["commanderror_argumentmismatch_string"] = "Argument #%s salah tipe data (passed number, wanted string)", + ["commanderror_argumentmismatch_positive_number"] = "Argument #%s salah tipe data (diberikan negatif/nol, diinginkan angka positif)", + ["commanderror_invaliditem"] = "Barang salah", + ["commanderror_invalidweapon"] = "Senjata salah", + ["commanderror_console"] = "Perintah tidak dapat dieksekusi dari console", + ["commanderror_invalidcommand"] = "Perintah Salah - /%s", + ["commanderror_invalidplayerid"] = "Player tersebut tidak online", + ["commandgeneric_playerid"] = "Id Server Player", + ["command_giveammo_noweapon_found"] = "%s tidak memiliki senjata tersebut", + ["command_giveammo_weapon"] = "Nama Senjata", + ["command_giveammo_ammo"] = "Jumlah Amunisi", + ["tpm_nowaypoint"] = "Titik Lokasi Tidak Diatur.", + ["tpm_success"] = "Berhasil Teleportasi", + + ["noclip_message"] = "Noclip telah %s", + ["enabled"] = "~g~diaktifkan~s~", + ["disabled"] = "~r~dimatikan~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "£%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dagger", + ["weapon_bat"] = "Bat", + ["weapon_battleaxe"] = "Battle Axe", + ["weapon_bottle"] = "Bottle", + ["weapon_crowbar"] = "Crowbar", + ["weapon_flashlight"] = "Flashlight", + ["weapon_golfclub"] = "Golf Club", + ["weapon_hammer"] = "Hammer", + ["weapon_hatchet"] = "Hatchet", + ["weapon_knife"] = "Knife", + ["weapon_knuckle"] = "Knuckledusters", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Nightstick", + ["weapon_wrench"] = "Pipe Wrench", + ["weapon_poolcue"] = "Pool Cue", + ["weapon_stone_hatchet"] = "Stone Hatchet", + ["weapon_switchblade"] = "Switchblade", + + -- Handguns + ["weapon_appistol"] = "AP Pistol", + ["weapon_ceramicpistol"] = "Ceramic Pistol", + ["weapon_combatpistol"] = "Combat Pistol", + ["weapon_doubleaction"] = "Double-Action Revolver", + ["weapon_navyrevolver"] = "Navy Revolver", + ["weapon_flaregun"] = "Flaregun", + ["weapon_gadgetpistol"] = "Gadget Pistol", + ["weapon_heavypistol"] = "Heavy Pistol", + ["weapon_revolver"] = "Heavy Revolver", + ["weapon_revolver_mk2"] = "Heavy Revolver MK2", + ["weapon_marksmanpistol"] = "Marksman Pistol", + ["weapon_pistol"] = "Pistol", + ["weapon_pistol_mk2"] = "Pistol MK2", + ["weapon_pistol50"] = "Pistol .50", + ["weapon_snspistol"] = "SNS Pistol", + ["weapon_snspistol_mk2"] = "SNS Pistol MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Vintage Pistol", + + -- Shotguns + ["weapon_assaultshotgun"] = "Assault Shotgun", + ["weapon_autoshotgun"] = "Auto Shotgun", + ["weapon_bullpupshotgun"] = "Bullpup Shotgun", + ["weapon_combatshotgun"] = "Combat Shotgun", + ["weapon_dbshotgun"] = "Double Barrel Shotgun", + ["weapon_heavyshotgun"] = "Heavy Shotgun", + ["weapon_musket"] = "Musket", + ["weapon_pumpshotgun"] = "Pump Shotgun", + ["weapon_pumpshotgun_mk2"] = "Pump Shotgun MK2", + ["weapon_sawnoffshotgun"] = "Sawed Off Shotgun", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Assault SMG", + ["weapon_combatmg"] = "Combat MG", + ["weapon_combatmg_mk2"] = "Combat MG MK2", + ["weapon_combatpdw"] = "Combat PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Machine Pistol", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Unholy Hellbringer", + + -- Rifles + ["weapon_advancedrifle"] = "Advanced Rifle", + ["weapon_assaultrifle"] = "Assault Rifle", + ["weapon_assaultrifle_mk2"] = "Assault Rifle MK2", + ["weapon_bullpuprifle"] = "Bullpup Rifle", + ["weapon_bullpuprifle_mk2"] = "Bullpup Rifle MK2", + ["weapon_carbinerifle"] = "Carbine Rifle", + ["weapon_carbinerifle_mk2"] = "Carbine Rifle MK2", + ["weapon_compactrifle"] = "Compact Rifle", + ["weapon_militaryrifle"] = "Military Rifle", + ["weapon_specialcarbine"] = "Special Carbine", + ["weapon_specialcarbine_mk2"] = "Special Carbine MK2", + ["weapon_heavyrifle"] = "Heavy Rifle", + + -- Sniper + ["weapon_heavysniper"] = "Heavy Sniper", + ["weapon_heavysniper_mk2"] = "Heavy Sniper MK2", + ["weapon_marksmanrifle"] = "Marksman Rifle", + ["weapon_marksmanrifle_mk2"] = "Marksman Rifle MK2", + ["weapon_sniperrifle"] = "Sniper Rifle", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Compact Launcher", + ["weapon_firework"] = "Firework Launcher", + ["weapon_grenadelauncher"] = "Grenade Launcher", + ["weapon_hominglauncher"] = "Homing Launcher", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Rocket Launcher", + ["weapon_rayminigun"] = "Widowmaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Metal Detector", + ["weapon_precisionrifle"] = "Precision Rifle", + ["weapon_tactilerifle"] = "Service Carbine", + + -- Drug wars dlc + ["weapon_candycane"] = "Candycane", + ["weapon_acidpackage"] = "Acid Package", + ["weapon_pistolxm3"] = "Pistol8 x3m", + ["weapon_railgunxm3"] = "Railgun", + + -- Thrown + ["weapon_ball"] = "Baseball", + ["weapon_bzgas"] = "BZ Gas", + ["weapon_flare"] = "Flare", + ["weapon_grenade"] = "Grenade", + ["weapon_petrolcan"] = "Jerrycan", + ["weapon_hazardcan"] = "Hazardous Jerrycan", + ["weapon_molotov"] = "Molotov Cocktail", + ["weapon_proxmine"] = "Proximity Mine", + ["weapon_pipebomb"] = "Pipe Bomb", + ["weapon_snowball"] = "Snowball", + ["weapon_stickybomb"] = "Sticky Bomb", + ["weapon_smokegrenade"] = "Tear Gas", + + -- Special + ["weapon_fireextinguisher"] = "Pemadam Api", + ["weapon_digiscanner"] = "Digital Scanner", + ["weapon_garbagebag"] = "Kantong Sampah", + ["weapon_handcuffs"] = "Borgol", + ["gadget_nightvision"] = "Night Vision", + ["gadget_parachute"] = "Parasut", + + -- Weapon Components + ["component_knuckle_base"] = "base Model", + ["component_knuckle_pimp"] = "the Pimp", + ["component_knuckle_ballas"] = "the Ballas", + ["component_knuckle_dollar"] = "the Hustler", + ["component_knuckle_diamond"] = "the Rock", + ["component_knuckle_hate"] = "the Hater", + ["component_knuckle_love"] = "the Lover", + ["component_knuckle_player"] = "the Player", + ["component_knuckle_king"] = "the King", + ["component_knuckle_vagos"] = "the Vagos", + + ["component_luxary_finish"] = "luxary Weapon Finish", + + ["component_handle_default"] = "default Handle", + ["component_handle_vip"] = "vIP Handle", + ["component_handle_bodyguard"] = "bodyguard Handle", + + ["component_vip_finish"] = "vIP Finish", + ["component_bodyguard_finish"] = "bodyguard Finish", + + ["component_camo_finish"] = "digital Camo", + ["component_camo_finish2"] = "brushstroke Camo", + ["component_camo_finish3"] = "woodland Camo", + ["component_camo_finish4"] = "skull Camo", + ["component_camo_finish5"] = "sessanta Nove Camo", + ["component_camo_finish6"] = "perseus Camo", + ["component_camo_finish7"] = "leopard Camo", + ["component_camo_finish8"] = "zebra Camo", + ["component_camo_finish9"] = "geometric Camo", + ["component_camo_finish10"] = "boom Camo", + ["component_camo_finish11"] = "patriotic Camo", + + ["component_camo_slide_finish"] = "digital Slide Camo", + ["component_camo_slide_finish2"] = "brushstroke Slide Camo", + ["component_camo_slide_finish3"] = "woodland Slide Camo", + ["component_camo_slide_finish4"] = "skull Slide Camo", + ["component_camo_slide_finish5"] = "sessanta Nove Slide Camo", + ["component_camo_slide_finish6"] = "perseus Slide Camo", + ["component_camo_slide_finish7"] = "leopard Slide Camo", + ["component_camo_slide_finish8"] = "zebra Slide Camo", + ["component_camo_slide_finish9"] = "geometric Slide Camo", + ["component_camo_slide_finish10"] = "boom Slide Camo", + ["component_camo_slide_finish11"] = "patriotic Slide Camo", + + ["component_clip_default"] = "default Magazine", + ["component_clip_extended"] = "extended Magazine", + ["component_clip_drum"] = "drum Magazine", + ["component_clip_box"] = "box Magazine", + + ["component_scope_holo"] = "holographic Scope", + ["component_scope_small"] = "small Scope", + ["component_scope_medium"] = "medium Scope", + ["component_scope_large"] = "large Scope", + ["component_scope"] = "mounted Scope", + ["component_scope_advanced"] = "advanced Scope", + ["component_ironsights"] = "ironsights", + + ["component_suppressor"] = "suppressor", + ["component_compensator"] = "compensator", + + ["component_muzzle_flat"] = "flat Muzzle Brake", + ["component_muzzle_tactical"] = "tactical Muzzle Brake", + ["component_muzzle_fat"] = "fat-End Muzzle Brake", + ["component_muzzle_precision"] = "precision Muzzle Brake", + ["component_muzzle_heavy"] = "heavy Duty Muzzle Brake", + ["component_muzzle_slanted"] = "slanted Muzzle Brake", + ["component_muzzle_split"] = "split-End Muzzle Brake", + ["component_muzzle_squared"] = "squared Muzzle Brake", + + ["component_flashlight"] = "flashlight", + ["component_grip"] = "grip", + + ["component_barrel_default"] = "default Barrel", + ["component_barrel_heavy"] = "heavy Barrel", + + ["component_ammo_tracer"] = "tracer Ammo", + ["component_ammo_incendiary"] = "incendiary Ammo", + ["component_ammo_hollowpoint"] = "hollowpoint Ammo", + ["component_ammo_fmj"] = "fMJ Ammo", + ["component_ammo_armor"] = "armor Piercing Ammo", + ["component_ammo_explosive"] = "armor Piercing Incendiary Ammo", + + ["component_shells_default"] = "default Shells", + ["component_shells_incendiary"] = "dragons Breath Shells", + ["component_shells_armor"] = "steel Buckshot Shells", + ["component_shells_hollowpoint"] = "flechette Shells", + ["component_shells_explosive"] = "explosive Slug Shells", + + -- Weapon Ammo + ["ammo_rounds"] = "peluru", + ["ammo_shells"] = "peluru", + ["ammo_charge"] = "peluru", + ["ammo_petrol"] = "gallon bahan bakar", + ["ammo_firework"] = "kembang api", + ["ammo_rockets"] = "roket", + ["ammo_grenadelauncher"] = "granat", + ["ammo_grenade"] = "granat", + ["ammo_stickybomb"] = "bom", + ["ammo_pipebomb"] = "bom pipa", + ["ammo_smokebomb"] = "bom asap", + ["ammo_molotov"] = "molotov", + ["ammo_proxmine"] = "peledak", + ["ammo_bzgas"] = "kaleng", + ["ammo_ball"] = "bola", + ["ammo_snowball"] = "bola salju", + ["ammo_flare"] = "flare", + ["ammo_flaregun"] = "flare", + + -- Weapon Tints + ["tint_default"] = "default skin", + ["tint_green"] = "green skin", + ["tint_gold"] = "gold skin", + ["tint_pink"] = "pink skin", + ["tint_army"] = "army skin", + ["tint_lspd"] = "blue skin", + ["tint_orange"] = "orange skin", + ["tint_platinum"] = "platinum skin", + -- MK2 Weapon Tints + ["tint_classic_black"] = "hitam klasik", + ["tint_classic_gray"] = "abu-abu klasik", + ["tint_classic_two_tone"] = "dua warna klasik", + ["tint_classic_white"] = "putih klasik", + ["tint_classic_beige"] = "beige klasik", + ["tint_classic_green"] = "hijau klasik", + ["tint_classic_blue"] = "biru klasik", + ["tint_classic_earth"] = "tanah klasik", + ["tint_classic_brown_black"] = "coklat hitam klasik", + ["tint_contrast_red"] = "merah kontras", + ["tint_contrast_blue"] = "biru kontras", + ["tint_contrast_yellow"] = "kuning kontras", + ["tint_contrast_orange"] = "oren kontras", + ["tint_bold_pink"] = "pink berani", + ["tint_bold_purple_yellow"] = "ungu kuning berani", + ["tint_bold_orange"] = "oren berani", + ["tint_bold_green_purple"] = "hijau ungu berani", + ["tint_bold_red_feat"] = "merah berani feat", + ["tint_bold_green_feat"] = "hijau berani feat", + ["tint_bold_cyan_feat"] = "sian berani feat", + ["tint_bold_yellow_feat"] = "kuning berani feat", + ["tint_bold_red_white"] = "merah putih berani", + ["tint_bold_blue_white"] = "biru putih berani", + ["tint_metallic_gold"] = "emas metalik", + ["tint_metallic_platinum"] = "platina metalik", + ["tint_metallic_gray_lilac"] = "abu-abu lilac metalik", + ["tint_metallic_purple_lime"] = "ungu jeruk nipis metalik", + ["tint_metallic_red"] = "merah metalik", + ["tint_metallic_green"] = "hijau metalik", + ["tint_metallic_blue"] = "biru metalik", + ["tint_metallic_white_aqua"] = "putih aqua metalik", + ["tint_metallic_red_yellow"] = "merah kuning metalik", +} diff --git a/resources/[core]/es_extended/locales/it.lua b/resources/[core]/es_extended/locales/it.lua new file mode 100644 index 0000000..8d09702 --- /dev/null +++ b/resources/[core]/es_extended/locales/it.lua @@ -0,0 +1,415 @@ +return { + -- Inventory + ["inventory"] = "Inventario ( Peso %s / %s )", + ["use"] = "Usa", + ["give"] = "Dai", + ["remove"] = "Butta", + ["return"] = "Ritorna", + ["give_to"] = "Dai a", + ["amount"] = "Quantità", + ["giveammo"] = "Dai munizioni", + ["amountammo"] = "Quantità munizioni", + ["noammo"] = "Non abbastanza!", + ["gave_item"] = "Dando %sx %s a %s", + ["received_item"] = "Ricevuto %sx %s da %s", + ["gave_weapon"] = "Dando %s a %s", + ["gave_weapon_ammo"] = "Dando ~o~%sx %s for %s to %s", + ["gave_weapon_withammo"] = "Dando %s con ~o~%sx %s a %s", + ["gave_weapon_hasalready"] = "%s possiede già %s", + ["gave_weapon_noweapon"] = "%s non ha quell' arma", + ["received_weapon"] = "Ricevuto %s da %s", + ["received_weapon_ammo"] = "Ricevuto ~o~%sx %s per il tuo %s da %s", + ["received_weapon_withammo"] = "Ricevuto %s con ~o~%sx %s per %s", + ["received_weapon_hasalready"] = "%s ha tentato di darti %s, ma hai già l'arma", + ["received_weapon_noweapon"] = "%s ha tentato di darti munizioni per %s, ma non hai l'arma", + ["gave_account_money"] = "Dando $%s (%s) a %s", + ["received_account_money"] = "Ricevuto $%s (%s) da %s", + ["amount_invalid"] = "Quantità non valida", + ["players_nearby"] = "Nessun giocatore vicino", + ["ex_inv_lim"] = "Non puoi farlo, eccedi il peso di %s", + ["imp_invalid_quantity"] = "Non puoi farlo, quantità non valida", + ["imp_invalid_amount"] = "Non puoi farlo, importo non valido", + ["threw_standard"] = "Gettando %sx %s", + ["threw_account"] = "Gettando $%s %s", + ["threw_weapon"] = "Gettando %s", + ["threw_weapon_ammo"] = "Gettando %s con ~o~%sx %s", + ["threw_weapon_already"] = "Hai gia quest' arma", + ["threw_cannot_pickup"] = "Inventario pieno, non puoi raccogliere!", + ["threw_pickup_prompt"] = "Premi E per raccogliere", + + -- Key mapping + ["keymap_showinventory"] = "Apri inventario", + + -- Salary related + ["received_salary"] = "Sei stato pagato: $%s", + ["received_help"] = "Hai ricevuto il reddito di cittadinanza: $%s", + ["company_nomoney"] = "La tua compagnia è troppo povera per pagarti", + ["received_paycheck"] = "Ricveuto stipendio", + ["bank"] = "Banca", + ["account_bank"] = "Conto", + ["account_black_money"] = "Soldi sporchi", + ["account_money"] = "Contanti", + + ["act_imp"] = "Non puoi farlo", + ["in_vehicle"] = "Non puoi farlo, il giocatore è in un veicolo", + ["not_in_vehicle"] = "Non puoi farlo, il player non è in un veicolo", + + -- Commands + ["command_bring"] = "Porta il giocatore da te", + ["command_car"] = "Spawna un veicolo", + ["command_car_car"] = "Modello o hash veicolo", + ["command_cardel"] = "Rimuovi i veicoli nelle prossimità", + ["command_cardel_radius"] = "Rimuovi i veicoli nel raggio specificato", + ["command_repair"] = "Ripara il tuo veicolo", + ["command_repair_success"] = "Hai riparato il veicolo con successo", + ["command_repair_success_target"] = "Un admin ha riparato la tua macchina", + ["command_clear"] = "Pulisci la chat testuale", + ["command_clearall"] = "Pulisci la chat testuale per tutti i giocatori", + ["command_clearinventory"] = "Rimuovi tutti gli oggetti dall' inventario del giocatore", + ["command_clearloadout"] = "Rimuovi tutte le armi dal loadout del giocatore", + ["command_freeze"] = "Blocca un giocatore", + ["command_unfreeze"] = "Sblocca un giocatore", + ["command_giveaccountmoney"] = "Dai soldi a un' account specifico", + ["command_giveaccountmoney_account"] = "Account a cui aggiungere", + ["command_giveaccountmoney_amount"] = "Quantità da aggiungere", + ["command_giveaccountmoney_invalid"] = "Nome account non valido", + ["command_removeaccountmoney"] = "Rimuovi soldi da un account specifico", + ["command_removeaccountmoney_account"] = "Account a cui togliere", + ["command_removeaccountmoney_amount"] = "Quantità da rimuovere", + ["command_removeaccountmoney_invalid"] = "Nome account non valido", + ["command_giveitem"] = "Dai un oggetto ad un giocatore", + ["command_giveitem_item"] = "Nome oggetto", + ["command_giveitem_count"] = "Quantità", + ["command_giveweapon"] = "Dai un' arma ad un giocatore", + ["command_giveweapon_weapon"] = "Nome arma", + ["command_giveweapon_ammo"] = "Quantità munizioni", + ["command_giveweapon_hasalready"] = "Il giocatore ha già l'arma", + ["command_giveweaponcomponent"] = "Dai un componente arma ad un giocatore", + ["command_giveweaponcomponent_component"] = "Nome componente", + ["command_giveweaponcomponent_invalid"] = "Componente arma non valido", + ["command_giveweaponcomponent_hasalready"] = "Il giocatore ha già questo componente arma", + ["command_giveweaponcomponent_missingweapon"] = "Il giocatore non ha l'arma", + ["command_goto"] = "Teletrasportati da un giocatore", + ["command_kill"] = "Uccidi un giocatore", + ["command_save"] = "Salva forzatamente i dati di un giocatore", + ["command_saveall"] = "Salva forzatamente i dati di tutti igiocatoria", + ["command_setaccountmoney"] = "Aggiorna i soldi dentro un account specifico", + ["command_setaccountmoney_amount"] = "Quantità", + ["command_setcoords"] = "Teletrasportati a delle coordinate specifiche", + ["command_setcoords_x"] = "Valore X", + ["command_setcoords_y"] = "Valore Y", + ["command_setcoords_z"] = "Valore Z", + ["command_setjob"] = "Setta lavoro ad un giocatore", + ["command_setjob_job"] = "Nome", + ["command_setjob_grade"] = "Grado lavoro", + ["command_setjob_invalid"] = "Il lavoro, grado o entrambi sono errati", + ["command_setgroup"] = "Setta un gruppo di permessi ad un giocatore", + ["command_setgroup_group"] = "Nome del gruppo", + ["commanderror_argumentmismatch"] = "Conta argomenti non valida (passati %s, richiesti %s)", + ["commanderror_argumentmismatch_number"] = "Argomento #%s di tipologia errata (passato testo, richiesto numero)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (passed number, wanted string)", + ["commanderror_argumentmismatch_positive_number"] = "Argomento #%s tipo di dato non valido (passato negativo/zero, richiesto numero positivo)", + ["commanderror_invaliditem"] = "Oggetto non valido", + ["commanderror_invalidweapon"] = "Arma non valida", + ["commanderror_console"] = "Comando non eseguibile dalla console", + ["commanderror_invalidcommand"] = "Comando non valido - /%s", + ["commanderror_invalidplayerid"] = "Il giocatore specificato non è online", + ["commandgeneric_playerid"] = "Id server del giocatore", + ["command_giveammo_noweapon_found"] = "%s non ha quell' arma", + ["command_giveammo_weapon"] = "Nome arma", + ["command_giveammo_ammo"] = "Quantità munizioni", + ["tpm_nowaypoint"] = "Nessuna meta impostata", + ["tpm_success"] = "Teletrasportato con successo", + + ["noclip_message"] = "Noclip %s", + ["enabled"] = "~g~abilitato~s~", + ["disabled"] = "~r~disabilitato~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "$%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Pugnale Antico", + ["weapon_bat"] = "Mazza", + ["weapon_battleaxe"] = "Ascia", + ["weapon_bottle"] = "Bottiglia", + ["weapon_crowbar"] = "Piede di porco", + ["weapon_flashlight"] = "Torcia", + ["weapon_golfclub"] = "Mazza da golf", + ["weapon_hammer"] = "Martello", + ["weapon_hatchet"] = "Accetta", + ["weapon_knife"] = "Coltello", + ["weapon_knuckle"] = "Tirapugni", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Manganello", + ["weapon_wrench"] = "Tubo", + ["weapon_poolcue"] = "Stecca", + ["weapon_stone_hatchet"] = "Accetta di pietra", + ["weapon_switchblade"] = "Coltello a serramanico", + + -- Handguns + ["weapon_appistol"] = "Pistola AP", + ["weapon_ceramicpistol"] = "Pistola di ceramica", + ["weapon_combatpistol"] = "Pistola da combattimento", + ["weapon_doubleaction"] = "Revolver doppia azione", + ["weapon_navyrevolver"] = "Revolver Marina", + ["weapon_flaregun"] = "Pistola lanciarazzi", + ["weapon_gadgetpistol"] = "Pistola Gadget", + ["weapon_heavypistol"] = "Pistola pesante", + ["weapon_revolver"] = "Revolver pesante", + ["weapon_revolver_mk2"] = "Revolver pesante MK2", + ["weapon_marksmanpistol"] = "Pistola da tiratore", + ["weapon_pistol"] = "Pistola", + ["weapon_pistol_mk2"] = "Pistola MK2", + ["weapon_pistol50"] = "Pistola .50", + ["weapon_snspistol"] = "Pistola SNS", + ["weapon_snspistol_mk2"] = "Pistola SNS MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizzatore", + ["weapon_vintagepistol"] = "Pistola Vintage", + + -- Shotguns + ["weapon_assaultshotgun"] = "Fucile a pompa d'assalto", + ["weapon_autoshotgun"] = "Fucile a pompa automatico", + ["weapon_bullpupshotgun"] = "Fucile a pompa Bullup", + ["weapon_combatshotgun"] = "Fucile a pompa da combattimento", + ["weapon_dbshotgun"] = "Fucile a pompa doppia canna", + ["weapon_heavyshotgun"] = "Fucile a pompa pesante", + ["weapon_musket"] = "Moschetto", + ["weapon_pumpshotgun"] = "Fucile a pompa", + ["weapon_pumpshotgun_mk2"] = "Fucile a pompa MK2", + ["weapon_sawnoffshotgun"] = "Fucile a canne mozza", + + -- SMG & LMG + ["weapon_assaultsmg"] = "SMG d'assalto", + ["weapon_combatmg"] = "MG da combattimento", + ["weapon_combatmg_mk2"] = "MG da combattimento MK2", + ["weapon_combatpdw"] = "PDW da combattimento", + ["weapon_gusenberg"] = "Mitragliatrice Gusenberg", + ["weapon_machinepistol"] = "Pistola mitragliatrice", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Hellbringer infernale", + + -- Rifles + ["weapon_advancedrifle"] = "Fucile avanzato", + ["weapon_assaultrifle"] = "Fucile d'assalto", + ["weapon_assaultrifle_mk2"] = "Fucile d' assalto MK2", + ["weapon_bullpuprifle"] = "Fucile Bullpup", + ["weapon_bullpuprifle_mk2"] = "Fucile Bullpup MK2", + ["weapon_carbinerifle"] = "Carabina", + ["weapon_carbinerifle_mk2"] = "Carbine MK2", + ["weapon_compactrifle"] = "Fucile compatto", + ["weapon_militaryrifle"] = "Fucile militare", + ["weapon_specialcarbine"] = "Carabina speciale", + ["weapon_specialcarbine_mk2"] = "Carabina speciale MK2", + ["weapon_heavyrifle"] = "Fucile pesante", + + -- Sniper + ["weapon_heavysniper"] = "Cecchino pesante", + ["weapon_heavysniper_mk2"] = "Cecchino pesante MK2", + ["weapon_marksmanrifle"] = "Fucile da tiratore", + ["weapon_marksmanrifle_mk2"] = "Fucile da tiratore MK2", + ["weapon_sniperrifle"] = "Cecchino", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Lanciagranate compatto", + ["weapon_firework"] = "Cannone pirotecnico", + ["weapon_grenadelauncher"] = "Lanciagranate", + ["weapon_hominglauncher"] = "Lanciarazzi a tracciamento", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Lanciarazzi", + ["weapon_rayminigun"] = "Widowmaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Metal Detector", + ["weapon_precisionrifle"] = "Fucile di precisione", + ["weapon_tactilerifle"] = "Carabina di servizio", + + -- Drug Wars DLC + ["weapon_candycane"] = "Bastoncino di zucchero", + ["weapon_acidpackage"] = "Pacco di acidi", + ["weapon_pistolxm3"] = "Pistola WM 29", + ["weapon_railgunxm3"] = "Railgun", + + -- Thrown + ["weapon_ball"] = "Palla", + ["weapon_bzgas"] = "BZ Gas", + ["weapon_flare"] = "Flare", + ["weapon_grenade"] = "Granata", + ["weapon_petrolcan"] = "Tanica", + ["weapon_hazardcan"] = "Tanica pericolosa", + ["weapon_molotov"] = "Molotov", + ["weapon_proxmine"] = "Mina di prossimità", + ["weapon_pipebomb"] = "Esplosivo plastico", + ["weapon_snowball"] = "Palla di neve", + ["weapon_stickybomb"] = "Bomba adesiva", + ["weapon_smokegrenade"] = "Gas lacrimogeno", + + -- Special + ["weapon_fireextinguisher"] = "Estintore", + ["weapon_digiscanner"] = "Scanner digitale", + ["weapon_garbagebag"] = "Sacco della spazzatura", + ["weapon_handcuffs"] = "Manette", + ["gadget_nightvision"] = "Visore termico", + ["gadget_parachute"] = "Paracadute", + + -- Weapon Components + ["component_knuckle_base"] = "Modello basa", + ["component_knuckle_pimp"] = "il Pappone", + ["component_knuckle_ballas"] = "i Ballas", + ["component_knuckle_dollar"] = "il Riccone", + ["component_knuckle_diamond"] = "la Roccia", + ["component_knuckle_hate"] = "l' Hater", + ["component_knuckle_love"] = "l' Amante", + ["component_knuckle_player"] = "il Giocatore", + ["component_knuckle_king"] = "il Re", + ["component_knuckle_vagos"] = "i Vagos", + + ["component_luxary_finish"] = "rifinitura di lusso", + + ["component_handle_default"] = "impugnatura base", + ["component_handle_vip"] = "impugnatura VIP", + ["component_handle_bodyguard"] = "impugnatura guardia del corpo", + + ["component_vip_finish"] = "rifinitura VIP", + ["component_bodyguard_finish"] = "rifinitura Guardia del corpo", + + ["component_camo_finish"] = "mimetica Digitale", + ["component_camo_finish2"] = "mimetica Cespuglio", + ["component_camo_finish3"] = "mimetica Legnosa", + ["component_camo_finish4"] = "mimetica Teschio", + ["component_camo_finish5"] = "mimetica Sessanta Nove", + ["component_camo_finish6"] = "mimetica Perseo", + ["component_camo_finish7"] = "mimetica Leopardata", + ["component_camo_finish8"] = "mimetica Zebra", + ["component_camo_finish9"] = "mimetica Geometrica", + ["component_camo_finish10"] = "mimetica Boom", + ["component_camo_finish11"] = "mimetica Patriottica", + + ["component_camo_slide_finish"] = "mimetica Digitale Slide", + ["component_camo_slide_finish2"] = "mimetica Cespuglio Slide", + ["component_camo_slide_finish3"] = "mimetica Legnosa Slide", + ["component_camo_slide_finish4"] = "mimetica Teschio Slide", + ["component_camo_slide_finish5"] = "mimetica Sessanta Nove Slide", + ["component_camo_slide_finish6"] = "mimetica Perseo Slide", + ["component_camo_slide_finish7"] = "mimetica Leopardata Slide", + ["component_camo_slide_finish8"] = "mimetica Zebra Slide", + ["component_camo_slide_finish9"] = "mimetica Geometrica Slide", + ["component_camo_slide_finish10"] = "mimetica Boom Slide", + ["component_camo_slide_finish11"] = "mimetica Patriottica Slide", + + ["component_clip_default"] = "caricatore Standard", + ["component_clip_extended"] = "caricatore Esteso", + ["component_clip_drum"] = "caricatore A Batteria", + ["component_clip_box"] = "caricatore A Scatola", + + ["component_scope_holo"] = "mirino Olografico", + ["component_scope_small"] = "mirino Piccolo", + ["component_scope_medium"] = "mirino Medio", + ["component_scope_large"] = "mirino Largo", + ["component_scope"] = "mirino Montato", + ["component_scope_advanced"] = "mirino Avanzato", + ["component_ironsights"] = "integrato", + + ["component_suppressor"] = "silenziatore", + ["component_compensator"] = "compensatore", + + ["component_muzzle_flat"] = "freno Di Bocca Piatto", + ["component_muzzle_tactical"] = "freno Di Bocca Tattico", + ["component_muzzle_fat"] = "freno Di Bocca Grosso", + ["component_muzzle_precision"] = "freno Di Bocca Di Precisione", + ["component_muzzle_heavy"] = "freno Di Bocca Pesante", + ["component_muzzle_slanted"] = "freno Di Bocca Inclinato", + ["component_muzzle_split"] = "freno Di Bocca Diviso", + ["component_muzzle_squared"] = "freno Di Bocca Quadrato", + + ["component_flashlight"] = "torcia", + ["component_grip"] = "impugnatura", + + ["component_barrel_default"] = "canna Standard", + ["component_barrel_heavy"] = "canna Pesante", + + ["component_ammo_tracer"] = "munizioni Traccianti", + ["component_ammo_incendiary"] = "munizioni Incendiarie", + ["component_ammo_hollowpoint"] = "munizioni a Punta Cava", + ["component_ammo_fmj"] = "munizioni fMj", + ["component_ammo_armor"] = "munizioni penetranti", + ["component_ammo_explosive"] = "munizioni penetranti incendiarie", + + ["component_shells_default"] = "cartucce Standard", + ["component_shells_incendiary"] = "cartucce alito di Drago", + ["component_shells_armor"] = "cartucce a pallettoni", + ["component_shells_hollowpoint"] = "cartucce a freccette", + ["component_shells_explosive"] = "cartucce esplosive", + + -- Weapon Ammo + ["ammo_rounds"] = "colpo(i)", + ["ammo_shells"] = "cartuccia(e)", + ["ammo_charge"] = "carica", + ["ammo_petrol"] = "Litri di carburante", + ["ammo_firework"] = "fuochi d'artificio", + ["ammo_rockets"] = "razzo(i)", + ["ammo_grenadelauncher"] = "granata(e)", + ["ammo_grenade"] = "granata(e)", + ["ammo_stickybomb"] = "bomba(e)", + ["ammo_pipebomb"] = "bomba(e)", + ["ammo_smokebomb"] = "bomba(e)", + ["ammo_molotov"] = "bottiglia(e)", + ["ammo_proxmine"] = "mina(e)", + ["ammo_bzgas"] = "latta(e)", + ["ammo_ball"] = "palla(e)", + ["ammo_snowball"] = "palle di neve", + ["ammo_flare"] = "razzo(i)", + ["ammo_flaregun"] = "razzo(i)", + + -- Weapon Tints + ["tint_default"] = "Colore standard", + ["tint_green"] = "color verde", + ["tint_gold"] = "color oro", + ["tint_pink"] = "color rosa", + ["tint_army"] = "color army", + ["tint_lspd"] = "color blu", + ["tint_orange"] = "color arancio", + ["tint_platinum"] = "color platino", + -- MK2 Weapon Tints + ["tint_classic_black"] = "nero classico", + ["tint_classic_gray"] = "grigio classico", + ["tint_classic_two_tone"] = "due toni classico", + ["tint_classic_white"] = "bianco classico", + ["tint_classic_beige"] = "beige classico", + ["tint_classic_green"] = "verde classico", + ["tint_classic_blue"] = "blu classico", + ["tint_classic_earth"] = "terra classica", + ["tint_classic_brown_black"] = "marrone nero classico", + ["tint_contrast_red"] = "rosso contrastante", + ["tint_contrast_blue"] = "blu contrastante", + ["tint_contrast_yellow"] = "giallo contrastante", + ["tint_contrast_orange"] = "arancione contrastante", + ["tint_bold_pink"] = "rosa audace", + ["tint_bold_purple_yellow"] = "viola giallo audace", + ["tint_bold_orange"] = "arancione audace", + ["tint_bold_green_purple"] = "verde viola audace", + ["tint_bold_red_feat"] = "rosso audace feat", + ["tint_bold_green_feat"] = "verde audace feat", + ["tint_bold_cyan_feat"] = "cyan audace feat", + ["tint_bold_yellow_feat"] = "giallo audace feat", + ["tint_bold_red_white"] = "rosso bianco audace", + ["tint_bold_blue_white"] = "blu bianco audace", + ["tint_metallic_gold"] = "oro metallico", + ["tint_metallic_platinum"] = "platino metallico", + ["tint_metallic_gray_lilac"] = "grigio lilla metallico", + ["tint_metallic_purple_lime"] = "viola lime metallico", + ["tint_metallic_red"] = "rosso metallico", + ["tint_metallic_green"] = "verde metallico", + ["tint_metallic_blue"] = "blu metallico", + ["tint_metallic_white_aqua"] = "bianco aqua metallico", + ["tint_metallic_red_yellow"] = "rosso giallo metallico", +} diff --git a/resources/[core]/es_extended/locales/nl.lua b/resources/[core]/es_extended/locales/nl.lua new file mode 100644 index 0000000..03daad4 --- /dev/null +++ b/resources/[core]/es_extended/locales/nl.lua @@ -0,0 +1,406 @@ +return { + -- Inventory + ["inventory"] = "Inventaris ( Gewicht %s / %s )", + ["use"] = "Gebruik", + ["give"] = "Geef", + ["remove"] = "Gooi", + ["return"] = "Terug", + ["give_to"] = "Geef aan", + ["amount"] = "Aantal", + ["giveammo"] = "Geef munitie", + ["amountammo"] = "Hoeveelheid munitie", + ["noammo"] = "Niet genoeg munitie!", + ["gave_item"] = "%sx %s gegeven aan %s", + ["received_item"] = "%sx %s ontvangen van %s", + ["gave_weapon"] = "%s gegeven aan %s", + ["gave_weapon_ammo"] = "~o~%sx %s gegeven voor een %s aan %s", + ["gave_weapon_withammo"] = "%s gegeven met ~o~%sx %s aan %s", + ["gave_weapon_hasalready"] = "%s heeft al een %s", + ["gave_weapon_noweapon"] = "%s heeft dat wapen niet", + ["received_weapon"] = "%s ontvangen van %s", + ["received_weapon_ammo"] = "~o~%sx %s ontvangen voor je %s van %s", + ["received_weapon_withammo"] = "%s ontvangen met ~o~%sx %s van %s", + ["received_weapon_hasalready"] = "%s heeft geprobeerd je een %s te geven, maar je hebt dat wapen al.", + ["received_weapon_noweapon"] = "%s heeft geprobeerd je ammo te geven voor een %s, maar je hebt dit wapen niet", + ["gave_account_money"] = "€%s (%s) gegeven aan %s", + ["received_account_money"] = "€%s (%s) ontvangen van %s", + ["amount_invalid"] = "Ongeldige hoeveelheid", + ["players_nearby"] = "Geen spelers in de buurt", + ["ex_inv_lim"] = "Kan actie niet uitvoeren, overschrijdt max. gewicht van %s", + ["imp_invalid_quantity"] = "Kan actie niet uitvoeren, de hoeveelheid is ongeldig", + ["imp_invalid_amount"] = "Kan actie niet uitvoeren, het aantal is ongeldig", + ["threw_standard"] = "%sx %s weggegooid", + ["threw_account"] = "€%s %s weggegooid", + ["threw_weapon"] = "%s weggegooid", + ["threw_weapon_ammo"] = "%s met ~o~%sx %s weggegooid", + ["threw_weapon_already"] = "Je hebt dit wapen al !", + ["threw_cannot_pickup"] = "Inventaris is vol, je kan dit niet oppakken!", + ["threw_pickup_prompt"] = "Druk op E om op te pakken", + + -- Key mapping + ["keymap_showinventory"] = "Laat inventaris zien", + + -- Salary related + ["received_salary"] = "Je bent betaald: €%s", + ["received_help"] = "Je hebt je uitkering gekregen: €%s", + ["company_nomoney"] = "Het bedrijf waar je bij werkt heeft te weinig geld om je uit te betalen.", + ["received_paycheck"] = "salaris ontvangen", + ["bank"] = "Maze Bank", + ["account_bank"] = "Bank", + ["account_black_money"] = "Zwart geld", + ["account_money"] = "Contant", + + ["act_imp"] = "Kan actie niet uitvoeren", + ["in_vehicle"] = "Kan actie niet uitvoeren, de speler zit in een voertuig.", + + -- Commands + ["command_bring"] = "Breng speler naar jou", + ["command_car"] = "Spawn een voertuig", + ["command_car_car"] = "Voertuig model of hash", + ["command_cardel"] = "Verwijder voertuigen in straal", + ["command_cardel_radius"] = "Verwijderd alle voertuigen in gewenste straal", + ["command_clear"] = "Verwijder chat berichten", + ["command_clearall"] = "Verwijder chat berichten voor alle spelers", + ["command_clearinventory"] = "Verwijder alle items van een speler zijn inventory", + ["command_clearloadout"] = "Verwijder alle wapens die een speler heeft", + ["command_freeze"] = "Freeze een speler", + ["command_unfreeze"] = "Unfreeze een speler", + ["command_giveaccountmoney"] = "Geef geld aan een rekening", + ["command_giveaccountmoney_account"] = "Account om aan toe te voegen", + ["command_giveaccountmoney_amount"] = "Bedrag om toe te voegen", + ["command_giveaccountmoney_invalid"] = "Account Naam ongeldig", + ["command_giveitem"] = "Geef speler een item", + ["command_giveitem_item"] = "Item naam", + ["command_giveitem_count"] = "Hoeveelheid", + ["command_giveweapon"] = "Geef de speler een wapen", + ["command_giveweapon_weapon"] = "Wapen naam", + ["command_giveweapon_ammo"] = "Munitie Hoeveelheid", + ["command_giveweapon_hasalready"] = "Speler heeft dit wapen al", + ["command_giveweaponcomponent"] = "Geef wapen component aan speler", + ["command_giveweaponcomponent_component"] = "Component naam", + ["command_giveweaponcomponent_invalid"] = "Ongeldig wapen component", + ["command_giveweaponcomponent_hasalready"] = "De speler heeft dit wapen component al", + ["command_giveweaponcomponent_missingweapon"] = "De speler heeft dit wapen niet", + ["command_goto"] = "Teleporteer jezelf naar een speler", + ["command_kill"] = "Vermoord een speler", + ["command_save"] = "Slaag een speler zijn spelerdata geforceerd op", + ["command_saveall"] = "Slaag iedereen zijn spelerdata geforceerd op", + ["command_setaccountmoney"] = "Stel geld in op een account", + ["command_setaccountmoney_amount"] = "Hoeveelheid", + ["command_setcoords"] = "Telepeer naar coordinaten", + ["command_setcoords_x"] = "X waarde", + ["command_setcoords_y"] = "Y waarde", + ["command_setcoords_z"] = "Z waarde", + ["command_setjob"] = "Zet een speler zijn / haar job", + ["command_setjob_job"] = "Naam", + ["command_setjob_grade"] = "Job grade", + ["command_setjob_invalid"] = "De job, grade of beide zijn ongeldig", + ["command_setgroup"] = "Stel een toestemmingsgroep voor spelers in", + ["command_setgroup_group"] = "Naam van groep", + ["commanderror_argumentmismatch"] = "Ongeldig aantal argumenten (geslaagd %s, gezocht %s)", + ["commanderror_argumentmismatch_number"] = "Ongeldig argument #%s gegevenstype (doorgegeven string, gewenst nummer)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (doorgegeven string, gewenst nummer)", + ["commanderror_argumentmismatch_positive_number"] = "Ongeldig Argument #%s gegevenstype (doorgegeven negatief/nul, gewenst positief getal)", + ["commanderror_invaliditem"] = "Ongeldig item", + ["commanderror_invalidweapon"] = "Ongeldig wapen", + ["commanderror_console"] = "Command kan niet worden uitgevoerd vanaf console.", + ["commanderror_invalidcommand"] = "Ongeldig commando - /%s", + ["commanderror_invalidplayerid"] = "Opgegeven speler is niet online", + ["commandgeneric_playerid"] = "Speler server id", + ["command_giveammo_noweapon_found"] = "%s heeft dat wapen niet", + ["command_giveammo_weapon"] = "Wapen naam", + ["command_giveammo_ammo"] = "Munitie Hoeveelheid", + ["tpm_nowaypoint"] = "Geen navigatie ingesteld.", + ["tpm_success"] = "Successvol geteleporteerd", + + ["noclip_message"] = "Noclip is %s", + ["enabled"] = "~g~aangezet~s~", + ["disabled"] = "~r~uitgezet~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "€%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dolk", + ["weapon_bat"] = "Knuppel", + ["weapon_battleaxe"] = "Gevechtsbijl", + ["weapon_bottle"] = "Fles", + ["weapon_crowbar"] = "Koevoet", + ["weapon_flashlight"] = "Zaklamp", + ["weapon_golfclub"] = "Golfclub", + ["weapon_hammer"] = "Hamer", + ["weapon_hatchet"] = "Bijl", + ["weapon_knife"] = "Mes", + ["weapon_knuckle"] = "Boksbeugel", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Wapenstok", + ["weapon_wrench"] = "Pijpsleutel", + ["weapon_poolcue"] = "Biljart Keu", + ["weapon_stone_hatchet"] = "Steenbijl", + ["weapon_switchblade"] = "Stiletto", + + -- Handguns + ["weapon_appistol"] = "AP-pistool", + ["weapon_ceramicpistol"] = "Keramische pistool", + ["weapon_combatpistol"] = "Gevechtspistool", + ["weapon_doubleaction"] = "Revolver met dubbele actie", + ["weapon_navyrevolver"] = "Marine Revolver", + ["weapon_flaregun"] = "Noodsignaalpistool", + ["weapon_gadgetpistol"] = "Gadgetpistool", + ["weapon_heavypistol"] = "Zwaar pistool", + ["weapon_revolver"] = "Zware revolver", + ["weapon_revolver_mk2"] = "Zware revolver MK2", + ["weapon_marksmanpistol"] = "Marksman-pistool", + ["weapon_pistol"] = "Pistool", + ["weapon_pistol_mk2"] = "Pistool MK2", + ["weapon_pistol50"] = "Pistool .50", + ["weapon_snspistol"] = "SNS-pistool", + ["weapon_snspistol_mk2"] = "SNS-pistool MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Vintage Pistool", + + -- Shotguns + ["weapon_assaultshotgun"] = "Aanvalsgeweer", + ["weapon_autoshotgun"] = "Automatisch jachtgeweer", + ["weapon_bullpupshotgun"] = "Bullpup Shotgun", + ["weapon_combatshotgun"] = "Gevechtsgeweer", + ["weapon_dbshotgun"] = "Dubbelloops jachtgeweer", + ["weapon_heavyshotgun"] = "Zwaar jachtgeweer", + ["weapon_musket"] = "Musket", + ["weapon_pumpshotgun"] = "Pompgeweer", + ["weapon_pumpshotgun_mk2"] = "Pump Shotgun MK2", + ["weapon_sawnoffshotgun"] = "Afgezaagd jachtgeweer", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Aanval SMG", + ["weapon_combatmg"] = "Gevecht MG", + ["weapon_combatmg_mk2"] = "Combat MG MK2", + ["weapon_combatpdw"] = "Combat PDW", + ["weapon_gusenberg"] = "Gusenberg-veger", + ["weapon_machinepistol"] = "Machinepistool", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro-SMG", + ["weapon_minismg"] = "Mini-SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Onheilige Hellbringer", + + -- Rifles + ["weapon_advancedrifle"] = "Geavanceerd geweer", + ["weapon_assaultrifle"] = "Aanvalsgeweer", + ["weapon_assaultrifle_mk2"] = "Aanvalsgeweer MK2", + ["weapon_bullpuprifle"] = "Bullpup-geweer", + ["weapon_bullpuprifle_mk2"] = "Bullpup-geweer MK2", + ["weapon_carbinerifle"] = "Kabinet geweer", + ["weapon_carbinerifle_mk2"] = "Kabinet geweer MK2", + ["weapon_compactrifle"] = "Compact geweer", + ["weapon_militaryrifle"] = "Militair geweer", + ["weapon_specialcarbine"] = "Speciale karabijn", + ["weapon_specialcarbine_mk2"] = "Speciale karabijn MK2", + + -- Sniper + ["weapon_heavysniper"] = "Zware sluipschutter", + ["weapon_heavysniper_mk2"] = "Zware Sniper MK2", + ["weapon_marksmanrifle"] = "Schuttersgeweer", + ["weapon_marksmanrifle_mk2"] = "Schuttersgeweer MK2", + ["weapon_sniperrifle"] = "Sniper Rifle", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Compacte Launcher", + ["weapon_firework"] = "Vuurwerkstarter", + ["weapon_grenadelauncher"] = "Granaatwerper", + ["weapon_hominglauncher"] = "Homing Launcher", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Spoorgeweer", + ["weapon_rpg"] = "Raketwerper", + ["weapon_rayminigun"] = "Weduwemaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Metaal Detector", + ["weapon_precisionrifle"] = "Precisiegeweer", + ["weapon_tactilerifle"] = "Service Carbine", + + -- Drug Wars DLC + ["weapon_candycane"] = "Snoep stok", + ["weapon_acidpackage"] = "LSD pakket", + ["weapon_pistolxm3"] = "WM 29 Pistool", + ["weapon_railgunxm3"] = "Railgun", + + -- Thrown + ["weapon_ball"] = "Honkbal", + ["weapon_bzgas"] = "BZ-gas", + ["weapon_flare"] = "Flare", + ["weapon_grenade"] = "Granaat", + ["weapon_petrolcan"] = "Jerrycan", + ["weapon_hazardcan"] = "Gevaarlijke jerrycan", + ["weapon_molotov"] = "Molotovcocktail", + ["weapon_proxmine"] = "Nabijheidsmijn", + ["weapon_pipebomb"] = "Pijpbom", + ["weapon_snowball"] = "Sneeuwbal", + ["weapon_stickybomb"] = "Kleefbom", + ["weapon_smokegrenade"] = "Traangas", + + -- Special + ["weapon_firebluser"] = "Brandblusser", + ["weapon_digiscanner"] = "Digitale scanner", + ["weapon_garbagebag"] = "Vuilniszak", + ["weapon_handcuffs"] = "Handboeien", + ["gadget_nightvision"] = "Nachtzicht", + ["gadget_parachute"] = "parachute", + + -- Weapon Components + ["component_knuckle_base"] = "basismodel", + ["component_knuckle_pimp"] = "de pooier", + ["component_knuckle_ballas"] = "de ballen", + ["component_knuckle_dollar"] = "de Hustler", + ["component_knuckle_diamond"] = "de rots", + ["component_knuckle_hate"] = "de Hater", + ["component_knuckle_love"] = "de minnaar", + ["component_knuckle_player"] = "de speler", + ["component_knuckle_king"] = "de koning", + ["component_knuckle_vagos"] = "de Vagos", + + ["component_luxary_finish"] = "luxe wapenafwerking", + + ["component_handle_default"] = "standaard handvat", + ["component_handle_vip"] = "VIP-handvat", + ["component_handle_bodyguard"] = "bodyguard-handvat", + + ["component_vip_finish"] = "VIP Finish", + ["component_bodyguard_finish"] = "bodyguard Finish", + + ["component_camo_finish"] = "digitale camouflage", + ["component_camo_finish2"] = "penseelstreek camouflage", + ["component_camo_finish3"] = "bos camouflage", + ["component_camo_finish4"] = "schedel camouflage", + ["component_camo_finish5"] = "sessanta Nove camouflage", + ["component_camo_finish6"] = "perseus camouflage", + ["component_camo_finish7"] = "luipaard camouflage", + ["component_camo_finish8"] = "zebracamouflage", + ["component_camo_finish9"] = "geometrische camouflage", + ["component_camo_finish10"] = "boom camouflage", + ["component_camo_finish11"] = "patriottische camouflage", + + ["component_camo_slide_finish"] = "digitale diacamouflage", + ["component_camo_slide_finish2"] = "penseelstreek Dia Camo", + ["component_camo_slide_finish3"] = "bos Slide camouflage", + ["component_camo_slide_finish4"] = "schedelschuifcamouflage", + ["component_camo_slide_finish5"] = "sessanta Nove Dia camouflage", + ["component_camo_slide_finish6"] = "perseus diacamouflage", + ["component_camo_slide_finish7"] = "luipaard Slide camouflage", + ["component_camo_slide_finish8"] = "zebra Slide camouflage", + ["component_camo_slide_finish9"] = "geometrische diacamouflage", + ["component_camo_slide_finish10"] = "boom Slide camouflage", + ["component_camo_slide_finish11"] = "patriottische diacamouflage", + + ["component_clip_default"] = "standaard magazijn", + ["component_clip_extended"] = "uitgebreid magazijn", + ["component_clip_drum"] = "drum magazijn", + ["component_clip_box"] = "box magazijn", + + ["component_scope_holo"] = "holografisch bereik", + ["component_scope_small"] = "klein bereik", + ["component_scope_medium"] = "gemiddeld bereik", + ["component_scope_large"] = "groot bereik", + ["component_scope"] = "gemonteerde scope", + ["component_scope_advanced"] = "geavanceerd bereik", + ["component_ironsights"] = "ironsights", + + ["component_suppressor"] = "suppressor", + ["component_compensator"] = "compensator", + + ["component_muzzle_flat"] = "platte mondingsrem", + ["component_muzzle_tactical"] = "tactische mondingsrem", + ["component_muzzle_fat"] = "fat-end mondingsrem", + ["component_muzzle_precision"] = "precisie mondingsrem", + ["component_muzzle_heavy"] = "zware mondingsrem", + ["component_muzzle_slanted"] = "schuine mondingsrem", + ["component_muzzle_split"] = "gespleten mondingsrem", + ["component_muzzle_squared"] = "kwadraat mondingsrem", + + ["component_flashlight"] = "zaklamp", + ["component_grip"] = "grip", + + ["component_barrel_default"] = "standaard handvat", + ["component_barrel_heavy"] = "zware handvat", + + ["component_ammo_tracer"] = "tracermunitie", + ["component_ammo_incendiary"] = "brandgevaarlijke munitie", + ["component_ammo_hollowpoint"] = "hollowpoint munitie", + ["component_ammo_fmj"] = "fMJ-munitie", + ["component_ammo_armor"] = "pantser piercing munitie", + ["component_ammo_explosive"] = "pantserpiercing brandgevaarlijke munitie", + + ["component_shells_default"] = "standaard shells", + ["component_shells_incendiary"] = "draken ademschelpen", + ["component_shells_armor"] = "stalen Buckshot Shells", + ["component_shells_hollowpoint"] = "flechette schelpen", + ["component_shells_explosive"] = "explosieve slakkenhuizen", + + -- Weapon Ammo + ["ammo_rounds"] = "ronde(n)", + ["ammo_shells"] = "huls/(zen)", + ["ammo_charge"] = "charge", + ["ammo_petrol"] = "liters brandstof", + ["ammo_firework"] = "vuurwerkpijl(en)", + ["ammo_rockets"] = "raket(ten)", + ["ammo_grenadelauncher"] = "granaat(en)", + ["ammo_grenade"] = "granaat(en)", + ["ammo_stickybomb"] = "bom(men)", + ["ammo_pipebomb"] = "bom(men)", + ["ammo_smokebomb"] = "bom(men)", + ["ammo_molotov"] = "cocktail(s)", + ["ammo_proxmine"] = "mijn(en)", + ["ammo_bzgas"] = "blik(ken)", + ["ammo_ball"] = "bal(len)", + ["ammo_snowball"] = "sneeuwbal(len)", + ["ammo_flare"] = "flare(s)", + ["ammo_flaregun"] = "flare(s)", + + -- Weapon Tints + ["tint_default"] = "standaard skin", + ["tint_green"] = "groene skin", + ["tint_gold"] = "goude skin", + ["tint_pink"] = "roze skin", + ["tint_army"] = "legerprint", + ["tint_lspd"] = "blauwe skin", + ["tint_orange"] = "oranje skin", + ["tint_platinum"] = "platina skin", + -- MK2 Weapon Tints + ["tint_classic_black"] = "klassiek zwart", + ["tint_classic_gray"] = "klassiek grijs", + ["tint_classic_two_tone"] = "klassiek twee-tonig", + ["tint_classic_white"] = "klassiek wit", + ["tint_classic_beige"] = "klassiek beige", + ["tint_classic_green"] = "klassiek groen", + ["tint_classic_blue"] = "klassiek blauw", + ["tint_classic_earth"] = "klassieke aarde", + ["tint_classic_brown_black"] = "klassiek bruin zwart", + ["tint_contrast_red"] = "contrast rood", + ["tint_contrast_blue"] = "contrast blauw", + ["tint_contrast_yellow"] = "contrast geel", + ["tint_contrast_orange"] = "contrast oranje", + ["tint_bold_pink"] = "gedurfde roze", + ["tint_bold_purple_yellow"] = "gedurfde paarse geel", + ["tint_bold_orange"] = "gedurfde oranje", + ["tint_bold_green_purple"] = "gedurfde groene paarse", + ["tint_bold_red_feat"] = "gedurfde rode feat", + ["tint_bold_green_feat"] = "gedurfde groene feat", + ["tint_bold_cyan_feat"] = "gedurfde cyaan feat", + ["tint_bold_yellow_feat"] = "gedurfde gele feat", + ["tint_bold_red_white"] = "gedurfde rode witte", + ["tint_bold_blue_white"] = "gedurfde blauwe witte", + ["tint_metallic_gold"] = "metallisch goud", + ["tint_metallic_platinum"] = "metallisch platina", + ["tint_metallic_gray_lilac"] = "metallisch grijs lila", + ["tint_metallic_purple_lime"] = "metallisch paarse limo", + ["tint_metallic_red"] = "metallisch rood", + ["tint_metallic_green"] = "metallisch groen", + ["tint_metallic_blue"] = "metallisch blauw", + ["tint_metallic_white_aqua"] = "metallisch wit aqua", + ["tint_metallic_red_yellow"] = "metallisch rood geel", +} diff --git a/resources/[core]/es_extended/locales/pl.lua b/resources/[core]/es_extended/locales/pl.lua new file mode 100644 index 0000000..e0ec460 --- /dev/null +++ b/resources/[core]/es_extended/locales/pl.lua @@ -0,0 +1,273 @@ +return { + -- Inventory + ["inventory"] = "ekwipunek %s / %s", + ["use"] = "użyj", + ["give"] = "daj", + ["remove"] = "usuń", + ["return"] = "wróć", + ["give_to"] = "daj dla", + ["amount"] = "ilość", + ["giveammo"] = "daj amunicje", + ["amountammo"] = "ilość amunicji", + ["noammo"] = "nie posiadasz wystarczającej ilości amunicji!", + ["gave_item"] = "dałeś/aś %sx %s dla %s", + ["received_item"] = "otrzymałeś/aś %sx %s od %s", + ["gave_weapon"] = "dałeś/aś %s dla %s", + ["gave_weapon_ammo"] = "dałeś/aś ~o~%sx %s do %s dla %s", + ["gave_weapon_withammo"] = "dałeś/aś %s z ~o~%sx %s dla %s", + ["gave_weapon_hasalready"] = "%s już posiada %s", + ["gave_weapon_noweapon"] = "%s nie posiada tej broni", + ["received_weapon"] = "otrzymałeś/aś %s od %s", + ["received_weapon_ammo"] = "otrzymałeś/aś ~o~%sx %s do twojego %s od %s", + ["received_weapon_withammo"] = "otrzymałeś/aś %s z ~o~%sx %s od %s", + ["received_weapon_hasalready"] = "%s próbował/a przekazać ci %s, lecz już posiadasz jedno", + ["received_weapon_noweapon"] = "%s próbował/a przekazać ci amunicje do %s, lecz nie posiadasz tej broni", + ["gave_account_money"] = "dałeś/aś %s$ (%s) dla %s", + ["received_account_money"] = "otrzymałeś/aś %s$ (%s) od %s", + ["amount_invalid"] = "nieprawidłowa ilość", + ["players_nearby"] = "brak graczy w pobliżu", + ["ex_inv_lim"] = "akcja nie jest możliwa, nie możesz mieć więcej %s", + ["imp_invalid_quantity"] = "akcja jest niemożliwa, nieprawidłowa ilość", + ["imp_invalid_amount"] = "akcja jest niemożliwa, nieprawidłowa kwota", + ["threw_standard"] = "wyrzuciłeś/aś %sx %s", + ["threw_account"] = "wyrzuciłeś/aś $%s %s", + ["threw_weapon"] = "wyrzuciłeś/aś %s", + ["threw_weapon_ammo"] = "wyrzuciłeś/aś %s z ~o~%sx %s", + ["threw_weapon_already"] = "już posiadasz taką samą broń", + ["threw_cannot_pickup"] = "nie możesz tego podnieść, gdyż masz pełny ekwipunek!", + ["threw_pickup_prompt"] = "naciśnij E aby podnieść", + + -- Key mapping + ["keymap_showinventory"] = "pokaż ekwipunek", + + -- Salary related + ["received_salary"] = "otrzymałeś/aś wynagrodzenie: %s$", + ["received_help"] = "otrzymałeś/aś zapomogę: $%s", + ["company_nomoney"] = "firma, w której pracujesz, jest zbyt biedna, by wypłacić twoją pensję", + ["received_paycheck"] = "otrzymano wypłate", + ["bank"] = "bank", + ["account_bank"] = "bank", + ["account_black_money"] = "brudne pieniądze", + ["account_money"] = "pieniądze", + ["act_imp"] = "działanie niemożliwe", + ["in_vehicle"] = "nie możesz przekazywać przedmiotów w pojeździe", + ["not_in_vehicle"] = "Cannot Perform Action, Player isn't in a vehicle", + + -- Commands + ["command_car"] = "przywołaj pojazd", + ["command_car_car"] = "nazwa lub hash przywołanego pojazdu", + ["command_cardel"] = "usuń pojazd w pobliżu", + ["command_cardel_radius"] = "opcjonalnie usuń każdy pojazd w obszarze", + ["command_repair"] = "Repair your vehicle", + ["command_repair_success"] = "Successfully repaired vehicle", + ["command_repair_success_target"] = "An admin repaired your vehicle", + ["command_clear"] = "wyczyść czat", + ["command_clearall"] = "wyczyść czat dla wszystkich graczy", + ["command_clearinventory"] = "wyczyść ekwipunek gracza", + ["command_clearloadout"] = "wyczyść wyposarzenie gracza", + ["command_giveaccountmoney"] = "daj pieniądze na podany typ konta", + ["command_giveaccountmoney_account"] = "prawidłowy typ konta", + ["command_giveaccountmoney_amount"] = "ilość do dodania", + ["command_giveaccountmoney_invalid"] = "nieprawidłowy typ konta", + ["command_giveitem"] = "daj przedmiot graczowi", + ["command_giveitem_item"] = "nazwa przedmiotu", + ["command_giveitem_count"] = "ilość przedimotu", + ["command_giveweapon"] = "daj broń graczowi", + ["command_giveweapon_weapon"] = "nazwa broni", + ["command_giveweapon_ammo"] = "ilość amunicji", + ["command_giveweapon_hasalready"] = "gracz już posiada tą broń", + ["command_giveweaponcomponent"] = "daj komponent do broni graczowi", + ["command_giveweaponcomponent_component"] = "nazwa komponentu", + ["command_giveweaponcomponent_invalid"] = "nieprawidłowy komponent do broni", + ["command_giveweaponcomponent_hasalready"] = "gracz już posiada ten komponent do tej broni", + ["command_giveweaponcomponent_missingweapon"] = "gracz nie posiada tej broni", + ["command_save"] = "zapisz gracza w bazie danych", + ["command_saveall"] = "zapisz wszystkich graczy w bazie danych", + ["command_setaccountmoney"] = "ustaw ilość pieniędzy danego konta dla gracza", + ["command_setaccountmoney_amount"] = "ilość pieniędzy do ustawienia", + ["command_setcoords"] = "teleportuj na koordynaty", + ["command_setcoords_x"] = "x axis", + ["command_setcoords_y"] = "y axis", + ["command_setcoords_z"] = "z axis", + ["command_setjob"] = "ustaw prace dla gracza", + ["command_setjob_job"] = "nazwa pracy", + ["command_setjob_grade"] = "stanowisko w pracy", + ["command_setjob_invalid"] = "praca, stanowisko lub obydwa są nieprawidłowe", + ["command_setgroup"] = "ustaw grupe gracza", + ["command_setgroup_group"] = "nazwa grupy", + ["commanderror_argumentmismatch"] = "nieprawiłowa ilość argumentów (przeszło %s, wymagane %s)", + ["commanderror_argumentmismatch_number"] = "nieprawidłowy typ argumentu #%s (przeszedł tekst, wymagany numer)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (passed number, wanted string)", + ["commanderror_argumentmismatch_positive_number"] = "Nieprawidłowy argument #%s typ danych (przekazano ujemny/zero, oczekiwano liczby dodatniej)", + ["commanderror_invaliditem"] = "nieprawidłowa nazwa przedmiotu", + ["commanderror_invalidweapon"] = "nieprawidłowa broń", + ["commanderror_console"] = "podana komenda nie może zostać uruchomiona przez konsole", + ["commanderror_invalidcommand"] = "/%s nie jest poprawną komendą!", + ["commanderror_invalidplayerid"] = "brak dostepnego gracza pasującego do podanego id serwerowego", + ["commandgeneric_playerid"] = "id gracza", + ["command_giveammo_noweapon_found"] = "%s does not have that weapon", + ["command_giveammo_weapon"] = "Weapon name", + ["command_giveammo_ammo"] = "Ammo Quantity", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "$%s", + + -- Weapons + ["weapon_knife"] = "nóż", + ["weapon_nightstick"] = "pałka", + ["weapon_hammer"] = "młotek", + ["weapon_bat"] = "kij", + ["weapon_golfclub"] = "kij golfowy", + ["weapon_crowbar"] = "łom", + ["weapon_pistol"] = "pistolet", + ["weapon_combatpistol"] = "pistolet bojowy", + ["weapon_appistol"] = "ap pistol", + ["weapon_pistol50"] = "pistol .50", + ["weapon_microsmg"] = "micro smg", + ["weapon_smg"] = "smg", + ["weapon_assaultsmg"] = "assault smg", + ["weapon_assaultrifle"] = "assault rifle", + ["weapon_carbinerifle"] = "carbine rifle", + ["weapon_advancedrifle"] = "advanced rifle", + ["weapon_mg"] = "mg", + ["weapon_combatmg"] = "combat mg", + ["weapon_pumpshotgun"] = "pump shotgun", + ["weapon_sawnoffshotgun"] = "sawed off shotgun", + ["weapon_assaultshotgun"] = "assault shotgun", + ["weapon_bullpupshotgun"] = "bullpup shotgun", + ["weapon_stungun"] = "tazer", + ["weapon_sniperrifle"] = "karabin snajperski", + ["weapon_heavysniper"] = "ciężki karabin snajperski", + ["weapon_grenadelauncher"] = "granatnik", + ["weapon_rpg"] = "wyrzutnia rakiet", + ["weapon_minigun"] = "minigun", + ["weapon_grenade"] = "granat", + ["weapon_stickybomb"] = "ładunek przylepny", + ["weapon_smokegrenade"] = "granat dymny", + ["weapon_bzgas"] = "bz gas", + ["weapon_molotov"] = "koktajl Mołotowa", + ["weapon_fireextinguisher"] = "gaśnica", + ["weapon_petrolcan"] = "kanister", + ["weapon_ball"] = "piłka", + ["weapon_snspistol"] = "sns pistolet", + ["weapon_bottle"] = "butelka", + ["weapon_gusenberg"] = "gusenberg sweeper", + ["weapon_specialcarbine"] = "special carbine", + ["weapon_heavypistol"] = "heavy pistol", + ["weapon_bullpuprifle"] = "karabin wyborowy", + ["weapon_dagger"] = "sztylet", + ["weapon_vintagepistol"] = "vintage pistol", + ["weapon_firework"] = "fajerwerki", + ["weapon_musket"] = "muszkiet", + ["weapon_heavyshotgun"] = "ciężki shotgun", + ["weapon_marksmanrifle"] = "marksman rifle", + ["weapon_hominglauncher"] = "program uruchamiający", + ["weapon_proxmine"] = "mina zbliżeniowa", + ["weapon_snowball"] = "śnieżka", + ["weapon_flaregun"] = "flara", + ["weapon_combatpdw"] = "combat pdw", + ["weapon_marksmanpistol"] = "marksman pistol", + ["weapon_knuckle"] = "kastety", + ["weapon_hatchet"] = "toporek", + ["weapon_railgun"] = "karabin", + ["weapon_machete"] = "meczeta", + ["weapon_machinepistol"] = "pistolet maszynowy", + ["weapon_switchblade"] = "scyzoryk", + ["weapon_revolver"] = "ciężki rewolwer", + ["weapon_dbshotgun"] = "dwururka", + ["weapon_compactrifle"] = "compact rifle", + ["weapon_autoshotgun"] = "auto shotgun", + ["weapon_battleaxe"] = "topór bitewny", + ["weapon_compactlauncher"] = "compact launcher", + ["weapon_minismg"] = "mini smg", + ["weapon_pipebomb"] = "bomba rurowa", + ["weapon_poolcue"] = "kij bilardowy", + ["weapon_wrench"] = "klucz do rur", + ["weapon_flashlight"] = "latarka", + ["gadget_parachute"] = "spadochron", + ["weapon_flare"] = "pistolet sygnałowy", + ["weapon_doubleaction"] = "double-Action Revolver", + ["weapon_heavyrifle"] = "Heavy Rifle", -- Not Translated + + -- Weapon Components + ["component_clip_default"] = "domyślny tłumik", + ["component_clip_extended"] = "rozszerzony tłumik", + ["component_clip_drum"] = "magazynek bębnowy", + ["component_clip_box"] = "magazynek", + ["component_flashlight"] = "latarka", + ["component_scope"] = "luneta", + ["component_scope_advanced"] = "zaawansowana luneta", + ["component_suppressor"] = "tłumik", + ["component_grip"] = "uchwyt", + ["component_luxary_finish"] = "luksusowe wykończenie broni", + + -- Drug Wars DLC + ["weapon_candycane"] = "Candy Cane", -- not translated + ["weapon_acidpackage"] = "Acid Package", -- not translated + ["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated + ["weapon_railgunxm3"] = "Railgun", -- not translated + + -- Weapon Ammo + ["ammo_rounds"] = "nabój/oi", + ["ammo_shells"] = "pocisk(ów)", + ["ammo_charge"] = "naładowania", + ["ammo_petrol"] = "galon(y) paliwa", + ["ammo_firework"] = "fajerwerka/i", + ["ammo_rockets"] = "rakieta/y", + ["ammo_grenadelauncher"] = "granat(y)", + ["ammo_grenade"] = "granat(y)", + ["ammo_stickybomb"] = "bomba/y", + ["ammo_pipebomb"] = "bomba/y", + ["ammo_smokebomb"] = "bomba/y", + ["ammo_molotov"] = "kontail(e)", + ["ammo_proxmine"] = "mina/y", + ["ammo_bzgas"] = "puszka/ek", + ["ammo_ball"] = "kula/e", + ["ammo_snowball"] = "snieżka/i", + ["ammo_flare"] = "flara/y", + ["ammo_flaregun"] = "flara/y", + + -- Weapon Tints + ["tint_default"] = "domyślny skin", + ["tint_green"] = "zielony skin", + ["tint_gold"] = "złoty skin", + ["tint_pink"] = "różowy skin", + ["tint_army"] = "wojskowy skin", + ["tint_lspd"] = "niebieski skin", + ["tint_orange"] = "pomarańczowy skin", + ["tint_platinum"] = "platynowy skin", + -- MK2 Weapon Tints + ["tint_classic_black"] = "klasyczna czerń", + ["tint_classic_gray"] = "klasyczny szary", + ["tint_classic_two_tone"] = "klasyczny dwutonowy", + ["tint_classic_white"] = "klasyczna biel", + ["tint_classic_beige"] = "klasyczny beż", + ["tint_classic_green"] = "klasyczna zieleń", + ["tint_classic_blue"] = "klasyczny niebieski", + ["tint_classic_earth"] = "klasyczna ziemia", + ["tint_classic_brown_black"] = "klasyczny brązowo-czarny", + ["tint_contrast_red"] = "kontrastowy czerwony", + ["tint_contrast_blue"] = "kontrastowy niebieski", + ["tint_contrast_yellow"] = "kontrastowy żółty", + ["tint_contrast_orange"] = "kontrastowy pomarańczowy", + ["tint_bold_pink"] = "odważny różowy", + ["tint_bold_purple_yellow"] = "odważny fioletowo-żółty", + ["tint_bold_orange"] = "odważny pomarańczowy", + ["tint_bold_green_purple"] = "odważny zielono-fioletowy", + ["tint_bold_red_feat"] = "odważny czerwony feat", + ["tint_bold_green_feat"] = "odważny zielony feat", + ["tint_bold_cyan_feat"] = "odważny cyjan feat", + ["tint_bold_yellow_feat"] = "odważny żółty feat", + ["tint_bold_red_white"] = "odważny czerwony biały", + ["tint_bold_blue_white"] = "odważny niebieski biały", + ["tint_metallic_gold"] = "złoto metaliczne", + ["tint_metallic_platinum"] = "platyna metaliczna", + ["tint_metallic_gray_lilac"] = "szaro-liliowe metaliczne", + ["tint_metallic_purple_lime"] = "fioletowo-limonkowe metaliczne", + ["tint_metallic_red"] = "czerwony metaliczny", + ["tint_metallic_green"] = "zielony metaliczny", + ["tint_metallic_blue"] = "niebieski metaliczny", + ["tint_metallic_white_aqua"] = "białe aqua metaliczne", + ["tint_metallic_red_yellow"] = "czerwono-żółte metaliczne", +} diff --git a/resources/[core]/es_extended/locales/sl.lua b/resources/[core]/es_extended/locales/sl.lua new file mode 100644 index 0000000..42a2c35 --- /dev/null +++ b/resources/[core]/es_extended/locales/sl.lua @@ -0,0 +1,411 @@ +return { + -- Inventory + ["inventory"] = "Shramba ( Teza %s / %s )", + ["use"] = "Uporabi", + ["give"] = "Daj", + ["remove"] = "Vrzi", + ["return"] = "Povratek", + ["give_to"] = "Daj", + ["amount"] = "Vsota", + ["giveammo"] = "Daj Strelivo", + ["amountammo"] = "Količina streliva", + ["noammo"] = "Ni dovolj!", + ["gave_item"] = "Dal si %sx %s k %s", + ["received_item"] = "Dobil si %sx %s od %s", + ["gave_weapon"] = "Dajanje %s do %s", + ["gave_weapon_ammo"] = "Dajanje ~o~%sx %s za %s do %s", + ["gave_weapon_withammo"] = "Dajanje %s z ~o~%sx %s do %s", + ["gave_weapon_hasalready"] = "%s ze ima %s", + ["gave_weapon_noweapon"] = "%s se nima tega orozja", + ["received_weapon"] = "Dobil si %s od %s", + ["received_weapon_ammo"] = "Dobil ~o~%sx %s za tvoj/o %s od %s", + ["received_weapon_withammo"] = "Dobil si %s z ~o~%sx %s od %s", + ["received_weapon_hasalready"] = "%s vam je poskušal dati %s, vendar že imate to orožje", + ["received_weapon_noweapon"] = "%s vam je poskušal dati strelivo za %s, vendar nimate tega orožja", + ["gave_account_money"] = "Dajanje $%s (%s) do %s", + ["received_account_money"] = "Dobil $%s (%s) od %s", + ["amount_invalid"] = "Neveljavna količina", + ["players_nearby"] = "V blizini ni ljudi", + ["ex_inv_lim"] = "Dejanja ni mogoče izvesti, saj presega največjo težo %s", + ["imp_invalid_quantity"] = "Dejanja ni mogoče izvesti, količina je neveljavna", + ["imp_invalid_amount"] = "Dejanja ni mogoče izvesti, znesek je neveljaven", + ["threw_standard"] = "Metanje %sx %s", + ["threw_account"] = "Metanje $%s %s", + ["threw_weapon"] = "Metanje %s", + ["threw_weapon_ammo"] = "Metanje %s z ~o~%sx %s", + ["threw_weapon_already"] = "Ti ze imas to orozje", + ["threw_cannot_pickup"] = "Shramba je poln, nemorem pobrati!", + ["threw_pickup_prompt"] = "Pritisni E da poberes", + + -- Key mapping + ["keymap_showinventory"] = "Pokazi Shrambo", + + -- Salary related + ["received_salary"] = "Vi ste plačali: $%s", + ["received_help"] = "Vi ste placali svoj CEK v vrednosti: $%s", + ["company_nomoney"] = "podjetje, v katerem ste zaposleni, je prerevno, da bi vam izplačevalo plačo", + ["received_paycheck"] = "Prejel si Placilo", + ["bank"] = "NLB", + ["account_bank"] = "Banka", + ["account_black_money"] = "Umazan Denar", + ["account_money"] = "Denar", + + ["act_imp"] = "Dejanja ni mogoče izvesti", + ["in_vehicle"] = "Dejanja ni mogoče izvesti, Oseba je v vozilu", + ["not_in_vehicle"] = "Cannot Perform Action, Player isn't in a vehicle", + + -- Commands + ["command_bring"] = "Teleportiraj osebo do sebe", + ["command_car"] = "Spawnaj si vozilo", + ["command_car_car"] = "Koda vozila", + ["command_cardel"] = "Odstranite vozila v bližini", + ["command_cardel_radius"] = "Odstrani vsa vozila v določenem radiju", + ["command_repair"] = "Repair your vehicle", + ["command_repair_success"] = "Successfully repaired vehicle", + ["command_repair_success_target"] = "An admin repaired your vehicle", + ["command_clear"] = "Odstrani vsa sporocila v CHATU", + ["command_clearall"] = "Počisti besedilo klepeta za vse igralce", + ["command_clearinventory"] = "Vzemi vse stvari iz osebove shrambe", + ["command_clearloadout"] = "Odstranite vse orožje iz nalaganja igralcev", + ["command_freeze"] = "Zmrzni osebno", + ["command_unfreeze"] = "Odmrzni osebo", + ["command_giveaccountmoney"] = "Poslji denar na dolocen Bancni racun", + ["command_giveaccountmoney_account"] = "Račun za dodajanje", + ["command_giveaccountmoney_amount"] = "Znesek za dodajanje", + ["command_giveaccountmoney_invalid"] = "Ime računa je neveljavno", + ["command_giveitem"] = "Daj osebi neko stvar", + ["command_giveitem_item"] = "Ime Stvari", + ["command_giveitem_count"] = "Kolicina", + ["command_giveweapon"] = "Daj osebi orozje", + ["command_giveweapon_weapon"] = "Ime orozja", + ["command_giveweapon_ammo"] = "Kolicina", + ["command_giveweapon_hasalready"] = "Oseba ze ima to orozje!", + ["command_giveweaponcomponent"] = "Daj komponento orožja igralcu", + ["command_giveweaponcomponent_component"] = "Ime Komponente", + ["command_giveweaponcomponent_invalid"] = "Neveljavna komponenta orožja", + ["command_giveweaponcomponent_hasalready"] = "Oseba ze ima to komponento", + ["command_giveweaponcomponent_missingweapon"] = "Oseba nima tega orozja!", + ["command_goto"] = "Teleportirajte se k igralcu", + ["command_kill"] = "Ubij igralca", + ["command_save"] = "Prisilno shrani podatke igralca!", + ["command_saveall"] = "Prisilno shrani vse podatke igralca", + ["command_setaccountmoney"] = "Nastavite denar znotraj dolocenega racuna", + ["command_setaccountmoney_amount"] = "Znesek", + ["command_setcoords"] = "Teleport na dolocene koordinate", + ["command_setcoords_x"] = "Vrednost X", + ["command_setcoords_y"] = "Vrednost Y", + ["command_setcoords_z"] = "Z vrednost", + ["command_setjob"] = "Nastavi opravilo igralca", + ["command_setjob_job"] = "Ime", + ["command_setjob_grade"] = "Delovna ocena", + ["command_setjob_invalid"] = "delovno mesto, ocena ali oboje ni veljavno", + ["command_setgroup"] = "Nastavi skupino dovoljenj igralcev", + ["command_setgroup_group"] = "Ime skupine", + ["commanderror_argumentmismatch"] = "Neveljavno stetje argumentov (podano %s, zeleno %s)", + ["commanderror_argumentmismatch_number"] = "Neveljaven podatkovni tip argumenta #%s (posredovan niz, zeleno stevilo)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (passed number, wanted string)", + ["commanderror_argumentmismatch_positive_number"] = "Neveljaven argument #%s tip podatkov (podano negativno/nič, zahtevano pozitivno število)", + ["commanderror_invaliditem"] = "Neveljaven element", + ["commanderror_invalidweapon"] = "Neveljavno orozje", + ["commanderror_console"] = "Ukaza ni mogoce izvesti s konzole", + ["commanderror_invalidcommand"] = "Neveljaven ukaz - /%s", + ["commanderror_invalidplayerid"] = "Naveden igralec ni na spletu", + ["commandgeneric_playerid"] = "Id streznika igralca", + ["command_giveammo_noweapon_found"] = "%s nima tega orozja", + ["command_giveammo_weapon"] = "Ime orozja", + ["command_giveammo_ammo"] = "Kolicina streliva", + ["tpm_nowaypoint"] = "Ni nastavljene poti!.", + ["tpm_success"] = "Uspesno teleportiran", + + ["noclip_message"] = "Noclip je bil %s", + ["enabled"] = "~g~Vkljucen~s~", + ["disabled"] = "~r~Izkljucen~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "€%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dagger", + ["weapon_bat"] = "Bat", + ["weapon_battleaxe"] = "Battle Axe", + ["weapon_bottle"] = "Bottle", + ["weapon_crowbar"] = "Crowbar", + ["weapon_flashlight"] = "Flashlight", + ["weapon_golfclub"] = "Golf Club", + ["weapon_hammer"] = "Hammer", + ["weapon_hatchet"] = "Hatchet", + ["weapon_knife"] = "Knife", + ["weapon_knuckle"] = "Knuckledusters", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Nightstick", + ["weapon_wrench"] = "Pipe Wrench", + ["weapon_poolcue"] = "Pool Cue", + ["weapon_stone_hatchet"] = "Stone Hatchet", + ["weapon_switchblade"] = "Switchblade", + + -- Handguns + ["weapon_appistol"] = "AP Pistol", + ["weapon_ceramicpistol"] = "Ceramic Pistol", + ["weapon_combatpistol"] = "Combat Pistol", + ["weapon_doubleaction"] = "Double-Action Revolver", + ["weapon_navyrevolver"] = "Navy Revolver", + ["weapon_flaregun"] = "Flaregun", + ["weapon_gadgetpistol"] = "Gadget Pistol", + ["weapon_heavypistol"] = "Heavy Pistol", + ["weapon_revolver"] = "Heavy Revolver", + ["weapon_revolver_mk2"] = "Heavy Revolver MK2", + ["weapon_marksmanpistol"] = "Marksman Pistol", + ["weapon_pistol"] = "Pistol", + ["weapon_pistol_mk2"] = "Pistol MK2", + ["weapon_pistol50"] = "Pistol .50", + ["weapon_snspistol"] = "SNS Pistol", + ["weapon_snspistol_mk2"] = "SNS Pistol MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Vintage Pistol", + + -- Shotguns + ["weapon_assaultshotgun"] = "Assault Shotgun", + ["weapon_autoshotgun"] = "Auto Shotgun", + ["weapon_bullpupshotgun"] = "Bullpup Shotgun", + ["weapon_combatshotgun"] = "Combat Shotgun", + ["weapon_dbshotgun"] = "Double Barrel Shotgun", + ["weapon_heavyshotgun"] = "Heavy Shotgun", + ["weapon_musket"] = "Musket", + ["weapon_pumpshotgun"] = "Pump Shotgun", + ["weapon_pumpshotgun_mk2"] = "Pump Shotgun MK2", + ["weapon_sawnoffshotgun"] = "Sawed Off Shotgun", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Assault SMG", + ["weapon_combatmg"] = "Combat MG", + ["weapon_combatmg_mk2"] = "Combat MG MK2", + ["weapon_combatpdw"] = "Combat PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Machine Pistol", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Unholy Hellbringer", + + -- Rifles + ["weapon_advancedrifle"] = "Advanced Rifle", + ["weapon_assaultrifle"] = "Assault Rifle", + ["weapon_assaultrifle_mk2"] = "Assault Rifle MK2", + ["weapon_bullpuprifle"] = "Bullpup Rifle", + ["weapon_bullpuprifle_mk2"] = "Bullpup Rifle MK2", + ["weapon_carbinerifle"] = "Carbine Rifle", + ["weapon_carbinerifle_mk2"] = "Carbine Rifle MK2", + ["weapon_compactrifle"] = "Compact Rifle", + ["weapon_militaryrifle"] = "Military Rifle", + ["weapon_specialcarbine"] = "Special Carbine", + ["weapon_specialcarbine_mk2"] = "Special Carbine MK2", + ["weapon_heavyrifle"] = "Heavy Rifle", -- Not Translated + + -- Sniper + ["weapon_heavysniper"] = "Heavy Sniper", + ["weapon_heavysniper_mk2"] = "Heavy Sniper MK2", + ["weapon_marksmanrifle"] = "Marksman Rifle", + ["weapon_marksmanrifle_mk2"] = "Marksman Rifle MK2", + ["weapon_sniperrifle"] = "Sniper Rifle", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Compact Launcher", + ["weapon_firework"] = "Firework Launcher", + ["weapon_grenadelauncher"] = "Grenade Launcher", + ["weapon_hominglauncher"] = "Homing Launcher", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Rocket Launcher", + ["weapon_rayminigun"] = "Widowmaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Metal Detector", + ["weapon_precisionrifle"] = "Precision Rifle", + ["weapon_tactilerifle"] = "Service Carbine", + + -- Drug Wars DLC + ["weapon_candycane"] = "Candy Cane", -- not translated + ["weapon_acidpackage"] = "Acid Package", -- not translated + ["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated + ["weapon_railgunxm3"] = "Railgun", -- not translated + + -- Thrown + ["weapon_ball"] = "Baseball", + ["weapon_bzgas"] = "BZ Gas", + ["weapon_flare"] = "Flare", + ["weapon_grenade"] = "Grenade", + ["weapon_petrolcan"] = "Jerrycan", + ["weapon_hazardcan"] = "Hazardous Jerrycan", + ["weapon_molotov"] = "Molotov Cocktail", + ["weapon_proxmine"] = "Proximity Mine", + ["weapon_pipebomb"] = "Pipe Bomb", + ["weapon_snowball"] = "Snowball", + ["weapon_stickybomb"] = "Sticky Bomb", + ["weapon_smokegrenade"] = "Tear Gas", + + -- Special + ["weapon_fireextinguisher"] = "Fire Extinguisher", + ["weapon_digiscanner"] = "Digital Scanner", + ["weapon_garbagebag"] = "Garbage Bag", + ["weapon_handcuffs"] = "Handcuffs", + ["gadget_nightvision"] = "Night Vision", + ["gadget_parachute"] = "parachute", + + -- Weapon Components + ["component_knuckle_base"] = "base Model", + ["component_knuckle_pimp"] = "the Pimp", + ["component_knuckle_ballas"] = "the Ballas", + ["component_knuckle_dollar"] = "the Hustler", + ["component_knuckle_diamond"] = "the Rock", + ["component_knuckle_hate"] = "the Hater", + ["component_knuckle_love"] = "the Lover", + ["component_knuckle_player"] = "the Player", + ["component_knuckle_king"] = "the King", + ["component_knuckle_vagos"] = "the Vagos", + + ["component_luxary_finish"] = "luxary Weapon Finish", + + ["component_handle_default"] = "default Handle", + ["component_handle_vip"] = "vIP Handle", + ["component_handle_bodyguard"] = "bodyguard Handle", + + ["component_vip_finish"] = "vIP Finish", + ["component_bodyguard_finish"] = "bodyguard Finish", + + ["component_camo_finish"] = "digital Camo", + ["component_camo_finish2"] = "brushstroke Camo", + ["component_camo_finish3"] = "woodland Camo", + ["component_camo_finish4"] = "skull Camo", + ["component_camo_finish5"] = "sessanta Nove Camo", + ["component_camo_finish6"] = "perseus Camo", + ["component_camo_finish7"] = "leopard Camo", + ["component_camo_finish8"] = "zebra Camo", + ["component_camo_finish9"] = "geometric Camo", + ["component_camo_finish10"] = "boom Camo", + ["component_camo_finish11"] = "patriotic Camo", + + ["component_camo_slide_finish"] = "digital Slide Camo", + ["component_camo_slide_finish2"] = "brushstroke Slide Camo", + ["component_camo_slide_finish3"] = "woodland Slide Camo", + ["component_camo_slide_finish4"] = "skull Slide Camo", + ["component_camo_slide_finish5"] = "sessanta Nove Slide Camo", + ["component_camo_slide_finish6"] = "perseus Slide Camo", + ["component_camo_slide_finish7"] = "leopard Slide Camo", + ["component_camo_slide_finish8"] = "zebra Slide Camo", + ["component_camo_slide_finish9"] = "geometric Slide Camo", + ["component_camo_slide_finish10"] = "boom Slide Camo", + ["component_camo_slide_finish11"] = "patriotic Slide Camo", + + ["component_clip_default"] = "default Magazine", + ["component_clip_extended"] = "extended Magazine", + ["component_clip_drum"] = "drum Magazine", + ["component_clip_box"] = "box Magazine", + + ["component_scope_holo"] = "holographic Scope", + ["component_scope_small"] = "small Scope", + ["component_scope_medium"] = "medium Scope", + ["component_scope_large"] = "large Scope", + ["component_scope"] = "mounted Scope", + ["component_scope_advanced"] = "advanced Scope", + ["component_ironsights"] = "ironsights", + + ["component_suppressor"] = "suppressor", + ["component_compensator"] = "compensator", + + ["component_muzzle_flat"] = "flat Muzzle Brake", + ["component_muzzle_tactical"] = "tactical Muzzle Brake", + ["component_muzzle_fat"] = "fat-End Muzzle Brake", + ["component_muzzle_precision"] = "precision Muzzle Brake", + ["component_muzzle_heavy"] = "heavy Duty Muzzle Brake", + ["component_muzzle_slanted"] = "slanted Muzzle Brake", + ["component_muzzle_split"] = "split-End Muzzle Brake", + ["component_muzzle_squared"] = "squared Muzzle Brake", + + ["component_flashlight"] = "flashlight", + ["component_grip"] = "grip", + + ["component_barrel_default"] = "default Barrel", + ["component_barrel_heavy"] = "heavy Barrel", + + ["component_ammo_tracer"] = "tracer Ammo", + ["component_ammo_incendiary"] = "incendiary Ammo", + ["component_ammo_hollowpoint"] = "hollowpoint Ammo", + ["component_ammo_fmj"] = "fMJ Ammo", + ["component_ammo_armor"] = "armor Piercing Ammo", + ["component_ammo_explosive"] = "armor Piercing Incendiary Ammo", + + ["component_shells_default"] = "default Shells", + ["component_shells_incendiary"] = "dragons Breath Shells", + ["component_shells_armor"] = "steel Buckshot Shells", + ["component_shells_hollowpoint"] = "flechette Shells", + ["component_shells_explosive"] = "explosive Slug Shells", + + -- Weapon Ammo + ["ammo_rounds"] = "round(s)", + ["ammo_shells"] = "shell(s)", + ["ammo_charge"] = "charge", + ["ammo_petrol"] = "gallons of fuel", + ["ammo_firework"] = "firework(s)", + ["ammo_rockets"] = "rocket(s)", + ["ammo_grenadelauncher"] = "grenade(s)", + ["ammo_grenade"] = "grenade(s)", + ["ammo_stickybomb"] = "bomb(s)", + ["ammo_pipebomb"] = "bomb(s)", + ["ammo_smokebomb"] = "bomb(s)", + ["ammo_molotov"] = "cocktail(s)", + ["ammo_proxmine"] = "mine(s)", + ["ammo_bzgas"] = "can(s)", + ["ammo_ball"] = "ball(s)", + ["ammo_snowball"] = "snowball(s)", + ["ammo_flare"] = "flare(s)", + ["ammo_flaregun"] = "flare(s)", + + -- Weapon Tints + ["tint_default"] = "default skin", + ["tint_green"] = "green skin", + ["tint_gold"] = "gold skin", + ["tint_pink"] = "pink skin", + ["tint_army"] = "army skin", + ["tint_lspd"] = "blue skin", + ["tint_orange"] = "orange skin", + ["tint_platinum"] = "platinum skin", + -- MK2 Weapon Tints + ["tint_classic_black"] = "klasična črna", + ["tint_classic_gray"] = "klasična siva", + ["tint_classic_two_tone"] = "klasična dvo-tonska", + ["tint_classic_white"] = "klasična bela", + ["tint_classic_beige"] = "klasična bež", + ["tint_classic_green"] = "klasična zelena", + ["tint_classic_blue"] = "klasična modra", + ["tint_classic_earth"] = "klasična zemlja", + ["tint_classic_brown_black"] = "klasična rjava-črna", + ["tint_contrast_red"] = "kontrastna rdeča", + ["tint_contrast_blue"] = "kontrastna modra", + ["tint_contrast_yellow"] = "kontrastna rumena", + ["tint_contrast_orange"] = "kontrastna oranžna", + ["tint_bold_pink"] = "drzna roza", + ["tint_bold_purple_yellow"] = "drzna vijolično-rumena", + ["tint_bold_orange"] = "drzna oranžna", + ["tint_bold_green_purple"] = "drzna zelena-vijolična", + ["tint_bold_red_feat"] = "drzna rdeča feat", + ["tint_bold_green_feat"] = "drzna zelena feat", + ["tint_bold_cyan_feat"] = "drzna cian feat", + ["tint_bold_yellow_feat"] = "drzna rumena feat", + ["tint_bold_red_white"] = "drzna rdeča bela", + ["tint_bold_blue_white"] = "drzna modra bela", + ["tint_metallic_gold"] = "metalik zlato", + ["tint_metallic_platinum"] = "metalik platina", + ["tint_metallic_gray_lilac"] = "metalik siv lila", + ["tint_metallic_purple_lime"] = "metalik vijolična limona", + ["tint_metallic_red"] = "metalik rdeča", + ["tint_metallic_green"] = "metalik zelena", + ["tint_metallic_blue"] = "metalik modra", + ["tint_metallic_white_aqua"] = "metalik bela aqua", + ["tint_metallic_red_yellow"] = "metalik rdeče rumeno", +} diff --git a/resources/[core]/es_extended/locales/sr.lua b/resources/[core]/es_extended/locales/sr.lua new file mode 100644 index 0000000..292e350 --- /dev/null +++ b/resources/[core]/es_extended/locales/sr.lua @@ -0,0 +1,411 @@ +return { + -- Inventory + ["inventory"] = "Inventar ( Težina %s / %s )", + ["use"] = "Koristi", + ["give"] = "Daj", + ["remove"] = "Baci", + ["return"] = "Nazad", + ["give_to"] = "Daj", + ["amount"] = "Količina", + ["giveammo"] = "Daj municiju", + ["amountammo"] = "Količina municije", + ["noammo"] = "Nemate dovoljno!", + ["gave_item"] = "Davanje %sx %s igraču %s", + ["received_item"] = "Dobijeno %sx %s od %s", + ["gave_weapon"] = "Davanje %s igraču %s", + ["gave_weapon_ammo"] = "Davanje ~o~%sx %s za %s igraču %s", + ["gave_weapon_withammo"] = "Davanje %s sa ~o~%sx %s igraču %s", + ["gave_weapon_hasalready"] = "%s već ima %s", + ["gave_weapon_noweapon"] = "%s nema to oružje", + ["received_weapon"] = "Dobijeno %s od %s", + ["received_weapon_ammo"] = "Dobijeno ~o~%sx %s za vaš %s od %s", + ["received_weapon_withammo"] = "Dobijeno %s sa ~o~%sx %s od %s", + ["received_weapon_hasalready"] = "%s je pokušao da Vam da %s, ali vi već imate to oružje", + ["received_weapon_noweapon"] = "%s je pokušao da Vam da municiju za %s, ali vi nemate to oružje", + ["gave_account_money"] = "Davanje $%s (%s) igraču %s", + ["received_account_money"] = "Dobijeno $%s (%s) od %s", + ["amount_invalid"] = "Nevažeća količina", + ["players_nearby"] = "Nema igrača u blizini", + ["ex_inv_lim"] = "Ne možete uraditi to, premašuje max težinu od %s", + ["imp_invalid_quantity"] = "Nevažeća količina", + ["imp_invalid_amount"] = "Nevažeći iznos", + ["threw_standard"] = "Bacanje %sx %s", + ["threw_account"] = "Bacanje $%s %s", + ["threw_weapon"] = "Bacanje %s", + ["threw_weapon_ammo"] = "Bacanje %s sa ~o~%sx %s", + ["threw_weapon_already"] = "Vi već imate to oružje", + ["threw_cannot_pickup"] = "Inventar je pun, ne možete pokupiti to!", + ["threw_pickup_prompt"] = "Pritisni E da pokupiš", + + -- Key mapping + ["keymap_showinventory"] = "Otvaranje inventara", + + -- Salary related + ["received_salary"] = "Plaćeno Vam je: $%s", + ["received_help"] = "Isplaćen Vam je ček: $%s", + ["company_nomoney"] = "Kompanija u kojoj ste zapošljeni nema više novca", + ["received_paycheck"] = "primili ste platu", + ["bank"] = "Maze Banka", + ["account_bank"] = "Banka", + ["account_black_money"] = "Prljav novac", + ["account_money"] = "Novac", + + ["act_imp"] = "Ne možete izvršiti radnju", + ["in_vehicle"] = "Ne možete uraditi to dok je igrač u vozilu", + ["not_in_vehicle"] = "Cannot Perform Action, Player isn't in a vehicle", + + -- Commands + ["command_bring"] = "TP-ajte igrača do Vas", + ["command_car"] = "Stvorite vozilo", + ["command_car_car"] = "Model ili hash vozila", + ["command_cardel"] = "Obrišite vozilo u blizini", + ["command_cardel_radius"] = "Obrišite sva vozila unutar navedenog radiusa", + ["command_repair"] = "Repair your vehicle", + ["command_repair_success"] = "Successfully repaired vehicle", + ["command_repair_success_target"] = "An admin repaired your vehicle", + ["command_clear"] = "Obrišite chat", + ["command_clearall"] = "Obrišite chat za sve igrače", + ["command_clearinventory"] = "Obrišite sve stvari iz inventara igrača", + ["command_clearloadout"] = "Obrišite sva oružja iz inventara igrača", + ["command_freeze"] = "Zaledite igrača", + ["command_unfreeze"] = "Odledite igrača", + ["command_giveaccountmoney"] = "Dajte novac na odredjeni nalog", + ["command_giveaccountmoney_account"] = "Nalog za slanje", + ["command_giveaccountmoney_amount"] = "Količina", + ["command_giveaccountmoney_invalid"] = "Nalog nepostojeći", + ["command_giveitem"] = "Dajte item igraču", + ["command_giveitem_item"] = "Ime item-a", + ["command_giveitem_count"] = "Količina", + ["command_giveweapon"] = "Dajte oružje igraču", + ["command_giveweapon_weapon"] = "Ime oružja", + ["command_giveweapon_ammo"] = "Količina municije", + ["command_giveweapon_hasalready"] = "Igrač već ima to oružje", + ["command_giveweaponcomponent"] = "Dajte dodatak za oružje igraču", + ["command_giveweaponcomponent_component"] = "Ime dodatka", + ["command_giveweaponcomponent_invalid"] = "Nevažeći dodatak", + ["command_giveweaponcomponent_hasalready"] = "Igrač već ima taj dodatak", + ["command_giveweaponcomponent_missingweapon"] = "Igrač nema oružje", + ["command_goto"] = "Idite do igrača", + ["command_kill"] = "Ubijte igrača", + ["command_save"] = "Forsirajte čuvanje date igrača", + ["command_saveall"] = "Forsirajte čuvanje date svih igrača", + ["command_setaccountmoney"] = "Postavite novac na određeni račun", + ["command_setaccountmoney_amount"] = "Količina", + ["command_setcoords"] = "Teleportujte se na koordinate", + ["command_setcoords_x"] = "X", + ["command_setcoords_y"] = "Y", + ["command_setcoords_z"] = "Z", + ["command_setjob"] = "Postavite posao igraču", + ["command_setjob_job"] = "Ime", + ["command_setjob_grade"] = "Stepen posla", + ["command_setjob_invalid"] = "posao, stepen ili oba nisu validna", + ["command_setgroup"] = "Postavite permisiju", + ["command_setgroup_group"] = "Ime grupe", + ["commanderror_argumentmismatch"] = "Nevazeci broj argumenata (položio %s, željeno %s)", + ["commanderror_argumentmismatch_number"] = "Nevažeći argument #%s tip podataka (položeno, željeno)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (passed number, wanted string)", + ["commanderror_argumentmismatch_positive_number"] = "Nevaljan argument #%s tip podataka (prosleđen negativan/nula, potreban pozitivan broj)", + ["commanderror_invaliditem"] = "Nevažeći item", + ["commanderror_invalidweapon"] = "Nevažeće oružje", + ["commanderror_console"] = "Komanda se ne može izvršiti iz konzole", + ["commanderror_invalidcommand"] = "Nevažeća komanda - /%s", + ["commanderror_invalidplayerid"] = "Igrač nije online", + ["commandgeneric_playerid"] = "Igračev server ID", + ["command_giveammo_noweapon_found"] = "%s nema to oružje", + ["command_giveammo_weapon"] = "Ime oružja", + ["command_giveammo_ammo"] = "Količina municije", + ["tpm_nowaypoint"] = "Morate označiti lokaciju.", + ["tpm_success"] = "Teleportovani ste na lokaciju", + + ["noclip_message"] = "Noclip %s", + ["enabled"] = "~g~upaljen~s~", + ["disabled"] = "~r~ugašen~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "£%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dagger", + ["weapon_bat"] = "Bat", + ["weapon_battleaxe"] = "Battle Axe", + ["weapon_bottle"] = "Bottle", + ["weapon_crowbar"] = "Crowbar", + ["weapon_flashlight"] = "Flashlight", + ["weapon_golfclub"] = "Golf Club", + ["weapon_hammer"] = "Hammer", + ["weapon_hatchet"] = "Hatchet", + ["weapon_knife"] = "Knife", + ["weapon_knuckle"] = "Knuckledusters", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Nightstick", + ["weapon_wrench"] = "Pipe Wrench", + ["weapon_poolcue"] = "Pool Cue", + ["weapon_stone_hatchet"] = "Stone Hatchet", + ["weapon_switchblade"] = "Switchblade", + + -- Handguns + ["weapon_appistol"] = "AP Pistol", + ["weapon_ceramicpistol"] = "Ceramic Pistol", + ["weapon_combatpistol"] = "Combat Pistol", + ["weapon_doubleaction"] = "Double-Action Revolver", + ["weapon_navyrevolver"] = "Navy Revolver", + ["weapon_flaregun"] = "Flaregun", + ["weapon_gadgetpistol"] = "Gadget Pistol", + ["weapon_heavypistol"] = "Heavy Pistol", + ["weapon_revolver"] = "Heavy Revolver", + ["weapon_revolver_mk2"] = "Heavy Revolver MK2", + ["weapon_marksmanpistol"] = "Marksman Pistol", + ["weapon_pistol"] = "Pistol", + ["weapon_pistol_mk2"] = "Pistol MK2", + ["weapon_pistol50"] = "Pistol .50", + ["weapon_snspistol"] = "SNS Pistol", + ["weapon_snspistol_mk2"] = "SNS Pistol MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Vintage Pistol", + + -- Shotguns + ["weapon_assaultshotgun"] = "Assault Shotgun", + ["weapon_autoshotgun"] = "Auto Shotgun", + ["weapon_bullpupshotgun"] = "Bullpup Shotgun", + ["weapon_combatshotgun"] = "Combat Shotgun", + ["weapon_dbshotgun"] = "Double Barrel Shotgun", + ["weapon_heavyshotgun"] = "Heavy Shotgun", + ["weapon_musket"] = "Musket", + ["weapon_pumpshotgun"] = "Pump Shotgun", + ["weapon_pumpshotgun_mk2"] = "Pump Shotgun MK2", + ["weapon_sawnoffshotgun"] = "Sawed Off Shotgun", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Assault SMG", + ["weapon_combatmg"] = "Combat MG", + ["weapon_combatmg_mk2"] = "Combat MG MK2", + ["weapon_combatpdw"] = "Combat PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Machine Pistol", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Unholy Hellbringer", + + -- Rifles + ["weapon_advancedrifle"] = "Advanced Rifle", + ["weapon_assaultrifle"] = "Assault Rifle", + ["weapon_assaultrifle_mk2"] = "Assault Rifle MK2", + ["weapon_bullpuprifle"] = "Bullpup Rifle", + ["weapon_bullpuprifle_mk2"] = "Bullpup Rifle MK2", + ["weapon_carbinerifle"] = "Carbine Rifle", + ["weapon_carbinerifle_mk2"] = "Carbine Rifle MK2", + ["weapon_compactrifle"] = "Compact Rifle", + ["weapon_militaryrifle"] = "Military Rifle", + ["weapon_specialcarbine"] = "Special Carbine", + ["weapon_specialcarbine_mk2"] = "Special Carbine MK2", + ["weapon_heavyrifle"] = "Heavy Rifle", -- Not Translated + + -- Sniper + ["weapon_heavysniper"] = "Heavy Sniper", + ["weapon_heavysniper_mk2"] = "Heavy Sniper MK2", + ["weapon_marksmanrifle"] = "Marksman Rifle", + ["weapon_marksmanrifle_mk2"] = "Marksman Rifle MK2", + ["weapon_sniperrifle"] = "Sniper Rifle", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Compact Launcher", + ["weapon_firework"] = "Firework Launcher", + ["weapon_grenadelauncher"] = "Grenade Launcher", + ["weapon_hominglauncher"] = "Homing Launcher", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Rocket Launcher", + ["weapon_rayminigun"] = "Widowmaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Metal Detector", + ["weapon_precisionrifle"] = "Precision Rifle", + ["weapon_tactilerifle"] = "Service Carbine", + + -- Drug Wars DLC + ["weapon_candycane"] = "Candy Cane", -- not translated + ["weapon_acidpackage"] = "Acid Package", -- not translated + ["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated + ["weapon_railgunxm3"] = "Railgun", -- not translated + + -- Thrown + ["weapon_ball"] = "Baseball", + ["weapon_bzgas"] = "BZ Gas", + ["weapon_flare"] = "Flare", + ["weapon_grenade"] = "Grenade", + ["weapon_petrolcan"] = "Jerrycan", + ["weapon_hazardcan"] = "Hazardous Jerrycan", + ["weapon_molotov"] = "Molotov Cocktail", + ["weapon_proxmine"] = "Proximity Mine", + ["weapon_pipebomb"] = "Pipe Bomb", + ["weapon_snowball"] = "Snowball", + ["weapon_stickybomb"] = "Sticky Bomb", + ["weapon_smokegrenade"] = "Tear Gas", + + -- Special + ["weapon_fireextinguisher"] = "Fire Extinguisher", + ["weapon_digiscanner"] = "Digital Scanner", + ["weapon_garbagebag"] = "Garbage Bag", + ["weapon_handcuffs"] = "Handcuffs", + ["gadget_nightvision"] = "Night Vision", + ["gadget_parachute"] = "parachute", + + -- Weapon Components + ["component_knuckle_base"] = "base Model", + ["component_knuckle_pimp"] = "the Pimp", + ["component_knuckle_ballas"] = "the Ballas", + ["component_knuckle_dollar"] = "the Hustler", + ["component_knuckle_diamond"] = "the Rock", + ["component_knuckle_hate"] = "the Hater", + ["component_knuckle_love"] = "the Lover", + ["component_knuckle_player"] = "the Player", + ["component_knuckle_king"] = "the King", + ["component_knuckle_vagos"] = "the Vagos", + + ["component_luxary_finish"] = "luxary Weapon Finish", + + ["component_handle_default"] = "default Handle", + ["component_handle_vip"] = "vIP Handle", + ["component_handle_bodyguard"] = "bodyguard Handle", + + ["component_vip_finish"] = "vIP Finish", + ["component_bodyguard_finish"] = "bodyguard Finish", + + ["component_camo_finish"] = "digital Camo", + ["component_camo_finish2"] = "brushstroke Camo", + ["component_camo_finish3"] = "woodland Camo", + ["component_camo_finish4"] = "skull Camo", + ["component_camo_finish5"] = "sessanta Nove Camo", + ["component_camo_finish6"] = "perseus Camo", + ["component_camo_finish7"] = "leopard Camo", + ["component_camo_finish8"] = "zebra Camo", + ["component_camo_finish9"] = "geometric Camo", + ["component_camo_finish10"] = "boom Camo", + ["component_camo_finish11"] = "patriotic Camo", + + ["component_camo_slide_finish"] = "digital Slide Camo", + ["component_camo_slide_finish2"] = "brushstroke Slide Camo", + ["component_camo_slide_finish3"] = "woodland Slide Camo", + ["component_camo_slide_finish4"] = "skull Slide Camo", + ["component_camo_slide_finish5"] = "sessanta Nove Slide Camo", + ["component_camo_slide_finish6"] = "perseus Slide Camo", + ["component_camo_slide_finish7"] = "leopard Slide Camo", + ["component_camo_slide_finish8"] = "zebra Slide Camo", + ["component_camo_slide_finish9"] = "geometric Slide Camo", + ["component_camo_slide_finish10"] = "boom Slide Camo", + ["component_camo_slide_finish11"] = "patriotic Slide Camo", + + ["component_clip_default"] = "default Magazine", + ["component_clip_extended"] = "extended Magazine", + ["component_clip_drum"] = "drum Magazine", + ["component_clip_box"] = "box Magazine", + + ["component_scope_holo"] = "holographic Scope", + ["component_scope_small"] = "small Scope", + ["component_scope_medium"] = "medium Scope", + ["component_scope_large"] = "large Scope", + ["component_scope"] = "mounted Scope", + ["component_scope_advanced"] = "advanced Scope", + ["component_ironsights"] = "ironsights", + + ["component_suppressor"] = "suppressor", + ["component_compensator"] = "compensator", + + ["component_muzzle_flat"] = "flat Muzzle Brake", + ["component_muzzle_tactical"] = "tactical Muzzle Brake", + ["component_muzzle_fat"] = "fat-End Muzzle Brake", + ["component_muzzle_precision"] = "precision Muzzle Brake", + ["component_muzzle_heavy"] = "heavy Duty Muzzle Brake", + ["component_muzzle_slanted"] = "slanted Muzzle Brake", + ["component_muzzle_split"] = "split-End Muzzle Brake", + ["component_muzzle_squared"] = "squared Muzzle Brake", + + ["component_flashlight"] = "flashlight", + ["component_grip"] = "grip", + + ["component_barrel_default"] = "default Barrel", + ["component_barrel_heavy"] = "heavy Barrel", + + ["component_ammo_tracer"] = "tracer Ammo", + ["component_ammo_incendiary"] = "incendiary Ammo", + ["component_ammo_hollowpoint"] = "hollowpoint Ammo", + ["component_ammo_fmj"] = "fMJ Ammo", + ["component_ammo_armor"] = "armor Piercing Ammo", + ["component_ammo_explosive"] = "armor Piercing Incendiary Ammo", + + ["component_shells_default"] = "default Shells", + ["component_shells_incendiary"] = "dragons Breath Shells", + ["component_shells_armor"] = "steel Buckshot Shells", + ["component_shells_hollowpoint"] = "flechette Shells", + ["component_shells_explosive"] = "explosive Slug Shells", + + -- Weapon Ammo + ["ammo_rounds"] = "round(s)", + ["ammo_shells"] = "shell(s)", + ["ammo_charge"] = "charge", + ["ammo_petrol"] = "gallons of fuel", + ["ammo_firework"] = "firework(s)", + ["ammo_rockets"] = "rocket(s)", + ["ammo_grenadelauncher"] = "grenade(s)", + ["ammo_grenade"] = "grenade(s)", + ["ammo_stickybomb"] = "bomb(s)", + ["ammo_pipebomb"] = "bomb(s)", + ["ammo_smokebomb"] = "bomb(s)", + ["ammo_molotov"] = "cocktail(s)", + ["ammo_proxmine"] = "mine(s)", + ["ammo_bzgas"] = "can(s)", + ["ammo_ball"] = "ball(s)", + ["ammo_snowball"] = "snowball(s)", + ["ammo_flare"] = "flare(s)", + ["ammo_flaregun"] = "flare(s)", + + -- Weapon Tints + ["tint_default"] = "default skin", + ["tint_green"] = "green skin", + ["tint_gold"] = "gold skin", + ["tint_pink"] = "pink skin", + ["tint_army"] = "army skin", + ["tint_lspd"] = "blue skin", + ["tint_orange"] = "orange skin", + ["tint_platinum"] = "platinum skin", + -- MK2 Weapon Tints + ["tint_classic_black"] = "klasična crna", + ["tint_classic_gray"] = "klasična siva", + ["tint_classic_two_tone"] = "klasična dvo-tonska", + ["tint_classic_white"] = "klasična bela", + ["tint_classic_beige"] = "klasična bež", + ["tint_classic_green"] = "klasična zelena", + ["tint_classic_blue"] = "klasična plava", + ["tint_classic_earth"] = "klasična zemlja", + ["tint_classic_brown_black"] = "klasična braon-crna", + ["tint_contrast_red"] = "kontrastna crvena", + ["tint_contrast_blue"] = "kontrastna plava", + ["tint_contrast_yellow"] = "kontrastna žuta", + ["tint_contrast_orange"] = "kontrastna narandžasta", + ["tint_bold_pink"] = "drska roze", + ["tint_bold_purple_yellow"] = "drska ljubičasto-žuta", + ["tint_bold_orange"] = "drska narandžasta", + ["tint_bold_green_purple"] = "drska zelena-ljubičasta", + ["tint_bold_red_feat"] = "drska crvena feat", + ["tint_bold_green_feat"] = "drska zelena feat", + ["tint_bold_cyan_feat"] = "drska cijan feat", + ["tint_bold_yellow_feat"] = "drska žuta feat", + ["tint_bold_red_white"] = "drska crvena bela", + ["tint_bold_blue_white"] = "drska plava bela", + ["tint_metallic_gold"] = "metalik zlatna", + ["tint_metallic_platinum"] = "metalik platina", + ["tint_metallic_gray_lilac"] = "metalik siva lila", + ["tint_metallic_purple_lime"] = "metalik ljubičasta limeta", + ["tint_metallic_red"] = "metalik crvena", + ["tint_metallic_green"] = "metalik zelena", + ["tint_metallic_blue"] = "metalik plava", + ["tint_metallic_white_aqua"] = "metalik bela aqua", + ["tint_metallic_red_yellow"] = "metalik crvena-žuta", +} diff --git a/resources/[core]/es_extended/locales/sv.lua b/resources/[core]/es_extended/locales/sv.lua new file mode 100644 index 0000000..ac05ff7 --- /dev/null +++ b/resources/[core]/es_extended/locales/sv.lua @@ -0,0 +1,415 @@ +return { + -- Inventory + ["inventory"] = "Inventory ( Vikt %s / %s )", + ["use"] = "Använd", + ["give"] = "Ge", + ["remove"] = "Kasta", + ["return"] = "Tillbaka", + ["give_to"] = "Ge", + ["amount"] = "Antal", + ["giveammo"] = "Ge skott", + ["amountammo"] = "Antal skott", + ["noammo"] = "Inte tillräckligt!", + ["gave_item"] = "Ger %sx %s till %s", + ["received_item"] = "Mottog %sx %s från %s", + ["gave_weapon"] = "Ger %s till %s", + ["gave_weapon_ammo"] = "Ger ~o~%sx %s för %s till %s", + ["gave_weapon_withammo"] = "Ger %s med ~o~%sx %s till %s", + ["gave_weapon_hasalready"] = "%s har redan en %s", + ["gave_weapon_noweapon"] = "%s har inte detta vapen", + ["received_weapon"] = "Mottog %s från %s", + ["received_weapon_ammo"] = "Mottog ~o~%sx %s för din %s från %s", + ["received_weapon_withammo"] = "Mottog %s med ~o~%sx %s från %s", + ["received_weapon_hasalready"] = "%s har försökt ge dig en %s, men du har redan detta", + ["received_weapon_noweapon"] = "%s har försökt ge dig skott till en %s, men du har inte detta vapen", + ["gave_account_money"] = "Ger %skr (%s) till %s", + ["received_account_money"] = "Mottog %skr (%s) från %s", + ["amount_invalid"] = "Ogiltig mängd", + ["players_nearby"] = "Inga spelare nära", + ["ex_inv_lim"] = "Kan inte utföra, överskrider maxvikten på %s", + ["imp_invalid_quantity"] = "Kan inte utföra, mängden är ogiltig", + ["imp_invalid_amount"] = "Kan inte utföra, antalet är ogiltig", + ["threw_standard"] = "Kastar %sx %s", + ["threw_account"] = "Kastar %skr %s", + ["threw_weapon"] = "Kastar %s", + ["threw_weapon_ammo"] = "Kastar %s med ~o~%sx %s", + ["threw_weapon_already"] = "Du har redan detta vapen", + ["threw_cannot_pickup"] = "Inventoryt är fullt, kan inte plocka upp!", + ["threw_pickup_prompt"] = "Tryck E för att plocka upp", + + -- Key mapping + ["keymap_showinventory"] = "Öppna inventory", + + -- Salary related + ["received_salary"] = "Du har fått ditt bidrag: %skr", + ["received_help"] = "Du har fått betalt: %skr", + ["company_nomoney"] = "Företaget du är anställd hos har inte råd med att betala ut lön", + ["received_paycheck"] = "Mottog lön", + ["bank"] = "Maze Bank", + ["account_bank"] = "Bank", + ["account_black_money"] = "Svarta pengar", + ["account_money"] = "Kontanter", + + ["act_imp"] = "Kan inte utföra", + ["in_vehicle"] = "Kan inte utföra, spelaren är i ett fordon", + ["not_in_vehicle"] = "Kan inte utföra, spelaren är inte i ett fordon", + + -- Commands + ["command_bring"] = "Ta en spelare till dig", + ["command_car"] = "Ta fram ett fordon", + ["command_car_car"] = "modell", + ["command_cardel"] = "Raderar fordon inom en specifik radie", + ["command_cardel_radius"] = "Raderar fordon inom en specifik radie", + ["command_repair"] = "Reparera ditt fordon", + ["command_repair_success"] = "Fordon reparerat", + ["command_repair_success_target"] = "En admin har reparerat ditt fordon", + ["command_clear"] = "Rensa chatt", + ["command_clearall"] = "Rensa chatt för alla", + ["command_clearinventory"] = "Raderar alla föremål från en spelares inventory", + ["command_clearloadout"] = "Raderar alla vapen från en spelares inventory", + ["command_freeze"] = "Frys en spelare", + ["command_unfreeze"] = "Ta bort frysningen från en spelare", + ["command_giveaccountmoney"] = "Ge pengar till ett specifikt konto", + ["command_giveaccountmoney_account"] = "Konto", + ["command_giveaccountmoney_amount"] = "Summa", + ["command_giveaccountmoney_invalid"] = "Ogiltigt kontonamn", + ["command_removeaccountmoney"] = "Radera pengar från ett specifikt konto", + ["command_removeaccountmoney_account"] = "Konto", + ["command_removeaccountmoney_amount"] = "Summa", + ["command_removeaccountmoney_invalid"] = "Ogiltigt kontonamn", + ["command_giveitem"] = "Ge föremål till en spelare", + ["command_giveitem_item"] = "Namn", + ["command_giveitem_count"] = "Antal", + ["command_giveweapon"] = "Ge ett vapen till en spelare", + ["command_giveweapon_weapon"] = "Vapen", + ["command_giveweapon_ammo"] = "Antal skott", + ["command_giveweapon_hasalready"] = "Spelaren har redan detta vapen", + ["command_giveweaponcomponent"] = "Ge komponent till en spelare", + ["command_giveweaponcomponent_component"] = "Komponent", + ["command_giveweaponcomponent_invalid"] = "Ogiltig komponent", + ["command_giveweaponcomponent_hasalready"] = "Spelaren har redan denna komponent", + ["command_giveweaponcomponent_missingweapon"] = "Spelaren har inte vapen för komponenten", + ["command_goto"] = "Teleportera till en spelare", + ["command_kill"] = "Döda en spelare", + ["command_save"] = "Spara en spelares data", + ["command_saveall"] = "Spara alla spelares data", + ["command_setaccountmoney"] = "Sätt pengar på ett specifikt konto", + ["command_setaccountmoney_amount"] = "Summa", + ["command_setcoords"] = "Teleportera till koordinater", + ["command_setcoords_x"] = "X value", + ["command_setcoords_y"] = "Y value", + ["command_setcoords_z"] = "Z value", + ["command_setjob"] = "Sätt jobb för en spelare", + ["command_setjob_job"] = "Namn", + ["command_setjob_grade"] = "Grad", + ["command_setjob_invalid"] = "Jobbet, graden eller båda är ogiltiga", + ["command_setgroup"] = "Sätt en spelares grupp", + ["command_setgroup_group"] = "Grupp", + ["commanderror_argumentmismatch"] = "Invalid Argument Count (passed %s, wanted %s)", + ["commanderror_argumentmismatch_number"] = "Invalid Argument #%s data type (passed string, wanted number)", + ["commanderror_argumentmismatch_string"] = "Invalid Argument #%s data type (passed number, wanted string)", + ["commanderror_argumentmismatch_positive_number"] = "Ogiltigt argument #%s datatyp (skickade negativt/noll, ville ha positivt tal)", + ["commanderror_invaliditem"] = "Ogiltigt föremål", + ["commanderror_invalidweapon"] = "Ogiltigt vapen", + ["commanderror_console"] = "Kommandot kan inte användas i konsolen", + ["commanderror_invalidcommand"] = "Ogiltigt kommand - /%s", + ["commanderror_invalidplayerid"] = "Spelaren är inte online", + ["commandgeneric_playerid"] = "Spelares ID", + ["command_giveammo_noweapon_found"] = "%s har inte detta vapen", + ["command_giveammo_weapon"] = "Vapen namn", + ["command_giveammo_ammo"] = "Antal ammo", + ["tpm_nowaypoint"] = "Ingen markör sutten.", + ["tpm_success"] = "Du har teleporterat", + + ["noclip_message"] = "Noclip har %s", + ["enabled"] = "~g~aktiverats~s~", + ["disabled"] = "~r~avaktiverats~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "%skr", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "Dolk", + ["weapon_bat"] = "Baseballträd", + ["weapon_battleaxe"] = "Stridsyxa", + ["weapon_bottle"] = "Glasflaska", + ["weapon_crowbar"] = "Kofot", + ["weapon_flashlight"] = "Ficklampa", + ["weapon_golfclub"] = "Golfklubba", + ["weapon_hammer"] = "Hammare", + ["weapon_hatchet"] = "Yxa", + ["weapon_knife"] = "Kniv", + ["weapon_knuckle"] = "Knogjärn", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Ficklampa", + ["weapon_wrench"] = "Rörtång", + ["weapon_poolcue"] = "Biljardkö", + ["weapon_stone_hatchet"] = "Stenyxa", + ["weapon_switchblade"] = "Fickkniv", + + -- Handguns + ["weapon_appistol"] = "AP Pistol", + ["weapon_ceramicpistol"] = "Ceramic Pistol", + ["weapon_combatpistol"] = "Combat Pistol", + ["weapon_doubleaction"] = "Double-Action Revolver", + ["weapon_navyrevolver"] = "Navy Revolver", + ["weapon_flaregun"] = "Flaregun", + ["weapon_gadgetpistol"] = "Gadget Pistol", + ["weapon_heavypistol"] = "Heavy Pistol", + ["weapon_revolver"] = "Heavy Revolver", + ["weapon_revolver_mk2"] = "Heavy Revolver MK2", + ["weapon_marksmanpistol"] = "Marksman Pistol", + ["weapon_pistol"] = "Pistol", + ["weapon_pistol_mk2"] = "Pistol MK2", + ["weapon_pistol50"] = "Pistol .50", + ["weapon_snspistol"] = "SNS Pistol", + ["weapon_snspistol_mk2"] = "SNS Pistol MK2", + ["weapon_stungun"] = "Taser", + ["weapon_raypistol"] = "Up-N-Atomizer", + ["weapon_vintagepistol"] = "Vintage Pistol", + + -- Shotguns + ["weapon_assaultshotgun"] = "Assault Shotgun", + ["weapon_autoshotgun"] = "Auto Shotgun", + ["weapon_bullpupshotgun"] = "Bullpup Shotgun", + ["weapon_combatshotgun"] = "Combat Shotgun", + ["weapon_dbshotgun"] = "Double Barrel Shotgun", + ["weapon_heavyshotgun"] = "Heavy Shotgun", + ["weapon_musket"] = "Musket", + ["weapon_pumpshotgun"] = "Pump Shotgun", + ["weapon_pumpshotgun_mk2"] = "Pump Shotgun MK2", + ["weapon_sawnoffshotgun"] = "Sawed Off Shotgun", + + -- SMG & LMG + ["weapon_assaultsmg"] = "Assault SMG", + ["weapon_combatmg"] = "Combat MG", + ["weapon_combatmg_mk2"] = "Combat MG MK2", + ["weapon_combatpdw"] = "Combat PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Machine Pistol", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Unholy Hellbringer", + + -- Rifles + ["weapon_advancedrifle"] = "Advanced Rifle", + ["weapon_assaultrifle"] = "Assault Rifle", + ["weapon_assaultrifle_mk2"] = "Assault Rifle MK2", + ["weapon_bullpuprifle"] = "Bullpup Rifle", + ["weapon_bullpuprifle_mk2"] = "Bullpup Rifle MK2", + ["weapon_carbinerifle"] = "Carbine Rifle", + ["weapon_carbinerifle_mk2"] = "Carbine Rifle MK2", + ["weapon_compactrifle"] = "Compact Rifle", + ["weapon_militaryrifle"] = "Military Rifle", + ["weapon_specialcarbine"] = "Special Carbine", + ["weapon_specialcarbine_mk2"] = "Special Carbine MK2", + ["weapon_heavyrifle"] = "Heavy Rifle", + + -- Sniper + ["weapon_heavysniper"] = "Heavy Sniper", + ["weapon_heavysniper_mk2"] = "Heavy Sniper MK2", + ["weapon_marksmanrifle"] = "Marksman Rifle", + ["weapon_marksmanrifle_mk2"] = "Marksman Rifle MK2", + ["weapon_sniperrifle"] = "Sniper Rifle", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "Compact Launcher", + ["weapon_firework"] = "Firework Launcher", + ["weapon_grenadelauncher"] = "Grenade Launcher", + ["weapon_hominglauncher"] = "Homing Launcher", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Railgun", + ["weapon_rpg"] = "Rocket Launcher", + ["weapon_rayminigun"] = "Widowmaker", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "Metal Detector", + ["weapon_precisionrifle"] = "Precision Rifle", + ["weapon_tactilerifle"] = "Service Carbine", + + -- Drug wars dlc + ["weapon_candycane"] = "Candycane", + ["weapon_acidpackage"] = "Acid Package", + ["weapon_pistolxm3"] = "Pistol8 x3m", + ["weapon_railgunxm3"] = "Railgun", + + -- Thrown + ["weapon_ball"] = "Baseball", + ["weapon_bzgas"] = "BZ Gas", + ["weapon_flare"] = "Bloss", + ["weapon_grenade"] = "Granat", + ["weapon_petrolcan"] = "Bensindunk", + ["weapon_hazardcan"] = "Hazardous Jerrycan", + ["weapon_molotov"] = "Molotov", + ["weapon_proxmine"] = "Mina", + ["weapon_pipebomb"] = "Pipe Bomb", + ["weapon_snowball"] = "Snöboll", + ["weapon_stickybomb"] = "Sticky Bomb", + ["weapon_smokegrenade"] = "Tårgas", + + -- Special + ["weapon_fireextinguisher"] = "Brandsläckare", + ["weapon_digiscanner"] = "Digital Scanner", + ["weapon_garbagebag"] = "Soppåse", + ["weapon_handcuffs"] = "Handklovar", + ["gadget_nightvision"] = "Night Vision", + ["gadget_parachute"] = "Fallskärm", + + -- Weapon Components + ["component_knuckle_base"] = "base Model", + ["component_knuckle_pimp"] = "the Pimp", + ["component_knuckle_ballas"] = "the Ballas", + ["component_knuckle_dollar"] = "the Hustler", + ["component_knuckle_diamond"] = "the Rock", + ["component_knuckle_hate"] = "the Hater", + ["component_knuckle_love"] = "the Lover", + ["component_knuckle_player"] = "the Player", + ["component_knuckle_king"] = "the King", + ["component_knuckle_vagos"] = "the Vagos", + + ["component_luxary_finish"] = "luxary Weapon Finish", + + ["component_handle_default"] = "default Handle", + ["component_handle_vip"] = "vIP Handle", + ["component_handle_bodyguard"] = "bodyguard Handle", + + ["component_vip_finish"] = "vIP Finish", + ["component_bodyguard_finish"] = "bodyguard Finish", + + ["component_camo_finish"] = "digital Camo", + ["component_camo_finish2"] = "brushstroke Camo", + ["component_camo_finish3"] = "woodland Camo", + ["component_camo_finish4"] = "skull Camo", + ["component_camo_finish5"] = "sessanta Nove Camo", + ["component_camo_finish6"] = "perseus Camo", + ["component_camo_finish7"] = "leopard Camo", + ["component_camo_finish8"] = "zebra Camo", + ["component_camo_finish9"] = "geometric Camo", + ["component_camo_finish10"] = "boom Camo", + ["component_camo_finish11"] = "patriotic Camo", + + ["component_camo_slide_finish"] = "digital Slide Camo", + ["component_camo_slide_finish2"] = "brushstroke Slide Camo", + ["component_camo_slide_finish3"] = "woodland Slide Camo", + ["component_camo_slide_finish4"] = "skull Slide Camo", + ["component_camo_slide_finish5"] = "sessanta Nove Slide Camo", + ["component_camo_slide_finish6"] = "perseus Slide Camo", + ["component_camo_slide_finish7"] = "leopard Slide Camo", + ["component_camo_slide_finish8"] = "zebra Slide Camo", + ["component_camo_slide_finish9"] = "geometric Slide Camo", + ["component_camo_slide_finish10"] = "boom Slide Camo", + ["component_camo_slide_finish11"] = "patriotic Slide Camo", + + ["component_clip_default"] = "default Magazine", + ["component_clip_extended"] = "extended Magazine", + ["component_clip_drum"] = "drum Magazine", + ["component_clip_box"] = "box Magazine", + + ["component_scope_holo"] = "holographic Scope", + ["component_scope_small"] = "small Scope", + ["component_scope_medium"] = "medium Scope", + ["component_scope_large"] = "large Scope", + ["component_scope"] = "mounted Scope", + ["component_scope_advanced"] = "advanced Scope", + ["component_ironsights"] = "ironsights", + + ["component_suppressor"] = "ljuddämpare", + ["component_compensator"] = "compensator", + + ["component_muzzle_flat"] = "flat Muzzle Brake", + ["component_muzzle_tactical"] = "tactical Muzzle Brake", + ["component_muzzle_fat"] = "fat-End Muzzle Brake", + ["component_muzzle_precision"] = "precision Muzzle Brake", + ["component_muzzle_heavy"] = "heavy Duty Muzzle Brake", + ["component_muzzle_slanted"] = "slanted Muzzle Brake", + ["component_muzzle_split"] = "split-End Muzzle Brake", + ["component_muzzle_squared"] = "squared Muzzle Brake", + + ["component_flashlight"] = "Ficklampa", + ["component_grip"] = "grepp", + + ["component_barrel_default"] = "default Barrel", + ["component_barrel_heavy"] = "heavy Barrel", + + ["component_ammo_tracer"] = "tracer Ammo", + ["component_ammo_incendiary"] = "incendiary Ammo", + ["component_ammo_hollowpoint"] = "hollowpoint Ammo", + ["component_ammo_fmj"] = "fMJ Ammo", + ["component_ammo_armor"] = "armor Piercing Ammo", + ["component_ammo_explosive"] = "armor Piercing Incendiary Ammo", + + ["component_shells_default"] = "default Shells", + ["component_shells_incendiary"] = "dragons Breath Shells", + ["component_shells_armor"] = "steel Buckshot Shells", + ["component_shells_hollowpoint"] = "flechette Shells", + ["component_shells_explosive"] = "explosive Slug Shells", + + -- Weapon Ammo + ["ammo_rounds"] = "round(s)", + ["ammo_shells"] = "shell(s)", + ["ammo_charge"] = "charge", + ["ammo_petrol"] = "gallons of fuel", + ["ammo_firework"] = "firework(s)", + ["ammo_rockets"] = "rocket(s)", + ["ammo_grenadelauncher"] = "grenade(s)", + ["ammo_grenade"] = "grenade(s)", + ["ammo_stickybomb"] = "bomb(s)", + ["ammo_pipebomb"] = "bomb(s)", + ["ammo_smokebomb"] = "bomb(s)", + ["ammo_molotov"] = "cocktail(s)", + ["ammo_proxmine"] = "mine(s)", + ["ammo_bzgas"] = "can(s)", + ["ammo_ball"] = "ball(s)", + ["ammo_snowball"] = "snowball(s)", + ["ammo_flare"] = "flare(s)", + ["ammo_flaregun"] = "flare(s)", + + -- Weapon Tints + ["tint_default"] = "default skin", + ["tint_green"] = "green skin", + ["tint_gold"] = "gold skin", + ["tint_pink"] = "pink skin", + ["tint_army"] = "army skin", + ["tint_lspd"] = "blue skin", + ["tint_orange"] = "orange skin", + ["tint_platinum"] = "platinum skin", + -- MK2 Weapon Tints + ["tint_classic_black"] = "klassisk svart", + ["tint_classic_gray"] = "klassisk grå", + ["tint_classic_two_tone"] = "klassisk tvåfärgad", + ["tint_classic_white"] = "klassisk vit", + ["tint_classic_beige"] = "klassisk beige", + ["tint_classic_green"] = "klassisk grön", + ["tint_classic_blue"] = "klassisk blå", + ["tint_classic_earth"] = "klassisk jord", + ["tint_classic_brown_black"] = "klassisk brun svart", + ["tint_contrast_red"] = "kontrast röd", + ["tint_contrast_blue"] = "kontrast blå", + ["tint_contrast_yellow"] = "kontrast gul", + ["tint_contrast_orange"] = "kontrast orange", + ["tint_bold_pink"] = "djärv rosa", + ["tint_bold_purple_yellow"] = "djärv lila gul", + ["tint_bold_orange"] = "djärv orange", + ["tint_bold_green_purple"] = "djärv grön lila", + ["tint_bold_red_feat"] = "djärv röd feat", + ["tint_bold_green_feat"] = "djärv grön feat", + ["tint_bold_cyan_feat"] = "djärv cyan feat", + ["tint_bold_yellow_feat"] = "djärv gul feat", + ["tint_bold_red_white"] = "djärv röd vit", + ["tint_bold_blue_white"] = "djärv blå vit", + ["tint_metallic_gold"] = "metalliskt guld", + ["tint_metallic_platinum"] = "metalliskt platina", + ["tint_metallic_gray_lilac"] = "metalliskt grå lila", + ["tint_metallic_purple_lime"] = "metalliskt lila lime", + ["tint_metallic_red"] = "metalliskt röd", + ["tint_metallic_green"] = "metalliskt grön", + ["tint_metallic_blue"] = "metalliskt blå", + ["tint_metallic_white_aqua"] = "metalliskt vitt aqua", + ["tint_metallic_red_yellow"] = "metalliskt röd gul", +} diff --git a/resources/[core]/es_extended/locales/tr.lua b/resources/[core]/es_extended/locales/tr.lua new file mode 100644 index 0000000..5157e29 --- /dev/null +++ b/resources/[core]/es_extended/locales/tr.lua @@ -0,0 +1,382 @@ +return { + -- Inventory + ["inventory"] = "Envanter ( Ağırlık %s / %s )", + ["use"] = "Kullan", + ["give"] = "Ver", + ["remove"] = "At", + ["return"] = "Geri Ver", + ["give_to"] = "Şuna Ver", + ["amount"] = "Miktar", + ["giveammo"] = "Mermi Ver", + ["amountammo"] = "Mermi Miktarı", + ["noammo"] = "Yeterli Değil!", + ["gave_item"] = "Verilen %sx %s %s'ye", + ["received_item"] = "Alınan %sx %s %s'den", + ["gave_weapon"] = "Verilen %s %s'ye", + ["gave_weapon_ammo"] = "Verilen ~o~%sx %s %s için %s'ye", + ["gave_weapon_withammo"] = "Verilen %s ile ~o~%sx %s %s'ye", + ["gave_weapon_hasalready"] = "%s Zaten Bir %s Sahip", + ["gave_weapon_noweapon"] = "%s O Silahı Sahip Değil", + ["received_weapon"] = "%s'den %s Alındı", + ["received_weapon_ammo"] = "%s'den %s için ~o~%sx %s Alındı", + ["received_weapon_withammo"] = "%s'den %s ile ~o~%sx %s Alındı", + ["received_weapon_hasalready"] = "%s Size Bir %s Vermeye Çalıştı, Ama Zaten Bu Silahınız Var", + ["received_weapon_noweapon"] = "%s Size Bir %s İçin Mermi Vermeye Çalıştı, Ama Bu Silaha Sahip Değilsiniz", + ["gave_account_money"] = "Verilen $%s (%s) %s'ye", + ["received_account_money"] = "Alınan $%s (%s) %s'den", + ["amount_invalid"] = "Geçersiz Miktar", + ["players_nearby"] = "Yakınlarda Hiçbir Oyuncu Yok", + ["ex_inv_lim"] = "İşlem Yapılamaz, %s Ağırlık Sınırı Aşıldı", + ["imp_invalid_quantity"] = "İşlem Yapılamaz, Miktar Geçersiz", + ["imp_invalid_amount"] = "İşlem Yapılamaz, Miktar Geçersiz", + ["threw_standard"] = "Atılan %sx %s", + ["threw_account"] = "Atılan $%s %s", + ["threw_weapon"] = "Atılan %s", + ["threw_weapon_ammo"] = "Atılan %s ile ~o~%sx %s", + ["threw_weapon_already"] = "Bu Silaha Zaten Sahipsiniz", + ["threw_cannot_pickup"] = "Envanter Dolu, Alınamaz!", + ["threw_pickup_prompt"] = "Almak İçin E'ye Basın", + + -- Key mapping + ["keymap_showinventory"] = "Envanteri Göster", + + -- Salary related + ["received_salary"] = "Maaşınız Ödendi: $%s", + ["received_help"] = "Yardım Çekiniz Ödendi: $%s", + ["company_nomoney"] = "Çalıştığınız Şirket Maaşınızı Ödeyebilecek Kadar Zengin Değil", + ["received_paycheck"] = "Maaş Alındı", + ["bank"] = "Maze Bank", + ["account_bank"] = "Banka", + ["account_black_money"] = "Kirli Para", + ["account_money"] = "Nakit", + + ["act_imp"] = "İşlem Yapılamaz", + ["in_vehicle"] = "İşlem Yapılamaz, Oyuncu Araçta", + ["not_in_vehicle"] = "İşlem Yapılamaz, Oyuncu Araçta Değil", + + -- Commands + ["command_bring"] = "Oyuncuyu Yanınıza Getir", + ["command_car"] = "Araç Spawn Et", + ["command_car_car"] = "Araç Modeli veya Hash", + ["command_cardel"] = "Yakınlardaki Araçları Kaldır", + ["command_cardel_radius"] = "Belirtilen Yarıçap İçindeki Tüm Araçları Kaldırır", + ["command_repair"] = "Araçınızı Onarın", + ["command_repair_success"] = "Araç Başarıyla Onarıldı", + ["command_repair_success_target"] = "Bir Yönetici Araçınızı Onardı", + ["command_clear"] = "Sohbeti Temizle", + ["command_clearall"] = "Tüm Oyuncular İçin Sohbeti Temizle", + ["command_clearinventory"] = "Oyuncunun Envanterindeki Tüm Eşyaları Kaldır", + ["command_clearloadout"] = "Oyuncunun Yükündeki Tüm Silahları Kaldır", + ["command_freeze"] = "Bir Oyuncuyu Dondur", + ["command_unfreeze"] = "Bir Oyuncunun Dondurmasını Kaldır", + ["command_giveaccountmoney"] = "Bir Hesaba Para Ver", + ["command_giveaccountmoney_account"] = "Ekleme Yapılacak Hesap", + ["command_giveaccountmoney_amount"] = "Eklemek İçin Miktar", + ["command_giveaccountmoney_invalid"] = "Hesap Adı Geçersiz", + ["command_removeaccountmoney"] = "Bir Hesaptan Para Çek", + ["command_removeaccountmoney_account"] = "Çekilecek Hesap", + ["command_removeaccountmoney_amount"] = "Çekilecek Miktar", + ["command_removeaccountmoney_invalid"] = "Hesap Adı Geçersiz", + ["command_giveitem"] = "Oyuncuya Eşya Ver", + ["command_giveitem_item"] = "Eşya Adı", + ["command_giveitem_count"] = "Miktar", + ["command_giveweapon"] = "Oyuncuya Silah Ver", + ["command_giveweapon_weapon"] = "Silah Adı", + ["command_giveweapon_ammo"] = "Mermi Miktarı", + ["command_giveweapon_hasalready"] = "Oyuncu Zaten Bu Silaha Sahip", + ["command_giveweaponcomponent"] = "Oyuncuya Silah Parçası Ver", + ["command_giveweaponcomponent_component"] = "Parça Adı", + ["command_giveweaponcomponent_invalid"] = "Geçersiz Silah Parçası", + ["command_giveweaponcomponent_hasalready"] = "Oyuncu Zaten Bu Silah Parçasına Sahip", + ["command_giveweaponcomponent_missingweapon"] = "Oyuncu Bu Silaha Sahip Değil", + ["command_goto"] = "Kendinizi Bir Oyuncuya Teleport Et", + ["command_kill"] = "Bir Oyuncuyu Öldür", + ["command_save"] = "Bir Oyuncunun Verilerini Zorla Kaydet", + ["command_saveall"] = "Tüm Oyuncu Verilerini Zorla Kaydet", + ["command_setaccountmoney"] = "Bir Hesaptaki Parayı Ayarla", + ["command_setaccountmoney_amount"] = "Miktar", + ["command_setcoords"] = "Belirtilen Koordinatlara Teleport Ol", + ["command_setcoords_x"] = "X Değeri", + ["command_setcoords_y"] = "Y Değeri", + ["command_setcoords_z"] = "Z Değeri", + ["command_setjob"] = "Bir Oyuncunun Mesleğini Ayarla", + ["command_setjob_job"] = "Adı", + ["command_setjob_grade"] = "Meslek Derecesi", + ["command_setjob_invalid"] = "Meslek, Derece veya Her Ikisi Geçersiz", + ["command_setgroup"] = "Bir Oyuncunun Yetki Grubunu Ayarla", + ["command_setgroup_group"] = "Grup Adı", + ["commanderror_argumentmismatch"] = "Geçersiz Argüman Sayısı (Verilen %s, İstenen %s)", + ["commanderror_argumentmismatch_number"] = "Geçersiz Argüman #%s Veri Tipi (Verilen Metin, İstenen Sayı)", + ["commanderror_argumentmismatch_string"] = "Geçersiz Argüman #%s Veri Tipi (Verilen Sayı, İstenen Metin)", + ["commanderror_argumentmismatch_positive_number"] = "Geçersiz Argüman #%s Veri Tipi (Verilen Negatif/Sıfır, İstenen Pozitif Sayı)", + ["commanderror_invaliditem"] = "Geçersiz Eşya", + ["commanderror_invalidweapon"] = "Geçersiz Silah", + ["commanderror_console"] = "Komut Konsoldan Çalıştırılamaz", + ["commanderror_invalidcommand"] = "Geçersiz Komut - /%s", + ["commanderror_invalidplayerid"] = "Belirtilen Oyuncu Çevrimdışı", + ["commandgeneric_playerid"] = "Oyuncunun Sunucu ID'si", + ["command_giveammo_noweapon_found"] = "%s O Silaha Sahip Değil", + ["command_giveammo_weapon"] = "Silah Adı", + ["command_giveammo_ammo"] = "Mermi Miktarı", + ["tpm_nowaypoint"] = "Hiçbir Yol İşareti Ayarlanmadı.", + ["tpm_success"] = "Başarıyla Teleport Edildi", + + ["noclip_message"] = "Noclip %s Yapıldı", + ["enabled"] = "~g~Aktif Edildi~s~", + ["disabled"] = "~r~Pasif Edildi~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "£%s", + + -- Silahlar + + -- Melee + ["weapon_dagger"] = "Kılıç", + ["weapon_bat"] = "Sopa", + ["weapon_battleaxe"] = "Savaş Balta", + ["weapon_bottle"] = "Şişe", + ["weapon_crowbar"] = "Kaldıraç", + ["weapon_flashlight"] = "Fener", + ["weapon_golfclub"] = "Golf Sopası", + ["weapon_hammer"] = "Çekiç", + ["weapon_hatchet"] = "Balta", + ["weapon_knife"] = "Bıçak", + ["weapon_knuckle"] = "Düğmeli Eldiven", + ["weapon_machete"] = "Machete", + ["weapon_nightstick"] = "Gece Dürbünü", + ["weapon_wrench"] = "Anahtar", + ["weapon_poolcue"] = "Havuz Sopası", + ["weapon_stone_hatchet"] = "Taş Balta", + ["weapon_switchblade"] = "Dönme Bıçağı", + + -- Tabancalar + ["weapon_appistol"] = "AP Tabancası", + ["weapon_ceramicpistol"] = "Seramik Tabanca", + ["weapon_combatpistol"] = "Savaş Tabancası", + ["weapon_doubleaction"] = "Çift Aksiyonlu Tabanca", + ["weapon_navyrevolver"] = "Donanma Revolveri", + ["weapon_flaregun"] = "Işık Fişeği Tabancası", + ["weapon_gadgetpistol"] = "Cihaz Tabancası", + ["weapon_heavypistol"] = "Ağır Tabanca", + ["weapon_revolver"] = "Revolver", + ["weapon_revolver_mk2"] = "Revolver MK2", + ["weapon_marksmanpistol"] = "Nişancı Tabancası", + ["weapon_pistol"] = "Tabanca", + ["weapon_pistol_mk2"] = "Tabanca MK2", + ["weapon_pistol50"] = "Tabanca .50", + ["weapon_snspistol"] = "SNS Tabancası", + ["weapon_snspistol_mk2"] = "SNS Tabancası MK2", + ["weapon_stungun"] = "Elektrik Tabancası", + ["weapon_raypistol"] = "Atomizer Tabancası", + ["weapon_vintagepistol"] = "Vintage Tabanca", + + -- Av Tüfekleri + ["weapon_assaultshotgun"] = "Saldırı Tüfeği", + ["weapon_autoshotgun"] = "Otomatik Tüfek", + ["weapon_bullpupshotgun"] = "Bullpup Tüfeği", + ["weapon_combatshotgun"] = "Savaş Tüfeği", + ["weapon_dbshotgun"] = "Çift Namlu Tüfeği", + ["weapon_heavyshotgun"] = "Ağır Tüfek", + ["weapon_musket"] = "Tüfek", + ["weapon_pumpshotgun"] = "Pompalı Tüfek", + ["weapon_pumpshotgun_mk2"] = "Pompalı Tüfek MK2", + ["weapon_sawnoffshotgun"] = "Kısa Namlu Tüfek", + + -- SMG ve LMG + ["weapon_assaultsmg"] = "Saldırı SMG", + ["weapon_combatmg"] = "Savaş MG", + ["weapon_combatmg_mk2"] = "Savaş MG MK2", + ["weapon_combatpdw"] = "Savaş PDW", + ["weapon_gusenberg"] = "Gusenberg Sweeper", + ["weapon_machinepistol"] = "Makine Tabancası", + ["weapon_mg"] = "MG", + ["weapon_microsmg"] = "Micro SMG", + ["weapon_minismg"] = "Mini SMG", + ["weapon_smg"] = "SMG", + ["weapon_smg_mk2"] = "SMG MK2", + ["weapon_raycarbine"] = "Unholy Hellbringer", + + -- Tüfekler + ["weapon_advancedrifle"] = "İleri Düzey Tüfeği", + ["weapon_assaultrifle"] = "Saldırı Tüfeği", + ["weapon_assaultrifle_mk2"] = "Saldırı Tüfeği MK2", + ["weapon_bullpuprifle"] = "Bullpup Tüfeği", + ["weapon_bullpuprifle_mk2"] = "Bullpup Tüfeği MK2", + ["weapon_carbinerifle"] = "Carbine Tüfeği", + ["weapon_carbinerifle_mk2"] = "Carbine Tüfeği MK2", + ["weapon_compactrifle"] = "Komple Tüfek", + ["weapon_militaryrifle"] = "Askeri Tüfek", + ["weapon_specialcarbine"] = "Özel Carbine", + ["weapon_specialcarbine_mk2"] = "Özel Carbine MK2", + ["weapon_heavyrifle"] = "Ağır Tüfek", + + -- Keskin Nişancı + ["weapon_heavysniper"] = "Ağır Keskin Nişancı", + ["weapon_heavysniper_mk2"] = "Ağır Keskin Nişancı MK2", + ["weapon_marksmanrifle"] = "Keskin Nişancı Tüfeği", + ["weapon_marksmanrifle_mk2"] = "Keskin Nişancı Tüfeği MK2", + ["weapon_sniperrifle"] = "Keskin Nişancı Tüfeği", + + -- Ağır / Roket Atıcılar + ["weapon_compactlauncher"] = "Kompakt Roket Atıcı", + ["weapon_firework"] = "Havai Fişek Atıcı", + ["weapon_grenadelauncher"] = "El Bombası Atıcı", + ["weapon_hominglauncher"] = "Hedefli Roket Atıcı", + ["weapon_minigun"] = "Minigun", + ["weapon_railgun"] = "Raylı Silah", + ["weapon_rpg"] = "Roket Atıcı", + ["weapon_rayminigun"] = "Widowmaker", + + -- Suçlu Girişimleri DLC + ["weapon_metaldetector"] = "Metal Dedektörü", + ["weapon_precisionrifle"] = "Keskin Nişancı Tüfeği", + ["weapon_tactilerifle"] = "Hizmet Karabina", + + -- Uyuşturucu Savaşları DLC + ["weapon_candycane"] = "Şeker Kamışı", + ["weapon_acidpackage"] = "Asit Paketi", + ["weapon_pistolxm3"] = "Pistol8 x3m", + ["weapon_railgunxm3"] = "Raylı Silah", + + -- Atılan Silahlar + ["weapon_ball"] = "Beyzbol Topu", + ["weapon_bzgas"] = "BZ Gazı", + ["weapon_flare"] = "Duman Fişeği", + ["weapon_grenade"] = "El Bombası", + ["weapon_petrolcan"] = "Petrol Bidonu", + ["weapon_hazardcan"] = "Tehlikeli Bidon", + ["weapon_molotov"] = "Molotof Kokteyli", + ["weapon_proxmine"] = "Yakınlık Mayını", + ["weapon_pipebomb"] = "Boru Bombası", + ["weapon_snowball"] = "Karla Bombası", + ["weapon_stickybomb"] = "Yapışkan Bomba", + ["weapon_smokegrenade"] = "Gözyaşı Gazı", + + -- Özel + ["weapon_fireextinguisher"] = "Yangın Söndürücü", + ["weapon_digiscanner"] = "Dijital Tarayıcı", + ["weapon_garbagebag"] = "Çöp Torbası", + ["weapon_handcuffs"] = "Kelepçe", + ["gadget_nightvision"] = "Gece Görüşü", + ["gadget_parachute"] = "Paraşüt", + + -- Silah Bileşenleri + ["component_knuckle_base"] = "Temel Model", + ["component_knuckle_pimp"] = "Fahişe", + ["component_knuckle_ballas"] = "Ballas", + ["component_knuckle_dollar"] = "Hustler", + ["component_knuckle_diamond"] = "Elmas", + ["component_knuckle_hate"] = "Nefret", + ["component_knuckle_love"] = "Aşk", + ["component_knuckle_player"] = "Oyuncu", + ["component_knuckle_king"] = "Kral", + ["component_knuckle_vagos"] = "Vagos", + + ["component_luxary_finish"] = "Lüks Silah Kaplama", + + ["component_handle_default"] = "Varsayılan Sap", + ["component_handle_vip"] = "VIP Sap", + ["component_handle_bodyguard"] = "Vücut Koruma Sapı", + + ["component_vip_finish"] = "VIP Kaplama", + ["component_bodyguard_finish"] = "Vücut Koruma Kaplaması", + + ["component_camo_finish"] = "Dijital Kamuflaj", + ["component_camo_finish2"] = "Fırçalama Kamuflaj", + ["component_camo_finish3"] = "Orman Kamuflajı", + ["component_camo_finish4"] = "Kafatası Kamuflajı", + ["component_camo_finish5"] = "Sessanta Nove Kamuflajı", + ["component_camo_finish6"] = "Perseus Kamuflajı", + ["component_camo_finish7"] = "Leopar Kamuflajı", + ["component_camo_finish8"] = "Zebra Kamuflajı", + ["component_camo_finish9"] = "Geometrik Kamuflaj", + ["component_camo_finish10"] = "Boom Kamuflajı", + ["component_camo_finish11"] = "Patriot Kamuflajı", + + ["component_camo_slide_finish"] = "Dijital Kayma Kamuflajı", + ["component_camo_slide_finish2"] = "Fırçalama Kayma Kamuflajı", + ["component_camo_slide_finish3"] = "Orman Kayma Kamuflajı", + ["component_camo_slide_finish4"] = "Kafatası Kayma Kamuflajı", + ["component_camo_slide_finish5"] = "Sessanta Nove Kayma Kamuflajı", + ["component_camo_slide_finish6"] = "Perseus Kayma Kamuflajı", + ["component_camo_slide_finish7"] = "Leopar Kayma Kamuflajı", + ["component_camo_slide_finish8"] = "Zebra Kayma Kamuflajı", + ["component_camo_slide_finish9"] = "Geometrik Kayma Kamuflajı", + ["component_camo_slide_finish10"] = "Boom Kayma Kamuflajı", + ["component_camo_slide_finish11"] = "Patriot Kayma Kamuflajı", + + ["component_clip_default"] = "Varsayılan Şarjör", + ["component_clip_extended"] = "Uzun Şarjör", + ["component_clip_drum"] = "Davul Şarjör", + ["component_clip_box"] = "Kutu Şarjör", + + ["component_scope_holo"] = "Holografik Dürbün", + ["component_scope_small"] = "Küçük Dürbün", + ["component_scope_medium"] = "Orta Dürbün", + ["component_scope_large"] = "Büyük Dürbün", + ["component_scope"] = "Montelenmiş Dürbün", + ["component_scope_advanced"] = "İleri Seviye Dürbün", + ["component_ironsights"] = "Nişangah", + + ["component_suppressor"] = "Susturucu", + ["component_compensator"] = "Dengeleyici", + + ["component_muzzle_flat"] = "Düz Namlu Freni", + ["component_muzzle_tactical"] = "Taktiksel Namlu Freni", + ["component_muzzle_fat"] = "Geniş Uçlu Namlu Freni", + ["component_muzzle_precision"] = "Hassas Namlu Freni", + ["component_muzzle_heavy"] = "Ağır Namlu Freni", + ["component_muzzle_slanted"] = "Eğik Namlu Freni", + ["component_muzzle_split"] = "Bölünmüş Namlu Freni", + ["component_muzzle_squared"] = "Kare Namlu Freni", + + ["component_flashlight"] = "Fener", + ["component_grip"] = "Tutamak", + + ["component_barrel_default"] = "Varsayılan Namlu", + ["component_barrel_heavy"] = "Ağır Namlu", + + ["component_ammo_tracer"] = "Işık İzli Mühimmat", + ["component_ammo_incendiary"] = "Alev Alıcı Mühimmat", + ["component_ammo_hollowpoint"] = "Hollowpoint Mühimmat", + ["component_ammo_fmj"] = "FMJ Mühimmat", + ["component_ammo_armor"] = "Zırh Delici Mühimmat", + ["component_ammo_explosive"] = "Zırh Delici Alev Alıcı Mühimmat", + + ["component_shells_default"] = "Varsayılan Mühimmat", + ["component_shells_incendiary"] = "Dragon's Breath Mühimmatı", + ["component_shells_armor"] = "Çelik Buckshot Mühimmat", + ["component_shells_hollowpoint"] = "Flechette Mühimmat", + ["component_shells_explosive"] = "Patlayıcı Slug Mühimmat", + + -- Silah Mermileri + ["ammo_rounds"] = "Dişli(ler)", + ["ammo_shells"] = "Kovan(lar)", + ["ammo_charge"] = "Şarjör", + ["ammo_petrol"] = "Yakıt Galonları", + ["ammo_firework"] = "Havai Fişek(ler)", + ["ammo_rockets"] = "Roket(ler)", + ["ammo_grenadelauncher"] = "El Bombası(ları)", + ["ammo_grenade"] = "El Bombası(ları)", + ["ammo_stickybomb"] = "Bomba(lar)", + ["ammo_pipebomb"] = "Bomba(lar)", + ["ammo_smokebomb"] = "Bomba(lar)", + ["ammo_molotov"] = "Molotof Kokteyli(leri)", + ["ammo_proxmine"] = "Mayın(lar)", + ["ammo_bzgas"] = "Kutu(lar)", + ["ammo_ball"] = "Top(lar)", + ["ammo_snowball"] = "Kar Topu(ları)", + ["ammo_flare"] = "Duman Fişek(leri)", + ["ammo_flaregun"] = "Duman Fişek(leri)", + + -- Silah Renkleri + ["tint_default"] = "Varsayılan Kaplama", + ["tint_green"] = "Yeşil Kaplama", + ["tint_gold"] = "Altın Kaplama", + ["tint_pink"] = "Pembe Kaplama", + ["tint_army"] = "Ordu Kaplaması", + ["tint_lspd"] = "Mavi Kaplama", + ["tint_orange"] = "Turuncu Kaplama", + ["tint_platinum"] = "Platin Kaplama", +} diff --git a/resources/[core]/es_extended/locales/zh-cn.lua b/resources/[core]/es_extended/locales/zh-cn.lua new file mode 100644 index 0000000..4f55db7 --- /dev/null +++ b/resources/[core]/es_extended/locales/zh-cn.lua @@ -0,0 +1,426 @@ +return { + -- Inventory + ["inventory"] = "物品栏 (负重 %s / %s)", + ["use"] = "使用", + ["give"] = "赠予", + ["remove"] = "丢弃", + ["return"] = "返回", + ["give_to"] = "赠予目标", + ["amount"] = "数量", + ["giveammo"] = "赠予弹药", + ["amountammo"] = "弹药数量", + ["noammo"] = "弹药不足!", + ["gave_item"] = "您将 %s 个 %s 赠予给 %s", + ["received_item"] = "您收到 %s 个 %s, 由 %s 的赠予", + ["gave_weapon"] = "您将 %s 赠予给 %s", + ["gave_weapon_ammo"] = "您将 ~o~%s 发 %s %s 赠予 %s", + ["gave_weapon_withammo"] = "您把 %s 及 ~o~%s 发 %s 赠予 %s", + ["gave_weapon_hasalready"] = "%s 已拥有 %s", + ["gave_weapon_noweapon"] = "%s 未拥有该武器", + ["received_weapon"] = "您收到 %s, 由 %s 赠", + ["received_weapon_ammo"] = "您收到 ~o~%s 发 %s 的%s, 由 %s 赠予", + ["received_weapon_withammo"] = "您收到 %s 及 ~o~%s 发 %s, 由 %s 赠予", + ["received_weapon_hasalready"] = "%s 试图赠予您 %s, 但您已拥有", + ["received_weapon_noweapon"] = "%s 试图赠予您 %s 发弹药, 但您未装备该武器", + ["gave_account_money"] = "您将 ¥%s (%s) 转账至 %s", + ["received_account_money"] = "您收到 ¥%s (%s), 由 %s 转账", + ["amount_invalid"] = "无效数量", + ["players_nearby"] = "附近暂无其他人员", + ["ex_inv_lim"] = "操作失败: 超过最大负重限制 (%s)", + ["imp_invalid_quantity"] = "操作失败: 无效数量输入", + ["imp_invalid_amount"] = "操作失败: 无效金额输入", + ["threw_standard"] = "您已丢弃 %s 个 %s", + ["threw_account"] = "您已丢弃 ¥%s 笔 %s", + ["threw_weapon"] = "您已丢弃武器 %s", + ["threw_weapon_ammo"] = "您已丢弃 %s 及其 ~o~%s 发 %s", + ["threw_weapon_already"] = "您已持有相同武器!", + ["threw_cannot_pickup"] = "物品栏已满, 无法拾取!", + ["threw_pickup_prompt"] = "键下 [E] 拾取", + + -- Key mapping + ["keymap_showinventory"] = "显示物品栏", + + -- Salary related + ["received_salary"] = "您已收到工资: ¥%s", + ["received_help"] = "您已领取补助金: ¥%s", + ["company_nomoney"] = "雇佣方资金不足, 无法支付薪资", + ["received_paycheck"] = "工资到账", + ["bank"] = "梅兹银行", + ["account_bank"] = "银行账户", + ["account_black_money"] = "赃款", + ["account_money"] = "现金", + + ["act_imp"] = "无法执行该操作", + ["in_vehicle"] = "目标处于载具中, 操作中止", + ["not_in_vehicle"] = "目标未在载具内, 操作中止", + + -- Commands + ["command_bring"] = "将目标玩家传送至当前位置", + ["command_car"] = "生成指定载具", + ["command_car_car"] = "载具模型名称或哈希值", + ["command_cardel"] = "删除邻近载具", + ["command_cardel_radius"] = "删除半径内的所有载具", + ["command_repair"] = "修复当前载具", + ["command_repair_success"] = "载具已修复完毕", + ["command_repair_success_target"] = "管理员已修复您的载具", + ["command_clear"] = "清除当前聊天记录", + ["command_clearall"] = "清除全服玩家聊天记录", + ["command_clearinventory"] = "清空目标玩家物品栏", + ["command_clearloadout"] = "移除目标玩家全部武器", + ["command_freeze"] = "冻结目标玩家", + ["command_unfreeze"] = "解冻目标玩家", + ["command_giveaccountmoney"] = "向指定账户注入资金", + ["command_giveaccountmoney_account"] = "接收账户名称", + ["command_giveaccountmoney_amount"] = "注入金额 (¥)", + ["command_giveaccountmoney_invalid"] = "错误: 无效账户类型", + ["command_removeaccountmoney"] = "从账户扣除资金", + ["command_removeaccountmoney_account"] = "扣款账户名称", + ["command_removeaccountmoney_amount"] = "扣除金额 (¥)", + ["command_removeaccountmoney_invalid"] = "账户名称无效", + ["command_giveitem"] = "向玩家发放物品", + ["command_giveitem_item"] = "物品ID/名称", + ["command_giveitem_count"] = "发放数量", + ["command_giveweapon"] = "授予玩家武器", + ["command_giveweapon_weapon"] = "武器ID/名称", + ["command_giveweapon_ammo"] = "配发弹药量", + ["command_giveweapon_hasalready"] = "操作失败: 玩家已持有该武器", + ["command_giveweaponcomponent"] = "装配武器组件", + ["command_giveweaponcomponent_component"] = "组件名称", + ["command_giveweaponcomponent_invalid"] = "错误: 无效组件", + ["command_giveweaponcomponent_hasalready"] = "操作失败: 该组件已装配", + ["command_giveweaponcomponent_missingweapon"] = "错误: 玩家未持有对应武器", + ["command_goto"] = "传送到目标玩家位置", + ["command_kill"] = "强制击杀玩家", + ["command_save"] = "立即保存玩家数据", + ["command_saveall"] = "强制执行全服数据存档", + ["command_setaccountmoney"] = "设定账户资金额度", + ["command_setaccountmoney_amount"] = "设定金额 (¥)", + ["command_setcoords"] = "传送至坐标点", + ["command_setcoords_x"] = "X坐标值", + ["command_setcoords_y"] = "Y坐标值", + ["command_setcoords_z"] = "Z坐标值", + ["command_setjob"] = "调整玩家职业", + ["command_setjob_job"] = "职业ID/名称", + ["command_setjob_grade"] = "职级序号", + ["command_setjob_invalid"] = "配置错误: 无效职业或职级", + ["command_setgroup"] = "设置玩家权限组别", + ["command_setgroup_group"] = "组别名称", + ["commanderror_argumentmismatch"] = "参数数量错误 (需%s个, 输入%s个)", + ["commanderror_argumentmismatch_number"] = "参数#%s类型不符 (需数字类型)", + ["commanderror_argumentmismatch_string"] = "参数#%s类型不符 (需文本类型)", + ["commanderror_argumentmismatch_positive_number"] = "参数#%s类型不符 (传入负数/零,需要正数)", + ["commanderror_invaliditem"] = "错误: 无效物品标识", + ["commanderror_invalidweapon"] = "错误: 无效武器标识", + ["commanderror_console"] = "控制台无法执行此指令", + ["commanderror_invalidcommand"] = "无效指令: /%s", + ["commanderror_invalidplayerid"] = "目标玩家不在线", + ["commandgeneric_playerid"] = "玩家服务器ID", + ["commandgeneric_dimension"] = "维度ID", + ["command_giveammo_noweapon_found"] = "操作失败: %s未装备该武器", + ["command_giveammo_weapon"] = "目标武器名称", + ["command_giveammo_ammo"] = "补充弹药量", + ["command_setdim"] = "切换玩家维度", + ["tpm_nowaypoint"] = "传送失败: 未设置路径点", + ["tpm_success"] = "路径点传送完成", + + ["noclip_message"] = "飞行模式 %s", + ["enabled"] = "~g~已激活~s~", + ["disabled"] = "~r~已禁用~s~", + + -- Locale settings + ["locale_digit_grouping_symbol"] = ",", + ["locale_currency"] = "¥%s", + + -- Weapons + + -- Melee + ["weapon_dagger"] = "古骑兵匕首", + ["weapon_bat"] = "棒球棍", + ["weapon_battleaxe"] = "战斧", + ["weapon_bottle"] = "碎酒瓶", + ["weapon_crowbar"] = "撬棍", + ["weapon_flashlight"] = "手电筒", + ["weapon_golfclub"] = "高尔夫球杆", + ["weapon_hammer"] = "铁锤", + ["weapon_hatchet"] = "手斧", + ["weapon_knife"] = "小刀", + ["weapon_knuckle"] = "手指虎", + ["weapon_machete"] = "开山刀", + ["weapon_nightstick"] = "警棍", + ["weapon_wrench"] = "管钳扳手", + ["weapon_poolcue"] = "台球杆", + ["weapon_stone_hatchet"] = "石斧", + ["weapon_switchblade"] = "弹簧刀", + + -- Handguns + ["weapon_appistol"] = "穿甲手枪", + ["weapon_ceramicpistol"] = "陶瓷手枪", + ["weapon_combatpistol"] = "战斗手枪", + ["weapon_doubleaction"] = "双动式左轮手枪", + ["weapon_navyrevolver"] = "海军左轮手枪", + ["weapon_flaregun"] = "信号枪", + ["weapon_gadgetpistol"] = "佩里克手枪", + ["weapon_heavypistol"] = "重型手枪", + ["weapon_revolver"] = "重型左轮手枪", + ["weapon_revolver_mk2"] = "重型左轮手枪-MK2", + ["weapon_marksmanpistol"] = "射手手枪", + ["weapon_pistol"] = "手枪", + ["weapon_pistol_mk2"] = "手枪-MK2", + ["weapon_pistol50"] = "0.5-口径手枪", + ["weapon_snspistol"] = "劣质手枪", + ["weapon_snspistol_mk2"] = "劣质手枪-MK2", + ["weapon_stungun"] = "电击枪", + ["weapon_raypistol"] = "原子堡手枪", + ["weapon_vintagepistol"] = "老式手枪", + + -- Shotguns + ["weapon_assaultshotgun"] = "突击霰弹枪", + ["weapon_autoshotgun"] = "半自动霰弹枪", + ["weapon_bullpupshotgun"] = "无托式霰弹枪", + ["weapon_combatshotgun"] = "战斗霰弹枪", + ["weapon_dbshotgun"] = "双管霰弹枪", + ["weapon_heavyshotgun"] = "重型霰弹枪", + ["weapon_musket"] = "老式火枪", + ["weapon_pumpshotgun"] = "泵动式霰弹枪", + ["weapon_pumpshotgun_mk2"] = "泵动式霰弹枪-MK2", + ["weapon_sawnoffshotgun"] = "短管霰弹枪", + + -- SMG & LMG + ["weapon_assaultsmg"] = "突击冲锋枪", + ["weapon_combatmg"] = "战斗机枪", + ["weapon_combatmg_mk2"] = "战斗机枪-MK2", + ["weapon_combatpdw"] = "作战自卫冲锋枪", + ["weapon_gusenberg"] = "古森柏冲锋枪", + ["weapon_machinepistol"] = "冲锋手枪", + ["weapon_mg"] = "机枪", + ["weapon_microsmg"] = "微型冲锋枪", + ["weapon_minismg"] = "迷你冲锋枪", + ["weapon_smg"] = "冲锋枪", + ["weapon_smg_mk2"] = "冲锋枪-MK2", + ["weapon_raycarbine"] = "不洁使者", + ["weapon_tecpistol"] = "战术冲锋枪", + + -- Rifles + ["weapon_advancedrifle"] = "高级步枪", + ["weapon_assaultrifle"] = "突击步枪", + ["weapon_assaultrifle_mk2"] = "突击步枪-MK2", + ["weapon_bullpuprifle"] = "无托式步枪", + ["weapon_bullpuprifle_mk2"] = "无托式步枪-MK2", + ["weapon_carbinerifle"] = "卡宾步枪", + ["weapon_carbinerifle_mk2"] = "卡宾步枪-MK2", + ["weapon_compactrifle"] = "紧凑型步枪", + ["weapon_militaryrifle"] = "军用步枪", + ["weapon_specialcarbine"] = "特制卡宾步枪", + ["weapon_specialcarbine_mk2"] = "特制卡宾步枪-MK2", + ["weapon_heavyrifle"] = "重型步枪", + ["weapon_battlerifle"] = "战斗步枪", + + -- Sniper + ["weapon_heavysniper"] = "重型狙击步枪", + ["weapon_heavysniper_mk2"] = "重型狙击步枪-MK2", + ["weapon_marksmanrifle"] = "射手步枪", + ["weapon_marksmanrifle_mk2"] = "射手步枪-MK2", + ["weapon_sniperrifle"] = "狙击步枪", + + -- Heavy / Launchers + ["weapon_compactlauncher"] = "紧凑型榴弹发射器", + ["weapon_firework"] = "烟花发射器", + ["weapon_grenadelauncher"] = "榴弹发射器", + ["weapon_hominglauncher"] = "制导火箭发射器", + ["weapon_minigun"] = "火神机枪", + ["weapon_railgun"] = "电磁轨道炮", + ["weapon_rpg"] = "火箭炮", + ["weapon_rayminigun"] = "寡妇制造者", + + -- Criminal Enterprises DLC + ["weapon_metaldetector"] = "金属探测器", + ["weapon_precisionrifle"] = "精确步枪", + ["weapon_tactilerifle"] = "制式卡宾步枪", + + -- Drug wars dlc + ["weapon_candycane"] = "糖果手杖", + ["weapon_acidpackage"] = "酸液包", + ["weapon_pistolxm3"] = "战术手枪-x3m", + ["weapon_railgunxm3"] = "电磁轨道炮", + + -- Chop Shop DLC + ["weapon_snowlauncher"] = "雪球发射器", + ["weapon_hackingdevice"] = "黑客设备", + + -- Bottom Dollar Bounties DLC + ["weapon_stunrod"] = "电击棒", + + -- Thrown + ["weapon_ball"] = "棒球", + ["weapon_bzgas"] = "毒气弹", + ["weapon_flare"] = "信号棒", + ["weapon_grenade"] = "手榴弹", + ["weapon_petrolcan"] = "汽油桶", + ["weapon_hazardcan"] = "有害汽油桶", + ["weapon_molotov"] = "汽油弹", + ["weapon_proxmine"] = "感应式地雷", + ["weapon_pipebomb"] = "土製炸彈", + ["weapon_snowball"] = "雪球", + ["weapon_stickybomb"] = "黏弹", + ["weapon_smokegrenade"] = "催泪瓦斯", + + -- Special + ["weapon_fireextinguisher"] = "灭火器", + ["weapon_digiscanner"] = "数位扫描仪", + ["weapon_garbagebag"] = "垃圾袋", + ["weapon_handcuffs"] = "手铐", + ["gadget_nightvision"] = "夜视仪", + ["gadget_parachute"] = "降落伞", + + -- Weapon Components + ["component_knuckle_base"] = "基础", + ["component_knuckle_pimp"] = "皮条客", + ["component_knuckle_ballas"] = "巴拉斯帮", + ["component_knuckle_dollar"] = "暴发户", + ["component_knuckle_diamond"] = "钻石王", + ["component_knuckle_hate"] = "憎恶獠牙", + ["component_knuckle_love"] = "爱之惩戒", + ["component_knuckle_player"] = "情场玩家", + ["component_knuckle_king"] = "王者之牙", + ["component_knuckle_vagos"] = "维戈斯帮", + + ["component_luxary_finish"] = "奢华镀层", + + ["component_handle_default"] = "标准握把", + ["component_handle_vip"] = "VIP专用握把", + ["component_handle_bodyguard"] = "保镖战术握把", + + ["component_vip_finish"] = "VIP定制镀层", + ["component_bodyguard_finish"] = "护卫队特供镀层", + + ["component_camo_finish"] = "数码迷彩", + ["component_camo_finish2"] = "笔刷迷彩", + ["component_camo_finish3"] = "丛林迷彩", + ["component_camo_finish4"] = "骷髅迷彩", + ["component_camo_finish5"] = "69式迷彩", + ["component_camo_finish6"] = "英仙座迷彩", + ["component_camo_finish7"] = "豹纹迷彩", + ["component_camo_finish8"] = "斑马迷彩", + ["component_camo_finish9"] = "几何迷彩", + ["component_camo_finish10"] = "爆炸效果迷彩", + ["component_camo_finish11"] = "爱国者迷彩", + + ["component_camo_slide_finish"] = "数码迷彩滑轨", + ["component_camo_slide_finish2"] = "笔刷迷彩滑轨", + ["component_camo_slide_finish3"] = "丛林迷彩滑轨", + ["component_camo_slide_finish4"] = "骷髅迷彩滑轨", + ["component_camo_slide_finish5"] = "69式迷彩滑轨", + ["component_camo_slide_finish6"] = "英仙座迷彩滑轨", + ["component_camo_slide_finish7"] = "豹纹迷彩滑轨", + ["component_camo_slide_finish8"] = "斑马迷彩滑轨", + ["component_camo_slide_finish9"] = "几何迷彩滑轨", + ["component_camo_slide_finish10"] = "爆炸效果迷彩滑轨", + ["component_camo_slide_finish11"] = "爱国者迷彩滑轨", + + ["component_clip_default"] = "标准弹匣", + ["component_clip_extended"] = "扩容弹匣", + ["component_clip_drum"] = "弹鼓", + ["component_clip_box"] = "弹箱", + + ["component_scope_holo"] = "全息瞄具", + ["component_scope_small"] = "紧凑型瞄具", + ["component_scope_medium"] = "中型瞄具", + ["component_scope_large"] = "远距光学瞄具", + ["component_scope"] = "战术导轨瞄具", + ["component_scope_advanced"] = "先进战斗光学瞄具", + ["component_ironsights"] = "机械瞄具", + + ["component_suppressor"] = "消音器", + ["component_compensator"] = "枪口补偿器", + + ["component_muzzle_flat"] = "平面制退器", + ["component_muzzle_tactical"] = "战术制退器", + ["component_muzzle_fat"] = "粗齿制退器", + ["component_muzzle_precision"] = "精密补偿器", + ["component_muzzle_heavy"] = "重型枪口制退器", + ["component_muzzle_slanted"] = "斜切式枪口制退器", + ["component_muzzle_split"] = "开叉式枪口制退器", + ["component_muzzle_squared"] = "平顶式枪口制退器", + + ["component_flashlight"] = "战术手电", + ["component_grip"] = "握把", + + ["component_barrel_default"] = "标准枪管", + ["component_barrel_heavy"] = "重型枪管", + + ["component_ammo_tracer"] = "曳光弹药", + ["component_ammo_incendiary"] = "燃烧弹药", + ["component_ammo_hollowpoint"] = "空尖弹药", + ["component_ammo_fmj"] = "全金属被甲弹药", + ["component_ammo_armor"] = "穿甲弹药", + ["component_ammo_explosive"] = "高爆燃烧弹药", + + ["component_shells_default"] = "标准弹壳", + ["component_shells_incendiary"] = "龙息弹", + ["component_shells_armor"] = "钢珠霰弹", + ["component_shells_hollowpoint"] = "箭形弹", + ["component_shells_explosive"] = "高爆独头弹", + + -- Weapon Ammo + ["ammo_rounds"] = "发子弹", + ["ammo_shells"] = "发霰弹", + ["ammo_charge"] = "发能量", + ["ammo_petrol"] = "升燃料", + ["ammo_firework"] = "个烟花", + ["ammo_rockets"] = "枚火箭弹", + ["ammo_grenadelauncher"] = "枚榴弹", + ["ammo_grenade"] = "枚手雷", + ["ammo_stickybomb"] = "枚粘性炸弹", + ["ammo_pipebomb"] = "枚管状炸弹", + ["ammo_smokebomb"] = "枚烟雾弹", + ["ammo_molotov"] = "瓶燃烧瓶", + ["ammo_proxmine"] = "个感应地雷", + ["ammo_bzgas"] = "罐毒气", + ["ammo_ball"] = "个球体", + ["ammo_snowball"] = "个雪球", + ["ammo_flare"] = "发信号弹", + ["ammo_flaregun"] = "发信号弹", + + -- Weapon Tints + ["tint_default"] = "默认涂装", + ["tint_green"] = "绿色涂装", + ["tint_gold"] = "金色涂装", + ["tint_pink"] = "粉色涂装", + ["tint_army"] = "迷彩涂装", + ["tint_lspd"] = "警用蓝色涂装", + ["tint_orange"] = "橙色涂装", + ["tint_platinum"] = "铂金涂装", + -- MK2 Weapon Tints + ["tint_classic_black"] = "经典黑", + ["tint_classic_gray"] = "经典灰", + ["tint_classic_two_tone"] = "经典双色", + ["tint_classic_white"] = "经典白", + ["tint_classic_beige"] = "经典米色", + ["tint_classic_green"] = "经典绿", + ["tint_classic_blue"] = "经典蓝", + ["tint_classic_earth"] = "经典大地色", + ["tint_classic_brown_black"] = "经典棕黑", + ["tint_contrast_red"] = "对比红", + ["tint_contrast_blue"] = "对比蓝", + ["tint_contrast_yellow"] = "对比黄", + ["tint_contrast_orange"] = "对比橙", + ["tint_bold_pink"] = "炫彩粉", + ["tint_bold_purple_yellow"] = "炫彩紫黄", + ["tint_bold_orange"] = "炫彩橙", + ["tint_bold_green_purple"] = "炫彩绿紫", + ["tint_bold_red_feat"] = "炫彩红特调", + ["tint_bold_green_feat"] = "炫彩绿特调", + ["tint_bold_cyan_feat"] = "炫彩青特调", + ["tint_bold_yellow_feat"] = "炫彩黄特调", + ["tint_bold_red_white"] = "炫彩红白", + ["tint_bold_blue_white"] = "炫彩蓝白", + ["tint_metallic_gold"] = "金属金", + ["tint_metallic_platinum"] = "金属铂金", + ["tint_metallic_gray_lilac"] = "金属灰紫色", + ["tint_metallic_purple_lime"] = "金属紫柠色", + ["tint_metallic_red"] = "金属红", + ["tint_metallic_green"] = "金属绿", + ["tint_metallic_blue"] = "金属蓝", + ["tint_metallic_white_aqua"] = "金属白水色", + ["tint_metallic_red_yellow"] = "金属红黄色" +} diff --git a/resources/[core]/es_extended/server/bridge/inventory/oxinventory.lua b/resources/[core]/es_extended/server/bridge/inventory/oxinventory.lua new file mode 100644 index 0000000..62b4c2a --- /dev/null +++ b/resources/[core]/es_extended/server/bridge/inventory/oxinventory.lua @@ -0,0 +1,36 @@ +if Config.CustomInventory ~= "ox" then return end + +MySQL.ready(function() + TriggerEvent("__cfx_export_ox_inventory_Items", function(ref) + if ref then + ESX.Items = ref() + end + end) + + AddEventHandler("ox_inventory:itemList", function(items) + ESX.Items = items + end) +end) + +---@diagnostic disable-next-line: duplicate-set-field +ESX.GetItemLabel = function(item) + item = exports.ox_inventory:Items(item) + if item then + return item.label + end +end + +function setPlayerInventory(playerId, xPlayer, inventory, isNew) + exports.ox_inventory:setPlayerInventory(xPlayer, inventory) + if isNew then + local shared = json.decode(GetConvar("inventory:accounts", '["money"]')) + + for i = 1, #shared do + local name = shared[i] + local account = Config.StartingAccountMoney[name] + if account then + exports.ox_inventory:AddItem(playerId, name, account) + end + end + end +end diff --git a/resources/[core]/es_extended/server/classes/overrides/oxinventory.lua b/resources/[core]/es_extended/server/classes/overrides/oxinventory.lua new file mode 100644 index 0000000..c3be26a --- /dev/null +++ b/resources/[core]/es_extended/server/classes/overrides/oxinventory.lua @@ -0,0 +1,219 @@ +local Inventory + +if Config.CustomInventory ~= "ox" then return end + +AddEventHandler("ox_inventory:loadInventory", function(module) + Inventory = module +end) + +Core.PlayerFunctionOverrides.OxInventory = { + getInventory = function(self) + return function(minimal) + if not minimal then + return self.inventory + end + + local minimalInventory = {} + + for k, v in pairs(self.inventory) do + if v.count and v.count > 0 then + local metadata = v.metadata + + if v.metadata and next(v.metadata) == nil then + metadata = nil + end + + minimalInventory[#minimalInventory + 1] = { + name = v.name, + count = v.count, + slot = k, + metadata = metadata, + } + end + end + + return minimalInventory + end + end, + + getLoadout = function() + return function() + return {} + end + end, + + setAccountMoney = function(self) + return function(accountName, money, reason) + reason = reason or "unknown" + if money < 0 then return end + local account = self.getAccount(accountName) + + if not account then return end + + money = account.round and ESX.Math.Round(money) or money + self.accounts[account.index].money = money + + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:setAccountMoney", self.source, accountName, money, reason) + if Inventory.accounts[accountName] then + Inventory.SetItem(self.source, accountName, money) + end + end + end, + + addAccountMoney = function(self) + return function(accountName, money, reason) + reason = reason or "unknown" + if money < 1 then return end + + local account = self.getAccount(accountName) + if not account then return end + + money = account.round and ESX.Math.Round(money) or money + self.accounts[account.index].money = self.accounts[account.index].money + money + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:addAccountMoney", self.source, accountName, money, reason) + if Inventory.accounts[accountName] then + Inventory.AddItem(self.source, accountName, money) + end + end + end, + + removeAccountMoney = function(self) + return function(accountName, money, reason) + reason = reason or "unknown" + if money < 1 then return end + + local account = self.getAccount(accountName) + if not account then return end + + money = account.round and ESX.Math.Round(money) or money + self.accounts[account.index].money = self.accounts[account.index].money - money + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:removeAccountMoney", self.source, accountName, money, reason) + if Inventory.accounts[accountName] then + Inventory.RemoveItem(self.source, accountName, money) + end + end + end, + + getInventoryItem = function(self) + return function(name, metadata) + return Inventory.GetItem(self.source, name, metadata) + end + end, + + addInventoryItem = function(self) + return function(name, count, metadata, slot) + return Inventory.AddItem(self.source, name, count or 1, metadata, slot) + end + end, + + removeInventoryItem = function(self) + return function(name, count, metadata, slot) + return Inventory.RemoveItem(self.source, name, count or 1, metadata, slot) + end + end, + + setInventoryItem = function(self) + return function(name, count, metadata) + return Inventory.SetItem(self.source, name, count, metadata) + end + end, + + canCarryItem = function(self) + return function(name, count, metadata) + return Inventory.CanCarryItem(self.source, name, count, metadata) + end + end, + + canSwapItem = function(self) + return function(firstItem, firstItemCount, testItem, testItemCount) + return Inventory.CanSwapItem(self.source, firstItem, firstItemCount, testItem, testItemCount) + end + end, + + setMaxWeight = function(self) + return function(newWeight) + self.maxWeight = newWeight + self.triggerEvent("esx:setMaxWeight", self.maxWeight) + return Inventory.SetMaxWeight(self.source, newWeight) + end + end, + + addWeapon = function() + return function() end + end, + + addWeaponComponent = function() + return function() end + end, + + addWeaponAmmo = function() + return function() end + end, + + updateWeaponAmmo = function() + return function() end + end, + + setWeaponTint = function() + return function() end + end, + + getWeaponTint = function() + return function() end + end, + + removeWeapon = function() + return function() end + end, + + removeWeaponComponent = function() + return function() end + end, + + removeWeaponAmmo = function() + return function() end + end, + + hasWeaponComponent = function() + return function() + return false + end + end, + + hasWeapon = function() + return function() + return false + end + end, + + hasItem = function(self) + return function(name, metadata) + return Inventory.GetItem(self.source, name, metadata) + end + end, + + getWeapon = function() + return function() end + end, + + syncInventory = function(self) + return function(weight, maxWeight, items, money) + self.weight, self.maxWeight = weight, maxWeight + self.inventory = items + + if not money then return end + for accountName, amount in pairs(money) do + local account = self.getAccount(accountName) + + if account and ESX.Math.Round(account.money) ~= amount then + account.money = amount + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:setAccountMoney", self.source, accountName, amount, "Sync account with item") + end + end + end + end, +} diff --git a/resources/[core]/es_extended/server/classes/player.lua b/resources/[core]/es_extended/server/classes/player.lua new file mode 100644 index 0000000..367c983 --- /dev/null +++ b/resources/[core]/es_extended/server/classes/player.lua @@ -0,0 +1,969 @@ +---@class ESXAccount +---@field name string # Account name (e.g., "bank", "money"). +---@field money number # Current balance in this account. +---@field label string # Human-readable label for the account. +---@field round boolean # Whether amounts are rounded for display. +---@field index number # Index of the account in the player's accounts list. + +---@class ESXItem +---@field name string # Item identifier (internal name). +---@field label string # Display name of the item. +---@field weight number # Weight of a single unit of the item. +---@field usable boolean # Whether the item can be used. +---@field rare boolean # Whether the item is rare. +---@field canRemove boolean # Whether the item can be removed from inventory. + +---@class ESXInventoryItem:ESXItem +---@field count number # Number of this item in the player's inventory. + +---@class ESXJob +---@field id number # Job ID. +---@field name string # Job internal name. +---@field label string # Job display label. +---@field grade number # Current grade/rank number. +---@field grade_name string # Name of the current grade. +---@field grade_label string # Label of the current grade. +---@field grade_salary number # Salary for the current grade. +---@field skin_male table # Skin configuration for male characters. +---@field skin_female table # Skin configuration for female characters. +---@field onDuty boolean? # Whether the player is currently on duty. + +---@class ESXWeapon +---@field name string # Weapon identifier (internal name). +---@field label string # Weapon display name. + +---@class ESXInventoryWeapon:ESXWeapon +---@field ammo number # Amount of ammo in the weapon. +---@field components string[] # List of components attached to the weapon. +---@field tintIndex number # Current weapon tint index. + +---@class ESXWeaponComponent +---@field name string # Component identifier (internal name). +---@field label string # Component display name. +---@field hash string|number # Component hash or identifier. + +---@class StaticPlayer +---@field src number # Player's server ID. +--- Money Functions +---@field setMoney fun(money: number) # Set player's cash balance. +---@field getMoney fun(): number # Get player's current cash balance. +---@field addMoney fun(money: number, reason: string) # Add money to the player's cash balance. +---@field removeMoney fun(money: number, reason: string) # Remove money from the player's cash balance. +---@field setAccountMoney fun(accountName: string, money: number, reason?: string) # Set specific account balance. +---@field addAccountMoney fun(accountName: string, money: number, reason?: string) # Add money to an account. +---@field removeAccountMoney fun(accountName: string, money: number, reason?: string) # Remove money from an account. +---@field getAccount fun(account: string): ESXAccount? # Get account data by name. +---@field getAccounts fun(minimal?: boolean): ESXAccount[]|table # Get all accounts, optionally minimal. +--- Inventory Functions +---@field getInventory fun(minimal?: boolean): ESXInventoryItem[]|table # Get inventory, optionally minimal. +---@field getInventoryItem fun(itemName: string): ESXInventoryItem? # Get a specific item from inventory. +---@field addInventoryItem fun(itemName: string, count: number) # Add items to inventory. +---@field removeInventoryItem fun(itemName: string, count: number) # Remove items from inventory. +---@field setInventoryItem fun(itemName: string, count: number) # Set item count in inventory. +---@field getWeight fun(): number # Get current carried weight. +---@field getMaxWeight fun(): number # Get maximum carry weight. +---@field setMaxWeight fun(newWeight: number) # Set maximum carry weight. +---@field canCarryItem fun(itemName: string, count: number): boolean # Check if player can carry more of an item. +---@field canSwapItem fun(firstItem: string, firstItemCount: number, testItem: string, testItemCount: number): boolean # Check if items can be swapped. +---@field hasItem fun(item: string): ESXInventoryItem|false, number? # Check if player has an item. +---@field getLoadout fun(minimal?: boolean): ESXInventoryWeapon[]|table # Get player's weapon loadout. +--- Job Functions +---@field getJob fun(): ESXJob # Get player's current job. +---@field setJob fun(newJob: string, grade: string, onDuty?: boolean) # Set player's job and grade. +---@field setGroup fun(newGroup: string) # Set player's permission group. +---@field getGroup fun(): string # Get player's permission group. +--- Weapon Functions +---@field addWeapon fun(weaponName: string, ammo: number) # Give player a weapon. +---@field removeWeapon fun(weaponName: string) # Remove weapon from player. +---@field hasWeapon fun(weaponName: string): boolean # Check if player has a weapon. +---@field getWeapon fun(weaponName: string): number?, table? # Get weapon ammo & components. +---@field addWeaponAmmo fun(weaponName: string, ammoCount: number) # Add ammo to a weapon. +---@field removeWeaponAmmo fun(weaponName: string, ammoCount: number) # Remove ammo from a weapon. +---@field updateWeaponAmmo fun(weaponName: string, ammoCount: number) # Update ammo count for a weapon. +---@field addWeaponComponent fun(weaponName: string, weaponComponent: string) # Add component to weapon. +---@field removeWeaponComponent fun(weaponName: string, weaponComponent: string) # Remove component from weapon. +---@field hasWeaponComponent fun(weaponName: string, weaponComponent: string): boolean # Check if weapon has component. +---@field setWeaponTint fun(weaponName: string, weaponTintIndex: number) # Set weapon tint. +---@field getWeaponTint fun(weaponName: string): number # Get weapon tint. +--- Player State Functions +---@field getIdentifier fun(): string # Get player's unique identifier. +---@field getSSN fun(): string # Get player's social security number. +---@field getSource fun(): number # Get player source/server ID. +---@field getPlayerId fun(): number # Alias for getSource. +---@field getName fun(): string # Get player's name. +---@field setName fun(newName: string) # Set player's name. +---@field setCoords fun(coordinates: vector4|vector3|table) # Teleport player to coordinates. +---@field getCoords fun(vector?: boolean, heading?: boolean): vector3|vector4|table # Get player's coordinates. +---@field isAdmin fun(): boolean # Check if player is admin. +---@field kick fun(reason: string) # Kick player from server. +---@field getPlayTime fun(): number # Get total playtime in seconds. +---@field set fun(k: string, v: any) # Set custom variable. +---@field get fun(k: string): any # Get custom variable. +--- Metadata Functions +---@field getMeta fun(index?: string, subIndex?: string|table): any # Get metadata value(s). +---@field setMeta fun(index: string, value: any, subValue?: any) # Set metadata value(s). +---@field clearMeta fun(index: string, subValues?: string|table) # Clear metadata value(s). +--- Notification Functions +---@field showNotification fun(msg: string, notifyType?: string, length?: number, title?: string, position?: string) # Show a simple notification. +---@field showAdvancedNotification fun(sender: string, subject: string, msg: string, textureDict: string, iconType: string, flash: boolean, saveToBrief: boolean, hudColorIndex: number) # Show advanced notification. +---@field showHelpNotification fun(msg: string, thisFrame?: boolean, beep?: boolean, duration?: number) # Show help notification. +--- Misc Functions +---@field togglePaycheck fun(toggle: boolean) # Enable/disable paycheck. +---@field isPaycheckEnabled fun(): boolean # Check if paycheck is enabled. +---@field executeCommand fun(command: string) # Execute a server command. +---@field triggerEvent fun(eventName: string, ...) # Trigger client event for this player. + + +---@class xPlayer:StaticPlayer +--- Properties +---@field accounts ESXAccount[] # Array of the player's accounts. +---@field coords table # Player's coordinates {x, y, z, heading}. +---@field group string # Player permission group. +---@field identifier string # Unique identifier (usually Steam or license). +---@field license string # Player license string. +---@field inventory ESXInventoryItem[] # Player's inventory items. +---@field job ESXJob # Player's current job. +---@field loadout ESXInventoryWeapon[] # Player's current weapons. +---@field name string # Player's display name. +---@field playerId number # Player's ID (server ID). +---@field source number # Player's source (alias for playerId). +---@field variables table # Custom player variables. +---@field weight number # Current carried weight. +---@field maxWeight number # Maximum carry weight. +---@field metadata table # Custom metadata table. +---@field lastPlaytime number # Last recorded playtime in seconds. +---@field paycheckEnabled boolean # Whether paycheck is enabled. +---@field admin boolean # Whether the player is an admin. + +---@param playerId number +---@param identifier string +---@param ssn string +---@param group string +---@param accounts ESXAccount[] +---@param inventory table +---@param weight number +---@param job ESXJob +---@param loadout ESXInventoryWeapon[] +---@param name string +---@param coords vector4|{x: number, y: number, z: number, heading: number} +---@param metadata table +---@return xPlayer +function CreateExtendedPlayer(playerId, identifier, ssn, group, accounts, inventory, weight, job, loadout, name, coords, metadata) + ---@diagnostic disable-next-line: missing-fields + local self = {} ---@type xPlayer + + self.accounts = accounts + self.coords = coords + self.group = group + self.identifier = identifier + self.ssn = ssn + self.inventory = inventory + self.job = job + self.loadout = loadout + self.name = name + self.playerId = playerId + self.source = playerId + self.variables = {} + self.weight = weight + self.maxWeight = Config.MaxWeight + self.metadata = metadata + self.lastPlaytime = self.metadata.lastPlaytime or 0 + self.paycheckEnabled = true + self.admin = Core.IsPlayerAdmin(playerId) + if Config.Multichar then + local startIndex = identifier:find(":", 1) + if startIndex then + self.license = ("%s%s"):format(Config.Identifier, identifier:sub(startIndex, identifier:len())) + end + else + self.license = ("%s:%s"):format(Config.Identifier, identifier) + end + + if type(self.metadata.jobDuty) ~= "boolean" then + self.metadata.jobDuty = self.job.name ~= "unemployed" and Config.DefaultJobDuty or false + end + job.onDuty = self.metadata.jobDuty + + ExecuteCommand(("add_principal identifier.%s group.%s"):format(self.license, self.group)) + + local stateBag = Player(self.source).state + stateBag:set("identifier", self.identifier, false) + stateBag:set("license", self.license, false) + stateBag:set("job", self.job, true) + stateBag:set("group", self.group, true) + stateBag:set("name", self.name, true) + + function self.triggerEvent(eventName, ...) + assert(type(eventName) == "string", "eventName should be string!") + TriggerClientEvent(eventName, self.source, ...) + end + + function self.togglePaycheck(toggle) + self.paycheckEnabled = toggle + end + + function self.isPaycheckEnabled() + return self.paycheckEnabled + end + + function self.isAdmin() + return Core.IsPlayerAdmin(self.source) + end + + function self.setCoords(coordinates) + local ped = GetPlayerPed(self.source) + + SetEntityCoords(ped, coordinates.x, coordinates.y, coordinates.z, false, false, false, false) + SetEntityHeading(ped, coordinates.w or coordinates.heading or 0.0) + end + + function self.getCoords(vector, heading) + local ped = GetPlayerPed(self.source) + local entityCoords = GetEntityCoords(ped) + local entityHeading = GetEntityHeading(ped) + + local coordinates = { x = entityCoords.x, y = entityCoords.y, z = entityCoords.z } + + if vector then + coordinates = (heading and vector4(entityCoords.x, entityCoords.y, entityCoords.z, entityHeading) or entityCoords) + else + if heading then + coordinates.heading = entityHeading + end + end + + return coordinates + end + + function self.kick(reason) + DropPlayer(self.source --[[@as string]], reason) + end + + function self.getPlayTime() + -- luacheck: ignore + return self.lastPlaytime + GetPlayerTimeOnline(self.source --[[@as string]]) + end + + function self.setMoney(money) + assert(type(money) == "number", "money should be number!") + money = ESX.Math.Round(money) + self.setAccountMoney("money", money) + end + + function self.getMoney() + return self.getAccount("money").money + end + + function self.addMoney(money, reason) + money = ESX.Math.Round(money) + self.addAccountMoney("money", money, reason) + end + + function self.removeMoney(money, reason) + money = ESX.Math.Round(money) + self.removeAccountMoney("money", money, reason) + end + + function self.getIdentifier() + return self.identifier + end + + function self.getSSN() + return self.ssn + end + + function self.setGroup(newGroup) + local lastGroup = self.group + + ExecuteCommand(("remove_principal identifier.%s group.%s"):format(self.license, self.group)) + + self.group = newGroup + + TriggerEvent("esx:setGroup", self.source, self.group, lastGroup) + self.triggerEvent("esx:setGroup", self.group, lastGroup) + Player(self.source).state:set("group", self.group, true) + + ExecuteCommand(("add_principal identifier.%s group.%s"):format(self.license, self.group)) + end + + function self.getGroup() + return self.group + end + + function self.set(k, v) + self.variables[k] = v + + self.triggerEvent('esx:updatePlayerData', 'variables', self.variables) + end + + function self.get(k) + return self.variables[k] + end + + function self.getAccounts(minimal) + if not minimal then + return self.accounts + end + + local minimalAccounts = {} + + for i = 1, #self.accounts do + minimalAccounts[self.accounts[i].name] = self.accounts[i].money + end + + return minimalAccounts + end + + function self.getAccount(account) + account = string.lower(account) + for i = 1, #self.accounts do + local accountName = string.lower(self.accounts[i].name) + if accountName == account then + return self.accounts[i] + end + end + return nil + end + + function self.getInventory(minimal) + if minimal then + local minimalInventory = {} + + for _, v in ipairs(self.inventory) do + if v.count > 0 then + minimalInventory[v.name] = v.count + end + end + + return minimalInventory + end + + return self.inventory + end + + function self.getJob() + return self.job + end + + function self.getLoadout(minimal) + if not minimal then + return self.loadout + end + local minimalLoadout = {} + + for _, v in ipairs(self.loadout) do + minimalLoadout[v.name] = { ammo = v.ammo } + if v.tintIndex > 0 then + minimalLoadout[v.name].tintIndex = v.tintIndex + end + + if #v.components > 0 then + local components = {} + + for _, component in ipairs(v.components) do + if component ~= "clip_default" then + components[#components + 1] = component + end + end + + if #components > 0 then + minimalLoadout[v.name].components = components + end + end + end + + return minimalLoadout + end + + function self.getName() + return self.name + end + + function self.setName(newName) + self.name = newName + Player(self.source).state:set("name", self.name, true) + end + + function self.setAccountMoney(accountName, money, reason) + reason = reason or "unknown" + if not tonumber(money) then + error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money)) + return + end + if money >= 0 then + local account = self.getAccount(accountName) + + if account then + money = account.round and ESX.Math.Round(money) or money + self.accounts[account.index].money = money + + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:setAccountMoney", self.source, accountName, money, reason) + else + error(("Tried To Set Invalid Account ^5%s^1 For Player ^5%s^1!"):format(accountName, self.playerId)) + end + else + error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money)) + end + end + + function self.addAccountMoney(accountName, money, reason) + reason = reason or "Unknown" + if not tonumber(money) then + error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money)) + return + end + if money > 0 then + local account = self.getAccount(accountName) + if account then + money = account.round and ESX.Math.Round(money) or money + self.accounts[account.index].money = self.accounts[account.index].money + money + + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:addAccountMoney", self.source, accountName, money, reason) + else + error(("Tried To Set Add To Invalid Account ^5%s^1 For Player ^5%s^1!"):format(accountName, self.playerId)) + end + else + error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money)) + end + end + + function self.removeAccountMoney(accountName, money, reason) + reason = reason or "Unknown" + if not tonumber(money) then + error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money)) + return + end + if money > 0 then + local account = self.getAccount(accountName) + + if account then + money = account.round and ESX.Math.Round(money) or money + if self.accounts[account.index].money - money > self.accounts[account.index].money then + error(("Tried To Underflow Account ^5%s^1 For Player ^5%s^1!"):format(accountName, self.playerId)) + return + end + self.accounts[account.index].money = self.accounts[account.index].money - money + + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:removeAccountMoney", self.source, accountName, money, reason) + else + error(("Tried To Set Add To Invalid Account ^5%s^1 For Player ^5%s^1!"):format(accountName, self.playerId)) + end + else + error(("Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1"):format(accountName, self.playerId, money)) + end + end + + function self.getInventoryItem(itemName) + for _, v in ipairs(self.inventory) do + if v.name == itemName then + return v + end + end + return nil + end + + function self.addInventoryItem(itemName, count) + local item = self.getInventoryItem(itemName) + + if item then + count = ESX.Math.Round(count) + item.count = item.count + count + self.weight = self.weight + (item.weight * count) + + TriggerEvent("esx:onAddInventoryItem", self.source, item.name, item.count) + self.triggerEvent("esx:addInventoryItem", item.name, item.count) + end + end + + function self.removeInventoryItem(itemName, count) + local item = self.getInventoryItem(itemName) + + if item then + count = ESX.Math.Round(count) + if count > 0 then + local newCount = item.count - count + + if newCount >= 0 then + item.count = newCount + self.weight = self.weight - (item.weight * count) + + TriggerEvent("esx:onRemoveInventoryItem", self.source, item.name, item.count) + self.triggerEvent("esx:removeInventoryItem", item.name, item.count) + end + else + error(("Player ID:^5%s Tried remove a Invalid count -> %s of %s"):format(self.playerId, count, itemName)) + end + end + end + + function self.setInventoryItem(itemName, count) + local item = self.getInventoryItem(itemName) + + if item and count >= 0 then + count = ESX.Math.Round(count) + + if count > item.count then + self.addInventoryItem(item.name, count - item.count) + else + self.removeInventoryItem(item.name, item.count - count) + end + end + end + + function self.getWeight() + return self.weight + end + + function self.getSource() + return self.source + end + self.getPlayerId = self.getSource + + function self.getMaxWeight() + return self.maxWeight + end + + function self.canCarryItem(itemName, count) + if ESX.Items[itemName] then + local currentWeight, itemWeight = self.weight, ESX.Items[itemName].weight + local newWeight = currentWeight + (itemWeight * count) + + return newWeight <= self.maxWeight + else + print(('[^3WARNING^7] Item ^5"%s"^7 was used but does not exist!'):format(itemName)) + return false + end + end + + function self.canSwapItem(firstItem, firstItemCount, testItem, testItemCount) + local firstItemObject = self.getInventoryItem(firstItem) + if not firstItemObject then + return false + end + local testItemObject = self.getInventoryItem(testItem) + if not testItemObject then + return false + end + + if firstItemObject.count >= firstItemCount then + local weightWithoutFirstItem = ESX.Math.Round(self.weight - (firstItemObject.weight * firstItemCount)) + local weightWithTestItem = ESX.Math.Round(weightWithoutFirstItem + (testItemObject.weight * testItemCount)) + + return weightWithTestItem <= self.maxWeight + end + + return false + end + + function self.setMaxWeight(newWeight) + self.maxWeight = newWeight + self.triggerEvent("esx:setMaxWeight", self.maxWeight) + end + + function self.setJob(newJob, grade, onDuty) + grade = tostring(grade) + local lastJob = self.job + + if not ESX.DoesJobExist(newJob, grade) then + return print(("[ESX] [^3WARNING^7] Ignoring invalid ^5.setJob()^7 usage for ID: ^5%s^7, Job: ^5%s^7"):format(self.source, newJob)) + end + + if newJob == "unemployed" then + onDuty = false + end + + if type(onDuty) ~= "boolean" then + onDuty = Config.DefaultJobDuty + end + + local jobObject, gradeObject = ESX.Jobs[newJob], ESX.Jobs[newJob].grades[grade] + + self.job = { + id = jobObject.id, + name = jobObject.name, + label = jobObject.label, + type = jobObject.type, + onDuty = onDuty, + + grade = tonumber(grade) or 0, + grade_name = gradeObject.name, + grade_label = gradeObject.label, + grade_salary = gradeObject.salary, + + skin_male = gradeObject.skin_male and json.decode(gradeObject.skin_male) or {}, + skin_female = gradeObject.skin_female and json.decode(gradeObject.skin_female) or {}, + } + + self.metadata.jobDuty = onDuty + TriggerEvent("esx:setJob", self.source, self.job, lastJob) + self.triggerEvent("esx:setJob", self.job, lastJob) + Player(self.source).state:set("job", self.job, true) + end + + function self.addWeapon(weaponName, ammo) + if not self.hasWeapon(weaponName) then + local weaponLabel = ESX.GetWeaponLabel(weaponName) + + table.insert(self.loadout, { + name = weaponName, + ammo = ammo, + label = weaponLabel, + components = {}, + tintIndex = 0, + }) + + GiveWeaponToPed(GetPlayerPed(self.source), joaat(weaponName), ammo, false, false) + self.triggerEvent("esx:addInventoryItem", weaponLabel, false, true) + self.triggerEvent("esx:addLoadoutItem", weaponName, weaponLabel, ammo) + end + end + + function self.addWeaponComponent(weaponName, weaponComponent) + local loadoutNum , weapon = self.getWeapon(weaponName) + + if weapon then + local component = ESX.GetWeaponComponent(weaponName, weaponComponent) + + if component then + if not self.hasWeaponComponent(weaponName, weaponComponent) then + self.loadout[loadoutNum].components[#self.loadout[loadoutNum].components + 1] = weaponComponent + local componentHash = ESX.GetWeaponComponent(weaponName, weaponComponent).hash + GiveWeaponComponentToPed(GetPlayerPed(self.source), joaat(weaponName), componentHash) + self.triggerEvent("esx:addInventoryItem", component.label, false, true) + end + end + end + end + + function self.addWeaponAmmo(weaponName, ammoCount) + local _, weapon = self.getWeapon(weaponName) + + if weapon then + weapon.ammo = weapon.ammo + ammoCount + SetPedAmmo(GetPlayerPed(self.source), joaat(weaponName), weapon.ammo) + end + end + + function self.updateWeaponAmmo(weaponName, ammoCount) + local _, weapon = self.getWeapon(weaponName) + + if not weapon then + return + end + + weapon.ammo = ammoCount + + if weapon.ammo <= 0 then + local _, weaponConfig = ESX.GetWeapon(weaponName) + if weaponConfig.throwable then + self.removeWeapon(weaponName) + end + end + end + + function self.setWeaponTint(weaponName, weaponTintIndex) + local loadoutNum , weapon = self.getWeapon(weaponName) + + if weapon then + local _, weaponObject = ESX.GetWeapon(weaponName) + + if weaponObject.tints and weaponObject.tints[weaponTintIndex] then + self.loadout[loadoutNum].tintIndex = weaponTintIndex + self.triggerEvent("esx:setWeaponTint", weaponName, weaponTintIndex) + self.triggerEvent("esx:addInventoryItem", weaponObject.tints[weaponTintIndex], false, true) + end + end + end + + function self.getWeaponTint(weaponName) + local _, weapon = self.getWeapon(weaponName) + + if weapon then + return weapon.tintIndex + end + + return 0 + end + + function self.removeWeapon(weaponName) + local weaponLabel, playerPed = nil, GetPlayerPed(self.source) + + if not playerPed then + return error("xPlayer.removeWeapon ^5invalid^1 player ped!") + end + + for k, v in ipairs(self.loadout) do + if v.name == weaponName then + weaponLabel = v.label + + for _, v2 in ipairs(v.components) do + self.removeWeaponComponent(weaponName, v2) + end + + local weaponHash = joaat(v.name) + RemoveWeaponFromPed(playerPed, weaponHash) + SetPedAmmo(playerPed, weaponHash, 0) + + table.remove(self.loadout, k) + break + end + end + + if weaponLabel then + self.triggerEvent("esx:removeInventoryItem", weaponLabel, false, true) + self.triggerEvent("esx:removeLoadoutItem", weaponName, weaponLabel) + end + end + + function self.removeWeaponComponent(weaponName, weaponComponent) + local loadoutNum , weapon = self.getWeapon(weaponName) + + if weapon then + local component = ESX.GetWeaponComponent(weaponName, weaponComponent) + + if component then + if self.hasWeaponComponent(weaponName, weaponComponent) then + for k, v in ipairs(self.loadout[loadoutNum].components) do + if v == weaponComponent then + table.remove(self.loadout[loadoutNum].components, k) + break + end + end + + self.triggerEvent("esx:removeWeaponComponent", weaponName, weaponComponent) + self.triggerEvent("esx:removeInventoryItem", component.label, false, true) + end + end + end + end + + function self.removeWeaponAmmo(weaponName, ammoCount) + local _, weapon = self.getWeapon(weaponName) + + if weapon then + weapon.ammo = weapon.ammo - ammoCount + SetPedAmmo(GetPlayerPed(self.source), joaat(weaponName), weapon.ammo) + end + end + + function self.hasWeaponComponent(weaponName, weaponComponent) + local _, weapon = self.getWeapon(weaponName) + + if weapon then + for _, v in ipairs(weapon.components) do + if v == weaponComponent then + return true + end + end + + return false + end + + return false + end + + function self.hasWeapon(weaponName) + for _, v in ipairs(self.loadout) do + if v.name == weaponName then + return true + end + end + + return false + end + + function self.hasItem(item) + for _, v in ipairs(self.inventory) do + if v.name == item and v.count >= 1 then + return v, v.count + end + end + + return false + end + + function self.getWeapon(weaponName) + for k, v in ipairs(self.loadout) do + if v.name == weaponName then + return k, v + end + end + + return nil, nil + end + + function self.showNotification(msg, notifyType, length, title, position) + self.triggerEvent("esx:showNotification", msg, notifyType, length, title, position) + end + + function self.showAdvancedNotification(sender, subject, msg, textureDict, iconType, flash, saveToBrief, hudColorIndex) + self.triggerEvent("esx:showAdvancedNotification", sender, subject, msg, textureDict, iconType, flash, saveToBrief, hudColorIndex) + end + + function self.showHelpNotification(msg, thisFrame, beep, duration) + self.triggerEvent("esx:showHelpNotification", msg, thisFrame, beep, duration) + end + + function self.getMeta(index, subIndex) + if not index then + return self.metadata + end + + if type(index) ~= "string" then + error("xPlayer.getMeta ^5index^1 should be ^5string^1!") + return + end + + local metaData = self.metadata[index] + if metaData == nil then + return Config.EnableDebug and error(("xPlayer.getMeta ^5%s^1 not exist!"):format(index)) or nil + end + + if subIndex and type(metaData) == "table" then + local _type = type(subIndex) + + if _type == "string" then + local value = metaData[subIndex] + return value + end + + if _type == "table" then + local returnValues = {} + + for i = 1, #subIndex do + local key = subIndex[i] + if type(key) == "string" then + returnValues[key] = self.getMeta(index, key) + else + error(("xPlayer.getMeta subIndex should be ^5string^1 or ^5table^1! that contains ^5string^1, received ^5%s^1!, skipping..."):format(type(key))) + end + end + + return returnValues + end + + error(("xPlayer.getMeta subIndex should be ^5string^1 or ^5table^1!, received ^5%s^1!"):format(_type)) + return + end + + return metaData + end + + function self.setMeta(index, value, subValue) + if not index then + return error("xPlayer.setMeta ^5index^1 is Missing!") + end + + if type(index) ~= "string" then + return error("xPlayer.setMeta ^5index^1 should be ^5string^1!") + end + + if value == nil then + return error("xPlayer.setMeta value is missing!") + end + + local _type = type(value) + + if not subValue then + if _type ~= "number" and _type ~= "string" and _type ~= "table" then + return error(("xPlayer.setMeta ^5%s^1 should be ^5number^1 or ^5string^1 or ^5table^1!"):format(value)) + end + + self.metadata[index] = value + else + if _type ~= "string" then + return error(("xPlayer.setMeta ^5value^1 should be ^5string^1 as a subIndex!"):format(value)) + end + + if not self.metadata[index] or type(self.metadata[index]) ~= "table" then + self.metadata[index] = {} + end + + self.metadata[index] = type(self.metadata[index]) == "table" and self.metadata[index] or {} + self.metadata[index][value] = subValue + end + self.triggerEvent('esx:updatePlayerData', 'metadata', self.metadata) + end + + function self.clearMeta(index, subValues) + if not index then + return error("xPlayer.clearMeta ^5index^1 is Missing!") + end + + if type(index) ~= "string" then + return error("xPlayer.clearMeta ^5index^1 should be ^5string^1!") + end + + local metaData = self.metadata[index] + if metaData == nil then + if Config.EnableDebug then + error(("xPlayer.clearMeta ^5%s^1 does not exist!"):format(index)) + end + + return + end + + if not subValues then + -- If no subValues is provided, we will clear the entire value in the metaData table + self.metadata[index] = nil + elseif type(subValues) == "string" then + -- If subValues is a string, we will clear the specific subValue within the table + if type(metaData) == "table" then + metaData[subValues] = nil + else + return error(("xPlayer.clearMeta ^5%s^1 is not a table! Cannot clear subValue ^5%s^1."):format(index, subValues)) + end + elseif type(subValues) == "table" then + -- If subValues is a table, we will clear multiple subValues within the table + for i = 1, #subValues do + local subValue = subValues[i] + if type(subValue) == "string" then + if type(metaData) == "table" then + metaData[subValue] = nil + else + error(("xPlayer.clearMeta ^5%s^1 is not a table! Cannot clear subValue ^5%s^1."):format(index, subValue)) + end + else + error(("xPlayer.clearMeta subValues should contain ^5string^1, received ^5%s^1, skipping..."):format(type(subValue))) + end + end + else + return error(("xPlayer.clearMeta ^5subValues^1 should be ^5string^1 or ^5table^1, received ^5%s^1!"):format(type(subValues))) + end + self.triggerEvent('esx:updatePlayerData', 'metadata', self.metadata) + end + + function self.executeCommand(command) + if type(command) ~= "string" then + error("xPlayer.executeCommand must be of type string!") + return + end + + self.triggerEvent("esx:executeCommand", command) + end + + for _, funcs in pairs(Core.PlayerFunctionOverrides) do + for fnName, fn in pairs(funcs) do + self[fnName] = fn(self) + end + end + + return self +end + +local function runStaticPlayerMethod(src, method, ...) + local xPlayer = ESX.Players[src] + if not xPlayer then + return + end + + if not ESX.IsFunctionReference(xPlayer[method]) then + error(("Attempted to call invalid method on playerId %s: %s"):format(src, method)) + end + + return xPlayer[method](...) +end +exports("RunStaticPlayerMethod", runStaticPlayerMethod) diff --git a/resources/[core]/es_extended/server/classes/vehicle.lua b/resources/[core]/es_extended/server/classes/vehicle.lua new file mode 100644 index 0000000..b85c8f6 --- /dev/null +++ b/resources/[core]/es_extended/server/classes/vehicle.lua @@ -0,0 +1,237 @@ +---@class CVehicleData +---@field plate string +---@field netId number +---@field entity number +---@field modelHash number +---@field owner string + +---@class CExtendedVehicle +---@field plate string +---@field isValid fun(self:CExtendedVehicle):boolean +---@field new fun(owner:string, plate:string, coords:vector4): CExtendedVehicle? +---@field getFromPlate fun(plate:string):CExtendedVehicle? +---@field getPlate fun(self:CExtendedVehicle):string? +---@field getNetId fun(self:CExtendedVehicle):number? +---@field getEntity fun(self:CExtendedVehicle):number? +---@field getModelHash fun(self:CExtendedVehicle):number? +---@field getOwner fun(self:CExtendedVehicle):string? +---@field setPlate fun(self:CExtendedVehicle, newPlate:string):boolean +---@field setProps fun(self:CExtendedVehicle, newProps:table):boolean +---@field setOwner fun(self:CExtendedVehicle, newOwner:string):boolean +---@field delete fun(self:CExtendedVehicle, garageName:string?, isImpound:boolean?):nil +Core.vehicleClass = { + plate = "", + new = function(owner, plate, coords) + assert(type(owner) == "string", "Expected 'owner' to be a string") + assert(type(plate) == "string", "Expected 'plate' to be a string") + assert(type(coords) == "vector4", "Expected 'coords' to be a vector4") + + local xVehicle = Core.vehicleClass.getFromPlate(plate) + if xVehicle then + return xVehicle + end + + local vehicleProps = MySQL.scalar.await("SELECT `vehicle` FROM `owned_vehicles` WHERE `stored` = true AND `owner` = ? AND `plate` = ? LIMIT 1", { owner, plate }) + if not vehicleProps then + return + end + vehicleProps = json.decode(vehicleProps) + + if type(vehicleProps.model) ~= "number" then + vehicleProps.model = joaat(vehicleProps.model) + end + + local netId = ESX.OneSync.SpawnVehicle(vehicleProps.model, coords.xyz, coords.w, vehicleProps) + if not netId then + return + end + + local entity = NetworkGetEntityFromNetworkId(netId) + if entity <= 0 then + return + end + Entity(entity).state:set("owner", owner, false) + Entity(entity).state:set("plate", plate, false) + + ---@type CVehicleData + local vehicleData = { + plate = plate, + entity = entity, + netId = netId, + modelHash = vehicleProps.model, + owner = owner, + } + Core.vehicles[plate] = vehicleData + + MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = false WHERE `owner` = ? AND `plate` = ?", { owner, plate }) + + local obj = table.clone(Core.vehicleClass) + obj.plate = plate + TriggerEvent("esx:createdExtendedVehicle", obj) + + return obj + end, + getFromPlate = function(plate) + assert(type(plate) == "string", "Expected 'plate' to be a string") + + if Core.vehicles[plate] then + local obj = table.clone(Core.vehicleClass) + obj.plate = plate + + if obj:isValid() then + return obj + end + end + end, + isValid = function(self) + local vehicleData = Core.vehicles[self.plate] + if not vehicleData then + return false + end + + local entity = NetworkGetEntityFromNetworkId(vehicleData.netId) + if entity <= 0 or Entity(entity).state.owner ~= vehicleData.owner or Entity(entity).state.plate ~= vehicleData.plate then + self:delete() + return false + end + + vehicleData.entity = entity + + return true + end, + getNetId = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].netId + end, + getEntity = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].entity + end, + getPlate = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].plate + end, + getModelHash = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].modelHash + end, + getOwner = function(self) + if not self:isValid() then + return + end + + return Core.vehicles[self.plate].owner + end, + setPlate = function(self, newPlate) + if not self:isValid() then + return false + end + assert(type(newPlate) == "string", "Expected 'plate' to be a string") + + local vehicleData = Core.vehicles[self.plate] + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { newPlate, vehicleData.plate, vehicleData.owner }) + if affectedRows <= 0 then + self:delete() + return false + end + + Entity(vehicleData.entity).state:set("plate", newPlate, false) + SetVehicleNumberPlateText(vehicleData.entity, newPlate) + + local oldPlate = vehicleData.plate + vehicleData.plate = newPlate + Core.vehicles[newPlate] = table.clone(vehicleData) + Core.vehicles[oldPlate] = nil + + TriggerEvent("esx:changedExtendedVehiclePlate", vehicleData.plate, oldPlate) + Wait(0) + + return true + end, + setProps = function(self, newProps) + if not self:isValid() then + return false + end + assert(type(newProps) == "table", "Expected 'props' to be a table") + + local vehicleData = Core.vehicles[self.plate] + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(newProps), vehicleData.plate, vehicleData.owner) + if affectedRows <= 0 then + self:delete() + return false + end + + Entity(vehicleData.entity).state:set("VehicleProperties", newProps, true) + + return true + end, + setOwner = function(self, newOwner) + if not self:isValid() then + return false + end + assert(type(newOwner) == "string", "Expected 'owner' to be a string") + + local vehicleData = Core.vehicles[self.plate] + if vehicleData.owner == newOwner then + return true + end + + local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE owner = ? AND `plate` = ?", { newOwner, vehicleData.owner, vehicleData.plate }) + if affectedRows <= 0 then + self:delete() + return false + end + + Entity(vehicleData.entity).state:set("owner", newOwner, false) + vehicleData.owner = newOwner + + return true + end, + delete = function(self, garageName, isImpound) + if type(garageName) ~= "string" then + garageName = nil + end + if type(isImpound) ~= "boolean" then + isImpound = false + end + + local vehicleData = Core.vehicles[self.plate] + if not vehicleData then + return + end + + local entity = NetworkGetEntityFromNetworkId(vehicleData.netId) + if entity >= 0 and Entity(entity).state.owner == vehicleData.owner then + DeleteEntity(vehicleData.entity) + end + + local query = "UPDATE `owned_vehicles` SET `stored` = true WHERE `plate` = ? AND `owner` = ?" + local queryParams = { vehicleData.plate, vehicleData.owner } + if garageName then + if isImpound then + query = "UPDATE `owned_vehicles` SET `stored` = true, `parking` = NULL, `pound` = ? WHERE `plate` = ? AND `owner` = ?" + else + query = "UPDATE `owned_vehicles` SET `stored` = true, `pound` = NULL, `parking` = ? WHERE `plate` = ? AND `owner` = ?" + end + + queryParams = { garageName, vehicleData.plate, vehicleData.owner } + end + + MySQL.update.await(query, queryParams) + TriggerEvent("esx:deletedExtendedVehicle", self) + + Core.vehicles[self.plate] = nil + end, +} diff --git a/resources/[core]/es_extended/server/common.lua b/resources/[core]/es_extended/server/common.lua new file mode 100644 index 0000000..a1aa9fe --- /dev/null +++ b/resources/[core]/es_extended/server/common.lua @@ -0,0 +1,54 @@ +ESX.Players = {} +ESX.Jobs = {} +ESX.Items = {} + +RegisterNetEvent("esx:onPlayerSpawn", function() + ESX.Players[source].spawned = true +end) + +if Config.CustomInventory then + SetConvarReplicated("inventory:framework", "esx") + SetConvarReplicated("inventory:weight", tostring(Config.MaxWeight * 1000)) +end + +local function StartDBSync() + CreateThread(function() + local interval = 10 * 60 * 1000 + while true do + Wait(interval) + Core.SavePlayers() + end + end) +end + +MySQL.ready(function() + Core.DatabaseConnected = true + + if not Config.CustomInventory then + ESX.RefreshItems() + end + + ESX.RefreshJobs() + + print(("[^2INFO^7] ESX ^5Legacy %s^0 initialized!"):format(GetResourceMetadata(GetCurrentResourceName(), "version", 0))) + + StartDBSync() + if Config.EnablePaycheck then + StartPayCheck() + end +end) + +RegisterNetEvent("esx:clientLog", function(msg) + if Config.EnableDebug then + print(("[^2TRACE^7] %s^7"):format(msg)) + end +end) + +RegisterNetEvent("esx:ReturnVehicleType", function(Type, Request) + if Core.ClientCallbacks[Request] then + Core.ClientCallbacks[Request](Type) + Core.ClientCallbacks[Request] = nil + end +end) + +GlobalState.playerCount = 0 diff --git a/resources/[core]/es_extended/server/core.lua b/resources/[core]/es_extended/server/core.lua new file mode 100644 index 0000000..b897983 --- /dev/null +++ b/resources/[core]/es_extended/server/core.lua @@ -0,0 +1,14 @@ +Core = {} +Core.JobsPlayerCount = {} +Core.UsableItemsCallbacks = {} +Core.RegisteredCommands = {} +Core.Pickups = {} +Core.PickupId = 0 +Core.PlayerFunctionOverrides = {} +Core.DatabaseConnected = false +Core.playersByIdentifier = {} +Core.JobsLoaded = false + +---@type table +Core.vehicles = {} +Core.vehicleTypesByModel = {} \ No newline at end of file diff --git a/resources/[core]/es_extended/server/functions.lua b/resources/[core]/es_extended/server/functions.lua new file mode 100644 index 0000000..7ab5f9b --- /dev/null +++ b/resources/[core]/es_extended/server/functions.lua @@ -0,0 +1,909 @@ +---@param msg string +---@return nil +function ESX.Trace(msg) + if Config.EnableDebug then + print(("[^2TRACE^7] %s^7"):format(msg)) + end +end + +--- Triggers an event for one or more clients. +---@param eventName string The name of the event to trigger. +---@param playerIds table|number If a number, represents a single player ID. If a table, represents an array of player IDs. +---@param ... any Additional arguments to pass to the event handler. +function ESX.TriggerClientEvent(eventName, playerIds, ...) + if type(playerIds) == "number" then + TriggerClientEvent(eventName, playerIds, ...) + return + end + + local payload = msgpack.pack_args(...) + local payloadLength = #payload + + for i = 1, #playerIds do + TriggerClientEventInternal(eventName, playerIds[i], payload, payloadLength) + end +end + +---@param name string | table +---@param group string | table +---@param cb function +---@param allowConsole? boolean +---@param suggestion? table +function ESX.RegisterCommand(name, group, cb, allowConsole, suggestion) + if type(name) == "table" then + for _, v in ipairs(name) do + ESX.RegisterCommand(v, group, cb, allowConsole, suggestion) + end + return + end + + if Core.RegisteredCommands[name] then + print(('[^3WARNING^7] Command ^5"%s" ^7already registered, overriding command'):format(name)) + + if Core.RegisteredCommands[name].suggestion then + TriggerClientEvent("chat:removeSuggestion", -1, ("/%s"):format(name)) + end + end + + if suggestion then + if not suggestion.arguments then + suggestion.arguments = {} + end + if not suggestion.help then + suggestion.help = "" + end + + TriggerClientEvent("chat:addSuggestion", -1, ("/%s"):format(name), suggestion.help, suggestion.arguments) + end + + Core.RegisteredCommands[name] = { group = group, cb = cb, allowConsole = allowConsole, suggestion = suggestion } + + RegisterCommand(name, function(playerId, args) + local command = Core.RegisteredCommands[name] + + if not command.allowConsole and playerId == 0 then + print(("[^3WARNING^7] ^5%s^0"):format(TranslateCap("commanderror_console"))) + else + local xPlayer, err = ESX.Players[playerId], nil + + if command.suggestion then + if command.suggestion.validate then + if #args ~= #command.suggestion.arguments then + err = TranslateCap("commanderror_argumentmismatch", #args, #command.suggestion.arguments) + end + end + + if not err and command.suggestion.arguments then + local newArgs = {} + + for k, v in ipairs(command.suggestion.arguments) do + if v.type then + if v.type == "number" then + local newArg = tonumber(args[k]) + + if newArg then + newArgs[v.name] = newArg + else + err = TranslateCap("commanderror_argumentmismatch_number", k) + end + elseif v.type == "player" or v.type == "playerId" then + local targetPlayer = tonumber(args[k]) + + if args[k] == "me" then + targetPlayer = playerId + end + + if targetPlayer then + local xTargetPlayer = ESX.GetPlayerFromId(targetPlayer) + + if xTargetPlayer then + if v.type == "player" then + newArgs[v.name] = xTargetPlayer + else + newArgs[v.name] = targetPlayer + end + else + err = TranslateCap("commanderror_invalidplayerid") + end + else + err = TranslateCap("commanderror_argumentmismatch_number", k) + end + elseif v.type == "string" then + local newArg = tonumber(args[k]) + if not newArg then + newArgs[v.name] = args[k] + else + err = TranslateCap("commanderror_argumentmismatch_string", k) + end + elseif v.type == "item" then + if ESX.Items[args[k]] then + newArgs[v.name] = args[k] + else + err = TranslateCap("commanderror_invaliditem") + end + elseif v.type == "weapon" then + if ESX.GetWeapon(args[k]) then + newArgs[v.name] = string.upper(args[k]) + else + err = TranslateCap("commanderror_invalidweapon") + end + elseif v.type == "any" then + newArgs[v.name] = args[k] + elseif v.type == "merge" then + local length = 0 + for i = 1, k - 1 do + length = length + string.len(args[i]) + 1 + end + local merge = table.concat(args, " ") + + newArgs[v.name] = string.sub(merge, length) + elseif v.type == "coordinate" then + local coord = tonumber(args[k]:match("(-?%d+%.?%d*)")) + if not coord then + err = TranslateCap("commanderror_argumentmismatch_number", k) + else + newArgs[v.name] = coord + end + end + end + + if ESX.IsFunctionReference(v.Validator?.validate) and not err then + local candidate = newArgs[v.name] + local ok, res = pcall(v.Validator.validate, candidate) + if not ok or res ~= true then + err = v.Validator.err or TranslateCap("commanderror_argumentmismatch") + end + end + + --backwards compatibility + if v.validate ~= nil and not v.validate then + err = nil + end + + if err then + break + end + end + + args = newArgs + end + end + + if err then + if playerId == 0 then + print(("[^3WARNING^7] %s^7"):format(err)) + else + xPlayer.showNotification(err) + end + else + cb(xPlayer or false, args, function(msg) + if playerId == 0 then + print(("[^3WARNING^7] %s^7"):format(msg)) + else + xPlayer.showNotification(msg) + end + end) + end + end + end, true) + + if type(group) == "table" then + for _, v in ipairs(group) do + ExecuteCommand(("add_ace group.%s command.%s allow"):format(v, name)) + end + else + ExecuteCommand(("add_ace group.%s command.%s allow"):format(group, name)) + end +end + +local function updateHealthAndArmorInMetadata(xPlayer) + local ped = GetPlayerPed(xPlayer.source) + xPlayer.setMeta("health", GetEntityHealth(ped)) + xPlayer.setMeta("armor", GetPedArmour(ped)) + xPlayer.setMeta("lastPlaytime", xPlayer.getPlayTime()) +end + +---@param xPlayer table +---@param cb? function +---@return nil +function Core.SavePlayer(xPlayer, cb) + if not xPlayer.spawned then + return cb and cb() + end + + updateHealthAndArmorInMetadata(xPlayer) + local parameters = { + json.encode(xPlayer.getAccounts(true)), + xPlayer.job.name, + xPlayer.job.grade, + xPlayer.group, + json.encode(xPlayer.getCoords(false, true)), + json.encode(xPlayer.getInventory(true)), + json.encode(xPlayer.getLoadout(true)), + json.encode(xPlayer.getMeta()), + xPlayer.identifier, + } + + MySQL.prepare( + "UPDATE `users` SET `accounts` = ?, `job` = ?, `job_grade` = ?, `group` = ?, `position` = ?, `inventory` = ?, `loadout` = ?, `metadata` = ? WHERE `identifier` = ?", + parameters, + function(affectedRows) + if affectedRows == 1 then + print(('[^2INFO^7] Saved player ^5"%s^7"'):format(xPlayer.name)) + TriggerEvent("esx:playerSaved", xPlayer.playerId, xPlayer) + end + if cb then + cb() + end + end + ) +end + +---@param cb? function +---@return nil +function Core.SavePlayers(cb) + local xPlayers = ESX.Players + if not next(xPlayers) then + return + end + + local startTime = os.time() + local parameters = {} + + for _, xPlayer in pairs(ESX.Players) do + updateHealthAndArmorInMetadata(xPlayer) + parameters[#parameters + 1] = { + json.encode(xPlayer.getAccounts(true)), + xPlayer.job.name, + xPlayer.job.grade, + xPlayer.group, + json.encode(xPlayer.getCoords(false, true)), + json.encode(xPlayer.getInventory(true)), + json.encode(xPlayer.getLoadout(true)), + json.encode(xPlayer.getMeta()), + xPlayer.identifier, + } + end + + MySQL.prepare( + "UPDATE `users` SET `accounts` = ?, `job` = ?, `job_grade` = ?, `group` = ?, `position` = ?, `inventory` = ?, `loadout` = ?, `metadata` = ? WHERE `identifier` = ?", + parameters, + function(results) + if not results then + return + end + + if type(cb) == "function" then + return cb() + end + + print(("[^2INFO^7] Saved ^5%s^7 %s over ^5%s^7 ms"):format(#parameters, + #parameters > 1 and "players" or "player", ESX.Math.Round((os.time() - startTime) / 1000000, 2))) + end + ) +end + +ESX.GetPlayers = GetPlayers + +local function checkTable(key, val, xPlayer, xPlayers, minimal) + for valIndex = 1, #val do + local value = val[valIndex] + if not xPlayers[value] then + xPlayers[value] = {} + end + + if (key == "job" and xPlayer.job.name == value) or xPlayer[key] == value then + xPlayers[value][#xPlayers[value] + 1] = (minimal and xPlayer.source or xPlayer) + end + end +end + +---@param key? string +---@param val? string|table +---@param minimal? boolean +---@return xPlayer[]|number[]|table|table +function ESX.GetExtendedPlayers(key, val, minimal) + if not key then + if not minimal then + return ESX.Table.ToArray(ESX.Players) + end + + local xPlayers = {} + local index = 1 + for src, _ in pairs(ESX.Players) do + xPlayers[index] = src + index += 1 + end + + return xPlayers + end + + local xPlayers = {} + if type(val) == "table" then + for _, xPlayer in pairs(ESX.Players) do + checkTable(key, val, xPlayer, xPlayers, minimal) + end + + return xPlayers + end + + for _, xPlayer in pairs(ESX.Players) do + if (key == "job" and xPlayer.job.name == val) or xPlayer[key] == val then + xPlayers[#xPlayers + 1] = (minimal and xPlayer.source or xPlayer) + end + end + + return xPlayers +end + +---@param key? string +---@param val? string|table +---@return number | table +function ESX.GetNumPlayers(key, val) + if not key then + return #GetPlayers() + end + + if type(val) == "table" then + local numPlayers = {} + if key == "job" then + for _, v in ipairs(val) do + numPlayers[v] = (Core.JobsPlayerCount[v] or 0) + end + return numPlayers + end + + local filteredPlayers = ESX.GetExtendedPlayers(key, val) + for i, v in pairs(filteredPlayers) do + numPlayers[i] = (#v or 0) + end + return numPlayers + end + + if key == "job" then + return (Core.JobsPlayerCount[val] or 0) + end + + return #ESX.GetExtendedPlayers(key, val) +end + +---@param source number +---@return xPlayer? +function ESX.GetPlayerFromId(source) + return ESX.Players[tonumber(source)] +end + +---@param identifier string +---@return xPlayer? +function ESX.GetPlayerFromIdentifier(identifier) + return Core.playersByIdentifier[identifier] +end + +---@param identifier string +---@return number playerId +function ESX.GetPlayerIdFromIdentifier(identifier) + return Core.playersByIdentifier[identifier]?.source +end + +---@param source number +---@return boolean +---@diagnostic disable-next-line: duplicate-set-field +function ESX.IsPlayerLoaded(source) + return ESX.Players[source] ~= nil +end + +---@param playerId number | string +---@return string, number +function ESX.GetIdentifier(playerId) + local fxDk = GetConvarInt("sv_fxdkMode", 0) + if fxDk == 1 then + return "ESX-DEBUG-LICENCE", 0 + end + + playerId = tostring(playerId) + + local identifierType = Config.Identifier + local identifier = GetPlayerIdentifierByType(playerId, identifierType) + + assert(identifier, ("[ESX] GetIdentifier failed: no identifier found for playerId %s with type '%s'"):format(playerId, identifierType)) + + return identifier:gsub(("%s:"):format(identifierType), "") +end + +---@param model string|number +---@param player number +---@param cb function? +---@return string? +---@diagnostic disable-next-line: duplicate-set-field +function ESX.GetVehicleType(model, player, cb) + if cb and not ESX.IsFunctionReference(cb) then + error("Invalid callback function") + end + + local promise = not cb and promise.new() + local function resolve(result) + if promise then + promise:resolve(result) + elseif cb then + cb(result) + end + + return result + end + + model = type(model) == "string" and joaat(model) or model + + if Core.vehicleTypesByModel[model] then + return resolve(Core.vehicleTypesByModel[model]) + end + + ESX.TriggerClientCallback(player, "esx:GetVehicleType", function(vehicleType) + Core.vehicleTypesByModel[model] = vehicleType + resolve(vehicleType) + end, model) + + if promise then + return Citizen.Await(promise) + end +end + +---@param name string +---@param title string +---@param color string +---@param message string +---@return nil +function ESX.DiscordLog(name, title, color, message) + local webHook = Config.DiscordLogs.Webhooks[name] or Config.DiscordLogs.Webhooks.default + local embedData = { + { + ["title"] = title, + ["color"] = Config.DiscordLogs.Colors[color] or Config.DiscordLogs.Colors.default, + ["footer"] = { + ["text"] = "| ESX Logs | " .. os.date(), + ["icon_url"] = + "https://cdn.discordapp.com/attachments/944789399852417096/1020099828266586193/blanc-800x800.png", + }, + ["description"] = message, + ["author"] = { + ["name"] = "ESX Framework", + ["icon_url"] = "https://cdn.discordapp.com/emojis/939245183621558362.webp?size=128&quality=lossless", + }, + }, + } + PerformHttpRequest( + webHook, + function() + return + end, + "POST", + json.encode({ + username = "Logs", + embeds = embedData, + }), + { + ["Content-Type"] = "application/json", + } + ) +end + +---@param name string +---@param title string +---@param color string +---@param fields table +---@return nil +function ESX.DiscordLogFields(name, title, color, fields) + for i = 1, #fields do + local field = fields[i] + field.value = tostring(field.value) + end + + local webHook = Config.DiscordLogs.Webhooks[name] or Config.DiscordLogs.Webhooks.default + local embedData = { + { + ["title"] = title, + ["color"] = Config.DiscordLogs.Colors[color] or Config.DiscordLogs.Colors.default, + ["footer"] = { + ["text"] = "| ESX Logs | " .. os.date(), + ["icon_url"] = + "https://cdn.discordapp.com/attachments/944789399852417096/1020099828266586193/blanc-800x800.png", + }, + ["fields"] = fields, + ["description"] = "", + ["author"] = { + ["name"] = "ESX Framework", + ["icon_url"] = "https://cdn.discordapp.com/emojis/939245183621558362.webp?size=128&quality=lossless", + }, + }, + } + PerformHttpRequest( + webHook, + function() + return + end, + "POST", + json.encode({ + username = "Logs", + embeds = embedData, + }), + { + ["Content-Type"] = "application/json", + } + ) +end + +---@return nil +function ESX.RefreshJobs() + Core.JobsLoaded = false + + local Jobs = {} + local jobs = MySQL.query.await("SELECT * FROM jobs") + + for _, v in ipairs(jobs) do + Jobs[v.name] = v + Jobs[v.name].grades = {} + end + + local jobGrades = MySQL.query.await("SELECT * FROM job_grades") + + for _, v in ipairs(jobGrades) do + if Jobs[v.job_name] then + Jobs[v.job_name].grades[tostring(v.grade)] = v + else + print(('[^3WARNING^7] Ignoring job grades for ^5"%s"^0 due to missing job'):format(v.job_name)) + end + end + + for _, v in pairs(Jobs) do + if ESX.Table.SizeOf(v.grades) == 0 then + Jobs[v.name] = nil + print(('[^3WARNING^7] Ignoring job ^5"%s"^0 due to no job grades found'):format(v.name)) + end + end + + if not Jobs then + -- Fallback data, if no jobs exist + ESX.Jobs["unemployed"] = { name = "unemployed", label = "Unemployed", type = "civ", whitelisted = false, grades = { ["0"] = { grade = 0, name = "unemployed", label = "Unemployed", salary = 200, skin_male = {}, skin_female = {} } } } + else + ESX.Jobs = Jobs + end + + TriggerEvent("esx:jobsRefreshed") + Core.JobsLoaded = true +end + +---@param item string +---@param cb function +---@return nil +function ESX.RegisterUsableItem(item, cb) + Core.UsableItemsCallbacks[item] = cb +end + +---@param source number +---@param item string +---@param ... any +---@return nil +function ESX.UseItem(source, item, ...) + if ESX.Items[item] then + local itemCallback = Core.UsableItemsCallbacks[item] + + if itemCallback then + local success, result = pcall(itemCallback, source, item, ...) + + if not success then + return result and print(result) or + print(('[^3WARNING^7] An error occured when using item ^5"%s"^7! This was not caused by ESX.'):format( + item)) + end + end + else + print(('[^3WARNING^7] Item ^5"%s"^7 was used but does not exist!'):format(item)) + end +end + +---@param index string +---@param overrides table +---@return nil +function ESX.RegisterPlayerFunctionOverrides(index, overrides) + Core.PlayerFunctionOverrides[index] = overrides +end + +---@param index string +---@return nil +function ESX.SetPlayerFunctionOverride(index) + if not index or not Core.PlayerFunctionOverrides[index] then + return print("[^3WARNING^7] No valid index provided.") + end + + Config.PlayerFunctionOverride = index +end + +---@param item string +---@return string? +---@diagnostic disable-next-line: duplicate-set-field +function ESX.GetItemLabel(item) + if ESX.Items[item] then + return ESX.Items[item].label + else + print(("[^3WARNING^7] Attemting to get invalid Item -> ^5%s^7"):format(item)) + end +end + +---@param jobType string|string[]? +---@return table +function ESX.GetJobs(jobType) + while not Core.JobsLoaded do + Citizen.Wait(200) + end + + if not jobType then + return ESX.Jobs + end + + jobType = type(jobType) == "string" and { jobType } or jobType + + local jobTypeLookup = {} + for i = 1, #jobType do + jobTypeLookup[jobType[i]] = true + end + + local filteredJobs = {} + for jobName, jobObject in pairs(ESX.Jobs) do + if jobTypeLookup[jobObject.type] then + filteredJobs[jobName] = jobObject + end + end + + return filteredJobs +end + +---@return table +function ESX.GetItems() + return ESX.Items +end + +---@return table +function ESX.GetUsableItems() + local Usables = {} + for k in pairs(Core.UsableItemsCallbacks) do + Usables[k] = true + end + return Usables +end + +if not Config.CustomInventory then + ---@param itemType string + ---@param name string + ---@param count integer + ---@param label string + ---@param playerId number + ---@param components? string | table + ---@param tintIndex? integer + ---@param coords? table | vector3 + ---@return nil + function ESX.CreatePickup(itemType, name, count, label, playerId, components, tintIndex, coords) + local pickupId = (Core.PickupId == 65635 and 0 or Core.PickupId + 1) + local xPlayer = ESX.Players[playerId] + coords = ((type(coords) == "vector3" or type(coords) == "vector4") and coords.xyz or xPlayer.getCoords(true)) + + Core.Pickups[pickupId] = { type = itemType, name = name, count = count, label = label, coords = coords } + + if itemType == "item_weapon" then + Core.Pickups[pickupId].components = components + Core.Pickups[pickupId].tintIndex = tintIndex + end + + TriggerClientEvent("esx:createPickup", -1, pickupId, label, coords, itemType, name, components, tintIndex) + Core.PickupId = pickupId + end + + local function refreshPlayerInventories() + local xPlayers = ESX.GetExtendedPlayers() + for i = 1, #xPlayers do + local xPlayer = xPlayers[i] + local minimalInv = xPlayer.getInventory(true) + + for itemName, _ in pairs(minimalInv) do + if not ESX.Items[itemName] then + xPlayer.setInventoryItem(itemName, 0) + minimalInv[itemName] = nil + end + end + + xPlayer.inventory = {} + local playerInvIndex = 1 + for itemName, itemData in pairs(ESX.Items) do + xPlayer.inventory[playerInvIndex] = { + name = itemName, + count = minimalInv[itemName] or 0, + label = itemData.label, + weight = itemData.weight, + usable = Core.UsableItemsCallbacks[itemName] ~= nil, + rare = itemData.rare, + canRemove = itemData.canRemove, + } + playerInvIndex += 1 + end + + TriggerClientEvent("esx:setInventory", xPlayer.source, xPlayer.inventory) + end + end + + ---@return number newItemCount + function ESX.RefreshItems() + ESX.Items = {} + + local items = MySQL.query.await("SELECT * FROM items") + local itemCount = #items + for i = 1, itemCount do + local item = items[i] + ESX.Items[item.name] = { label = item.label, weight = item.weight, rare = item.rare, canRemove = item + .can_remove } + end + refreshPlayerInventories() + + return itemCount + end + + ---@param items { name: string, label: string, weight?: number, rare?: boolean, canRemove?: boolean }[] + function ESX.AddItems(items) + local toInsert = {} + local toInsertIndex = 1 + + for i = 1, #items do + local item = items[i] + local name = item.name + local label = item.label + local weight = item.weight or 1 + local rare = item.rare or false + local canRemove = item.canRemove ~= false + + if type(name) ~= "string" then + print(("^1[AddItems]^0 Invalid item name: %s"):format(name)) + goto continue + end + + if ESX.Items[name] then + goto continue + end + + if type(label) ~= "string" then + print(("^1[AddItems]^0 Invalid label for item '%s'"):format(name)) + goto continue + end + + if type(weight) ~= "number" then + print(("^1[AddItems]^0 Invalid weight for item '%s'"):format(name)) + goto continue + end + + if type(rare) ~= "boolean" then + print(("^1[AddItems]^0 Invalid rare flag for item '%s'"):format(name)) + goto continue + end + + if type(canRemove) ~= "boolean" then + print(("^1[AddItems]^0 Invalid canRemove flag for item '%s'"):format(name)) + goto continue + end + + toInsert[toInsertIndex] = { + name = name, + label = label, + weight = weight, + rare = rare, + canRemove = canRemove, + } + toInsertIndex += 1 + + ::continue:: + end + + if #toInsert > 0 then + MySQL.prepare.await( + "INSERT IGNORE INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES (?, ?, ?, ?, ?)", + toInsert) + + for i = 1, #toInsert do + local row = toInsert[i] + ESX.Items[row.name] = { + label = row.label, + weight = row.weight, + rare = row.rare, + canRemove = row.canRemove, + } + end + + refreshPlayerInventories() + end + end +end + +---@param job string +---@param grade string +---@return boolean +function ESX.DoesJobExist(job, grade) + while not Core.JobsLoaded do + Citizen.Wait(200) + end + + return (ESX.Jobs[job] and ESX.Jobs[job].grades[tostring(grade)] ~= nil) or false +end + +---@param playerSrc number +---@return boolean +function Core.IsPlayerAdmin(playerSrc) + if type(playerSrc) ~= "number" then + return false + end + + if IsPlayerAceAllowed(playerSrc --[[@as string]], "command") or GetConvar("sv_lan", "") == "true" then + return true + end + + local xPlayer = ESX.GetPlayerFromId(playerSrc) + return xPlayer and Config.AdminGroups[xPlayer.getGroup()] or false +end + +-- Generates a unique 9-digit SSN in dashed format (XXX-XX-XXXX). +---@param skipUniqueCheck boolean? +---@return string +function Core.generateSSN(skipUniqueCheck) + local reservedSSNs = { + ["078-05-1120"] = true, + ["219-09-9999"] = true, + ["123-45-6789"] = true + } + + while true do + -- Generate the first part (area number) + local area = math.random(1, 899) + + -- 666 is never assigned + if area == 666 then + goto continue + end + + -- Generate the second part (group number) + local group = math.random(1, 99) + + -- Generate the last part (serial number) + local serial = math.random(1, 9999) + + -- Skip reserved SSN range (987-65-4320..4329) + if area == 987 and group == 65 and serial >= 4320 and serial <= 4329 then + goto continue + end + + local candidate = string.format("%03d-%02d-%04d", area, group, serial) + + if reservedSSNs[candidate] then + goto continue + end + + if skipUniqueCheck then + return candidate + end + + local exists = MySQL.scalar.await("SELECT 1 FROM `users` WHERE `ssn` = ? LIMIT 1", { candidate }) + + if not exists then + return candidate + end + + ::continue:: + end +end + +---@param owner string +---@param plate string +---@param coords vector4 +---@return CExtendedVehicle? +function ESX.CreateExtendedVehicle(owner, plate, coords) + return Core.vehicleClass.new(owner, plate, coords) +end + +---@param plate string +---@return CExtendedVehicle? +function ESX.GetExtendedVehicleFromPlate(plate) + return Core.vehicleClass.getFromPlate(plate) +end diff --git a/resources/[core]/es_extended/server/main.lua b/resources/[core]/es_extended/server/main.lua new file mode 100644 index 0000000..96c5cc6 --- /dev/null +++ b/resources/[core]/es_extended/server/main.lua @@ -0,0 +1,792 @@ +SetMapName("San Andreas") +SetGameType("ESX Legacy") + +local oneSyncState = GetConvar("onesync", "off") +local newPlayer = "INSERT INTO `users` SET `accounts` = ?, `identifier` = ?, `ssn` = ?, `group` = ?" +local loadPlayer = "SELECT `accounts`, `ssn`, `job`, `job_grade`, `group`, `position`, `inventory`, `skin`, `loadout`, `metadata`" + +if Config.Multichar then + newPlayer = newPlayer .. ", `firstname` = ?, `lastname` = ?, `dateofbirth` = ?, `sex` = ?, `height` = ?" +end + +if Config.StartingInventoryItems then + newPlayer = newPlayer .. ", `inventory` = ?" +end + +if Config.Multichar or Config.Identity then + loadPlayer = loadPlayer .. ", `firstname`, `lastname`, `dateofbirth`, `sex`, `height`" +end + +loadPlayer = loadPlayer .. " FROM `users` WHERE identifier = ?" + +local function createESXPlayer(identifier, playerId, data) + local accounts = {} + + for account, money in pairs(Config.StartingAccountMoney) do + accounts[account] = money + end + + local defaultGroup = "user" + if Core.IsPlayerAdmin(playerId) then + print(("[^2INFO^0] Player ^5%s^0 Has been granted admin permissions via ^5Ace Perms^7."):format(playerId)) + defaultGroup = "admin" + end + local parameters = Config.Multichar and + { json.encode(accounts), identifier, Core.generateSSN(), defaultGroup, data.firstname, data.lastname, data.dateofbirth, data.sex, data.height } + or { json.encode(accounts), identifier, Core.generateSSN(), defaultGroup } + + if Config.StartingInventoryItems then + table.insert(parameters, json.encode(Config.StartingInventoryItems)) + end + + MySQL.prepare(newPlayer, parameters, function() + loadESXPlayer(identifier, playerId, true) + end) +end + + +local function onPlayerJoined(playerId) + local identifier = ESX.GetIdentifier(playerId) + if not identifier then + return DropPlayer(playerId, "there was an error loading your character!\nError code: identifier-missing-ingame\n\nThe cause of this error is not known, your identifier could not be found. Please come back later or report this problem to the server administration team.") + end + + if ESX.GetPlayerFromIdentifier(identifier) then + DropPlayer( + playerId, + ("there was an error loading your character!\nError code: identifier-active-ingame\n\nThis error is caused by a player on this server who has the same identifier as you have. Make sure you are not playing on the same Rockstar account.\n\nYour Rockstar identifier: %s"):format( + identifier + ) + ) + else + local result = MySQL.scalar.await("SELECT 1 FROM users WHERE identifier = ?", { identifier }) + if result then + loadESXPlayer(identifier, playerId, false) + else + createESXPlayer(identifier, playerId) + end + end +end + +---@param playerId number +---@param reason string +---@param cb function? +local function onPlayerDropped(playerId, reason, cb) + local p = not cb and promise:new() + local function resolve() + if cb then + return cb() + elseif(p) then + return p:resolve() + end + end + + local xPlayer = ESX.GetPlayerFromId(playerId) + if not xPlayer then + return resolve() + end + + TriggerEvent("esx:playerDropped", playerId, reason) + local job = xPlayer.getJob().name + local currentJob = Core.JobsPlayerCount[job] + Core.JobsPlayerCount[job] = ((currentJob and currentJob > 0) and currentJob or 1) - 1 + + GlobalState[("%s:count"):format(job)] = Core.JobsPlayerCount[job] + + Core.SavePlayer(xPlayer, function() + GlobalState["playerCount"] = GlobalState["playerCount"] - 1 + ESX.Players[playerId] = nil + Core.playersByIdentifier[xPlayer.identifier] = nil + + resolve() + end) + + if p then + return Citizen.Await(p) + end +end +AddEventHandler("esx:onPlayerDropped", onPlayerDropped) + + +if Config.Multichar then + AddEventHandler("esx:onPlayerJoined", function(src, char, data) + while not next(ESX.Jobs) do + Wait(50) + end + + if not ESX.Players[src] then + local identifier = char .. ":" .. ESX.GetIdentifier(src) + if data then + createESXPlayer(identifier, src, data) + else + loadESXPlayer(identifier, src, false) + end + end + end) +else + RegisterNetEvent("esx:onPlayerJoined", function() + local _source = source + while not next(ESX.Jobs) do + Wait(50) + end + + if not ESX.Players[_source] then + onPlayerJoined(_source) + end + end) +end + +if not Config.Multichar then + AddEventHandler("playerConnecting", function(_, _, deferrals) + local playerId = source + deferrals.defer() + Wait(0) -- Required + local identifier + local correctLicense, _ = pcall(function () + identifier = ESX.GetIdentifier(playerId) + end) + + -- luacheck: ignore + if not SetEntityOrphanMode then + return deferrals.done(("[ESX] ESX Requires a minimum Artifact version of 10188, Please update your server.")) + end + + if oneSyncState == "off" or oneSyncState == "legacy" then + return deferrals.done(("[ESX] ESX Requires Onesync Infinity to work. This server currently has Onesync set to: %s"):format(oneSyncState)) + end + + if not Core.DatabaseConnected then + return deferrals.done("[ESX] OxMySQL Was Unable To Connect to your database. Please make sure it is turned on and correctly configured in your server.cfg") + end + + if not identifier or not correctLicense then + if GetResourceState("esx_identity") ~= "started" then + return deferrals.done("[ESX] There was an error loading your character!\nError code: identifier-missing\n\nThe cause of this error is not known, your identifier could not be found. Please come back later or report this problem to the server administration team.") + end + end + + local xPlayer = ESX.GetPlayerFromIdentifier(identifier) + + if not xPlayer then + return deferrals.done() + end + + if GetPlayerPing(xPlayer.source --[[@as string]]) > 0 then + return deferrals.done( + ("[ESX] There was an error loading your character!\nError code: identifier-active\n\nThis error is caused by a player on this server who has the same identifier as you have. Make sure you are not playing on the same account.\n\nYour identifier: %s"):format(identifier) + ) + end + + deferrals.update(("[ESX] Cleaning stale player entry..."):format(identifier)) + onPlayerDropped(xPlayer.source, "esx_stale_player_obj") + deferrals.done() + end) +end + +function loadESXPlayer(identifier, playerId, isNew) + local userData = { + accounts = {}, + inventory = {}, + loadout = {}, + weight = 0, + name = GetPlayerName(playerId), + identifier = identifier, + firstName = "John", + lastName = "Doe", + dateofbirth = "01/01/2000", + height = 120, + dead = false, + } + + local result = MySQL.prepare.await(loadPlayer, { identifier }) + + -- Accounts + local accounts = result.accounts + accounts = (accounts and accounts ~= "") and json.decode(accounts) or {} + + for account, data in pairs(Config.Accounts) do + data.round = data.round or data.round == nil + + local index = #userData.accounts + 1 + userData.accounts[index] = { + name = account, + money = accounts[account] or Config.StartingAccountMoney[account] or 0, + label = data.label, + round = data.round, + index = index, + } + end + + -- SSN + userData.ssn = result.ssn + + -- Job + local job, grade = result.job, tostring(result.job_grade) + + if not ESX.DoesJobExist(job, grade) then + print(("[^3WARNING^7] Ignoring invalid job for ^5%s^7 [job: ^5%s^7, grade: ^5%s^7]"):format(identifier, job, grade)) + job, grade = "unemployed", "0" + end + + local jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] + + userData.job = { + id = jobObject.id, + name = jobObject.name, + label = jobObject.label, + type = jobObject.type, + + grade = tonumber(grade), + grade_name = gradeObject.name, + grade_label = gradeObject.label, + grade_salary = gradeObject.salary, + + skin_male = gradeObject.skin_male and json.decode(gradeObject.skin_male) or {}, + skin_female = gradeObject.skin_female and json.decode(gradeObject.skin_female) or {}, + } + + -- Inventory + if not Config.CustomInventory then + local inventory = (result.inventory and result.inventory ~= "") and json.decode(result.inventory) or {} + + for name, item in pairs(ESX.Items) do + local count = inventory[name] or 0 + userData.weight += (count * item.weight) + + userData.inventory[#userData.inventory + 1] = { + name = name, + count = count, + label = item.label, + weight = item.weight, + usable = Core.UsableItemsCallbacks[name] ~= nil, + rare = item.rare, + canRemove = item.canRemove, + } + end + table.sort(userData.inventory, function(a, b) + return a.label < b.label + end) + elseif result.inventory and result.inventory ~= "" then + userData.inventory = json.decode(result.inventory) + end + + -- Group + if result.group then + if result.group == "superadmin" then + userData.group = "admin" + print("[^3WARNING^7] ^5Superadmin^7 detected, setting group to ^5admin^7") + else + userData.group = result.group + end + else + userData.group = "user" + end + + -- Loadout + if not Config.CustomInventory then + if result.loadout and result.loadout ~= "" then + + local loadout = json.decode(result.loadout) + for name, weapon in pairs(loadout) do + local label = ESX.GetWeaponLabel(name) + + if label then + userData.loadout[#userData.loadout + 1] = { + name = name, + ammo = weapon.ammo, + label = label, + components = weapon.components or {}, + tintIndex = weapon.tintIndex or 0, + } + end + end + end + end + + -- Position + userData.coords = json.decode(result.position) or Config.DefaultSpawns[ESX.Math.Random(1,#Config.DefaultSpawns)] + + -- Skin + userData.skin = (result.skin and result.skin ~= "") and json.decode(result.skin) or { sex = userData.sex == "f" and 1 or 0 } + + -- Metadata + userData.metadata = (result.metadata and result.metadata ~= "") and json.decode(result.metadata) or {} + + -- xPlayer Creation + local xPlayer = CreateExtendedPlayer(playerId, identifier, userData.ssn, userData.group, userData.accounts, userData.inventory, userData.weight, userData.job, userData.loadout, GetPlayerName(playerId), userData.coords, userData.metadata) + + GlobalState["playerCount"] = GlobalState["playerCount"] + 1 + ESX.Players[playerId] = xPlayer + Core.playersByIdentifier[identifier] = xPlayer + + -- Identity + if result.firstname and result.firstname ~= "" then + userData.firstName = result.firstname + userData.lastName = result.lastname + + local name = ("%s %s"):format(result.firstname, result.lastname) + userData.name = name + + xPlayer.set("firstName", result.firstname) + xPlayer.set("lastName", result.lastname) + xPlayer.setName(name) + + if result.dateofbirth then + userData.dateofbirth = result.dateofbirth + xPlayer.set("dateofbirth", result.dateofbirth) + end + if result.sex then + userData.sex = result.sex + xPlayer.set("sex", result.sex) + end + if result.height then + userData.height = result.height + xPlayer.set("height", result.height) + end + end + + TriggerEvent("esx:playerLoaded", playerId, xPlayer, isNew) + userData.money = xPlayer.getMoney() + userData.maxWeight = xPlayer.getMaxWeight() + userData.variables = xPlayer.variables or {} + xPlayer.triggerEvent("esx:playerLoaded", userData, isNew, userData.skin) + + if not Config.CustomInventory then + xPlayer.triggerEvent("esx:createMissingPickups", Core.Pickups) + elseif setPlayerInventory then + setPlayerInventory(playerId, xPlayer, userData.inventory, isNew) + end + + xPlayer.triggerEvent("esx:registerSuggestions", Core.RegisteredCommands) + print(('[^2INFO^0] Player ^5"%s"^0 has connected to the server. ID: ^5%s^7'):format(xPlayer.getName(), playerId)) +end + +AddEventHandler("chatMessage", function(playerId, _, message) + local xPlayer = ESX.GetPlayerFromId(playerId) + if xPlayer and message:sub(1, 1) == "/" and playerId > 0 then + CancelEvent() + local commandName = message:sub(1):gmatch("%w+")() + xPlayer.showNotification(TranslateCap("commanderror_invalidcommand", commandName)) + end +end) + +---@param reason string +AddEventHandler("playerDropped", function(reason) + onPlayerDropped(source --[[@as number]], reason) +end) + +AddEventHandler("esx:playerLoaded", function(_, xPlayer, isNew) + local job = xPlayer.getJob().name + local jobKey = ("%s:count"):format(job) + + Core.JobsPlayerCount[job] = (Core.JobsPlayerCount[job] or 0) + 1 + GlobalState[jobKey] = Core.JobsPlayerCount[job] + if isNew then + Player(xPlayer.source).state:set('isNew', true, false) + end +end) + +AddEventHandler("esx:setJob", function(_, job, lastJob) + local lastJobKey = ("%s:count"):format(lastJob.name) + local jobKey = ("%s:count"):format(job.name) + local currentLastJob = Core.JobsPlayerCount[lastJob.name] + + Core.JobsPlayerCount[lastJob.name] = ((currentLastJob and currentLastJob > 0) and currentLastJob or 1) - 1 + Core.JobsPlayerCount[job.name] = (Core.JobsPlayerCount[job.name] or 0) + 1 + + GlobalState[lastJobKey] = Core.JobsPlayerCount[lastJob.name] + GlobalState[jobKey] = Core.JobsPlayerCount[job.name] +end) + +AddEventHandler("esx:playerLogout", function(playerId, cb) + onPlayerDropped(playerId, "esx_player_logout", cb) + TriggerClientEvent("esx:onPlayerLogout", playerId) +end) + +if not Config.CustomInventory then + RegisterNetEvent("esx:updateWeaponAmmo", function(weaponName, ammoCount) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer then + xPlayer.updateWeaponAmmo(weaponName, ammoCount) + end + end) + + RegisterNetEvent("esx:giveInventoryItem", function(target, itemType, itemName, itemCount) + local playerId = source + local sourceXPlayer = ESX.GetPlayerFromId(playerId) + local targetXPlayer = ESX.GetPlayerFromId(target) + local distance = #(GetEntityCoords(GetPlayerPed(playerId)) - GetEntityCoords(GetPlayerPed(target))) + if not sourceXPlayer or not targetXPlayer or distance > Config.DistanceGive then + print(("[^3WARNING^7] Player Detected Cheating: ^5%s^7"):format(GetPlayerName(playerId))) + return + end + + if itemType == "item_standard" then + local sourceItem = sourceXPlayer.getInventoryItem(itemName) + + if not sourceItem then + return + end + + if itemCount < 1 or sourceItem.count < itemCount then + return sourceXPlayer.showNotification(TranslateCap("imp_invalid_quantity")) + end + + if not targetXPlayer.canCarryItem(itemName, itemCount) then + return sourceXPlayer.showNotification(TranslateCap("ex_inv_lim", targetXPlayer.name)) + end + + sourceXPlayer.removeInventoryItem(itemName, itemCount) + targetXPlayer.addInventoryItem(itemName, itemCount) + + sourceXPlayer.showNotification(TranslateCap("gave_item", itemCount, sourceItem.label, targetXPlayer.name)) + targetXPlayer.showNotification(TranslateCap("received_item", itemCount, sourceItem.label, sourceXPlayer.name)) + elseif itemType == "item_account" then + if itemCount < 1 or sourceXPlayer.getAccount(itemName).money < itemCount then + return sourceXPlayer.showNotification(TranslateCap("imp_invalid_amount")) + end + + sourceXPlayer.removeAccountMoney(itemName, itemCount, "Gave to " .. targetXPlayer.name) + targetXPlayer.addAccountMoney(itemName, itemCount, "Received from " .. sourceXPlayer.name) + + sourceXPlayer.showNotification(TranslateCap("gave_account_money", ESX.Math.GroupDigits(itemCount), Config.Accounts[itemName].label, targetXPlayer.name)) + targetXPlayer.showNotification(TranslateCap("received_account_money", ESX.Math.GroupDigits(itemCount), Config.Accounts[itemName].label, sourceXPlayer.name)) + elseif itemType == "item_weapon" then + if not sourceXPlayer.hasWeapon(itemName) then + return + end + + local weaponLabel = ESX.GetWeaponLabel(itemName) + if targetXPlayer.hasWeapon(itemName) then + sourceXPlayer.showNotification(TranslateCap("gave_weapon_hasalready", targetXPlayer.name, weaponLabel)) + targetXPlayer.showNotification(TranslateCap("received_weapon_hasalready", sourceXPlayer.name, weaponLabel)) + return + end + + local _, weapon = sourceXPlayer.getWeapon(itemName) + if not weapon then + return + end + + local _, weaponObject = ESX.GetWeapon(itemName) + itemCount = weapon.ammo + local weaponComponents = ESX.Table.Clone(weapon.components) + local weaponTint = weapon.tintIndex + + if weaponTint then + targetXPlayer.setWeaponTint(itemName, weaponTint) + end + + if weaponComponents then + for _, v in pairs(weaponComponents) do + targetXPlayer.addWeaponComponent(itemName, v) + end + end + + sourceXPlayer.removeWeapon(itemName) + targetXPlayer.addWeapon(itemName, itemCount) + + if weaponObject.ammo and itemCount > 0 then + local ammoLabel = weaponObject.ammo.label + sourceXPlayer.showNotification(TranslateCap("gave_weapon_withammo", weaponLabel, itemCount, ammoLabel, targetXPlayer.name)) + targetXPlayer.showNotification(TranslateCap("received_weapon_withammo", weaponLabel, itemCount, ammoLabel, sourceXPlayer.name)) + else + sourceXPlayer.showNotification(TranslateCap("gave_weapon", weaponLabel, targetXPlayer.name)) + targetXPlayer.showNotification(TranslateCap("received_weapon", weaponLabel, sourceXPlayer.name)) + end + elseif itemType == "item_ammo" then + if not sourceXPlayer.hasWeapon(itemName) then + return + end + + local _, weapon = sourceXPlayer.getWeapon(itemName) + if not weapon then + return + end + + if not targetXPlayer.hasWeapon(itemName) then + sourceXPlayer.showNotification(TranslateCap("gave_weapon_noweapon", targetXPlayer.name)) + targetXPlayer.showNotification(TranslateCap("received_weapon_noweapon", sourceXPlayer.name, weapon.label)) + return + end + + local _, weaponObject = ESX.GetWeapon(itemName) + + if not weaponObject.ammo then return end + + local ammoLabel = weaponObject.ammo.label + if weapon.ammo >= itemCount then + sourceXPlayer.removeWeaponAmmo(itemName, itemCount) + targetXPlayer.addWeaponAmmo(itemName, itemCount) + + sourceXPlayer.showNotification(TranslateCap("gave_weapon_ammo", itemCount, ammoLabel, weapon.label, targetXPlayer.name)) + targetXPlayer.showNotification(TranslateCap("received_weapon_ammo", itemCount, ammoLabel, weapon.label, sourceXPlayer.name)) + end + end + end) + + RegisterNetEvent("esx:removeInventoryItem", function(itemType, itemName, itemCount) + local playerId = source + local xPlayer = ESX.GetPlayerFromId(playerId) + + if not xPlayer then + return + end + + if itemType == "item_standard" then + if not itemCount or itemCount < 1 then + return xPlayer.showNotification(TranslateCap("imp_invalid_quantity")) + end + + local xItem = xPlayer.getInventoryItem(itemName) + if not xItem then + return + end + + if itemCount > xItem.count or xItem.count < 1 then + return xPlayer.showNotification(TranslateCap("imp_invalid_quantity")) + end + + xPlayer.removeInventoryItem(itemName, itemCount) + local pickupLabel = ("%s [%s]"):format(xItem.label, itemCount) + ESX.CreatePickup("item_standard", itemName, itemCount, pickupLabel, playerId) + xPlayer.showNotification(TranslateCap("threw_standard", itemCount, xItem.label)) + elseif itemType == "item_account" then + if itemCount == nil or itemCount < 1 then + return xPlayer.showNotification(TranslateCap("imp_invalid_amount")) + end + + local account = xPlayer.getAccount(itemName) + if not account then + return + end + + if itemCount > account.money or account.money < 1 then + return xPlayer.showNotification(TranslateCap("imp_invalid_amount")) + end + + xPlayer.removeAccountMoney(itemName, itemCount, "Threw away") + local pickupLabel = ("%s [%s]"):format(account.label, TranslateCap("locale_currency", ESX.Math.GroupDigits(itemCount))) + ESX.CreatePickup("item_account", itemName, itemCount, pickupLabel, playerId) + xPlayer.showNotification(TranslateCap("threw_account", ESX.Math.GroupDigits(itemCount), string.lower(account.label))) + elseif itemType == "item_weapon" then + itemName = string.upper(itemName) + + if not xPlayer.hasWeapon(itemName) then return end + + local _, weapon = xPlayer.getWeapon(itemName) + if not weapon then + return + end + + local _, weaponObject = ESX.GetWeapon(itemName) + -- luacheck: ignore weaponPickupLabel + local weaponPickupLabel = "" + local components = ESX.Table.Clone(weapon.components) + xPlayer.removeWeapon(itemName) + + if weaponObject.ammo and weapon.ammo > 0 then + local ammoLabel = weaponObject.ammo.label + weaponPickupLabel = ("%s [%s %s]"):format(weapon.label, weapon.ammo, ammoLabel) + xPlayer.showNotification(TranslateCap("threw_weapon_ammo", weapon.label, weapon.ammo, ammoLabel)) + else + weaponPickupLabel = ("%s"):format(weapon.label) + xPlayer.showNotification(TranslateCap("threw_weapon", weapon.label)) + end + + ESX.CreatePickup("item_weapon", itemName, weapon.ammo, weaponPickupLabel, playerId, components, weapon.tintIndex) + end + end) + + RegisterNetEvent("esx:useItem", function(itemName) + local source = source + local xPlayer = ESX.GetPlayerFromId(source) + + if not xPlayer then + return + end + + local count = xPlayer.getInventoryItem(itemName).count + + if count < 1 then + return xPlayer.showNotification(TranslateCap("act_imp")) + end + + ESX.UseItem(source, itemName) + end) + + RegisterNetEvent("esx:onPickup", function(pickupId) + local pickup, xPlayer, success = Core.Pickups[pickupId], ESX.GetPlayerFromId(source) + + if not xPlayer then + return + end + + if not pickup then return end + + local playerPickupDistance = #(pickup.coords - xPlayer.getCoords(true)) + if playerPickupDistance > 5.0 then + print(("[^3WARNING^7] Player Detected Cheating (Out of range pickup): ^5%s^7"):format(xPlayer.getIdentifier())) + return + end + + if pickup.type == "item_standard" then + if not xPlayer.canCarryItem(pickup.name, pickup.count) then + return xPlayer.showNotification(TranslateCap("threw_cannot_pickup")) + end + + xPlayer.addInventoryItem(pickup.name, pickup.count) + success = true + elseif pickup.type == "item_account" then + success = true + xPlayer.addAccountMoney(pickup.name, pickup.count, "Picked up") + elseif pickup.type == "item_weapon" then + if xPlayer.hasWeapon(pickup.name) then + return xPlayer.showNotification(TranslateCap("threw_weapon_already")) + end + + success = true + xPlayer.addWeapon(pickup.name, pickup.count) + xPlayer.setWeaponTint(pickup.name, pickup.tintIndex) + + for _, v in ipairs(pickup.components) do + xPlayer.addWeaponComponent(pickup.name, v) + end + end + + if success then + Core.Pickups[pickupId] = nil + TriggerClientEvent("esx:removePickup", -1, pickupId) + end + end) +end + +ESX.RegisterServerCallback("esx:getPlayerData", function(source, cb) + local xPlayer = ESX.GetPlayerFromId(source) + + if not xPlayer then + return + end + + cb({ + identifier = xPlayer.identifier, + accounts = xPlayer.getAccounts(), + inventory = xPlayer.getInventory(), + job = xPlayer.getJob(), + loadout = xPlayer.getLoadout(), + money = xPlayer.getMoney(), + position = xPlayer.getCoords(true), + metadata = xPlayer.getMeta(), + }) +end) + +ESX.RegisterServerCallback("esx:isUserAdmin", function(source, cb) + cb(Core.IsPlayerAdmin(source)) +end) + +ESX.RegisterServerCallback("esx:getGameBuild", function(_, cb) + cb(tonumber(GetConvar("sv_enforceGameBuild", "1604"))) +end) + +ESX.RegisterServerCallback("esx:getOtherPlayerData", function(_, cb, target) + local xPlayer = ESX.GetPlayerFromId(target) + + if not xPlayer then + return + end + + cb({ + identifier = xPlayer.identifier, + accounts = xPlayer.getAccounts(), + inventory = xPlayer.getInventory(), + job = xPlayer.getJob(), + loadout = xPlayer.getLoadout(), + money = xPlayer.getMoney(), + position = xPlayer.getCoords(true), + metadata = xPlayer.getMeta(), + }) +end) + +ESX.RegisterServerCallback("esx:getPlayerNames", function(source, cb, players) + players[source] = nil + + for playerId, _ in pairs(players) do + local xPlayer = ESX.GetPlayerFromId(playerId) + + if xPlayer then + players[playerId] = xPlayer.getName() + else + players[playerId] = nil + end + end + + cb(players) +end) + +ESX.RegisterServerCallback("esx:spawnVehicle", function(source, cb, vehData) + local ped = GetPlayerPed(source) + ESX.OneSync.SpawnVehicle(vehData.model or `ADDER`, vehData.coords or GetEntityCoords(ped), vehData.coords.w or 0.0, vehData.props or {}, function(id) + if vehData.warp then + local vehicle = NetworkGetEntityFromNetworkId(id) + local timeout = 0 + while GetVehiclePedIsIn(ped, false) ~= vehicle and timeout <= 15 do + Wait(0) + TaskWarpPedIntoVehicle(ped, vehicle, -1) + timeout += 1 + end + end + cb(id) + end) +end) + +AddEventHandler("txAdmin:events:scheduledRestart", function(eventData) + if eventData.secondsRemaining == 60 then + CreateThread(function() + Wait(50000) + Core.SavePlayers() + end) + end +end) + +AddEventHandler("txAdmin:events:serverShuttingDown", function() + Core.SavePlayers() +end) + +local DoNotUse = { + ["essentialmode"] = true, + ["es_admin2"] = true, + ["basic-gamemode"] = true, + ["mapmanager"] = true, + ["fivem-map-skater"] = true, + ["fivem-map-hipster"] = true, + ["qb-core"] = true, + ["default_spawnpoint"] = true, +} + +AddEventHandler("onResourceStart", function(key) + if DoNotUse[string.lower(key)] then + while GetResourceState(key) ~= "started" do + Wait(0) + end + + StopResource(key) + error(("WE STOPPED A RESOURCE THAT WILL BREAK ^1ESX^1, PLEASE REMOVE ^5%s^1"):format(key)) + end + -- luacheck: ignore + if not SetEntityOrphanMode then + CreateThread(function() + while true do + error("ESX Requires a minimum Artifact version of 10188, Please update your server.") + Wait(60 * 1000) + end + end) + end +end) + +for key in pairs(DoNotUse) do + if GetResourceState(key) == "started" or GetResourceState(key) == "starting" then + StopResource(key) + error(("WE STOPPED A RESOURCE THAT WILL BREAK ^1ESX^1, PLEASE REMOVE ^5%s^1"):format(key)) + end +end diff --git a/resources/[core]/es_extended/server/migration/main.lua b/resources/[core]/es_extended/server/migration/main.lua new file mode 100644 index 0000000..378894f --- /dev/null +++ b/resources/[core]/es_extended/server/migration/main.lua @@ -0,0 +1,46 @@ +RegisterCommand("resetmigrations", function(src) + if src > 0 then + print("^1[ERROR]^7 This command can only be run from the server console.") + return + end + + for version, _ in pairs(Core.Migrations or {}) do + DeleteResourceKvp(("esx_migration:%s"):format(version)) + end + print("^2[SUCCESS]^7 Reset all migrations. This will re-run all migrations on the next server start.") +end) + +local migrationsRan = 0 +local restartRequired = false + +for esxVersion, migrations in pairs(Core.Migrations or {}) do + ---@cast esxVersion string + ---@cast migrations table + + if ESX.Table.SizeOf(migrations) > 0 then + print(("^4[INFO]^7 Running migrations for ESX version %s"):format(esxVersion)) + + for migrationName, migration in pairs(migrations) do + local success, result = pcall(migration) + if not success then + local err = result --[[@as string]] + error(("^1[ERROR]^7 Failed migration ^4['%s.%s']^7: %s"):format(esxVersion, migrationName, err)) + end + + local migrationRequiresRestart = result --[[@as boolean]] + + if not restartRequired and migrationRequiresRestart then + restartRequired = true + end + end + + SetResourceKvpInt(("esx_migration:%s"):format(esxVersion), 1) + print(("^2[SUCCESS]^7 Successfully completed migrations for ESX version %s"):format(esxVersion)) + migrationsRan += 1 + end +end + +while restartRequired do + print(("^4[INFO]^7 Ran migrations for %d ESX version(s). ^1Server restart required!^7"):format(migrationsRan)) + Wait(500) +end diff --git a/resources/[core]/es_extended/server/migration/v1.13.3/ssn/main.lua b/resources/[core]/es_extended/server/migration/v1.13.3/ssn/main.lua new file mode 100644 index 0000000..83b36e9 --- /dev/null +++ b/resources/[core]/es_extended/server/migration/v1.13.3/ssn/main.lua @@ -0,0 +1,70 @@ +local esxVersion = "v1.13.3" + +Core.Migrations = Core.Migrations or {} +Core.Migrations[esxVersion] = Core.Migrations[esxVersion] or {} + +if GetResourceKvpInt(("esx_migration:%s"):format(esxVersion)) == 1 then + return +end + +---@return boolean restartRequired +Core.Migrations[esxVersion].ssn = function() + print("^4[esx_migration:v.1.13.3:ssn]^7 Adding SSN column to users table.") + local col = MySQL.scalar.await([[ + SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'users' + AND COLUMN_NAME = 'ssn' +]]) + + local idx = MySQL.scalar.await([[ + SELECT COUNT(*) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'users' + AND INDEX_NAME = 'unique_ssn' +]]) + + if col == 0 and idx == 0 then + MySQL.update.await([[ + ALTER TABLE `users` + ADD COLUMN `ssn` VARCHAR(11) NULL DEFAULT NULL AFTER `identifier`, + ADD UNIQUE KEY `unique_ssn` (`ssn`) + ]]) + elseif col == 0 then + MySQL.update.await("ALTER TABLE `users` ADD COLUMN `ssn` VARCHAR(11) NULL DEFAULT NULL AFTER `identifier`") + elseif idx == 0 then + MySQL.update.await("ALTER TABLE `users` ADD UNIQUE KEY `unique_ssn` (`ssn`)") + end + + + local Result = MySQL.query.await("SELECT `identifier` FROM `users` WHERE `ssn` IS NULL") + if #Result == 0 then + print("^4[esx_migration:v.1.13.3:ssn]^7 No users found without SSN, migration not needed.") + return false + end + + print("^4[esx_migration:v.1.13.3:ssn]^7 Generating SSN for existing users.") + local GeneratedSSNs = {} + local Parameters = {} + for i = 1, #Result do + local ssn + repeat + ssn = Core.generateSSN(true) + until not GeneratedSSNs[ssn] + + GeneratedSSNs[ssn] = true + Parameters[i] = { ssn, Result[i].identifier } + end + + print("^4[esx_migration:v.1.13.3:ssn]^7 Updating users with generated SSN. This may take a minute...") + MySQL.prepare.await("UPDATE `users` SET `ssn` = ? WHERE `identifier` = ?", Parameters) + + print("^4[esx_migration:v.1.13.3:ssn]^7 Removing SSN default value.") + MySQL.update.await("ALTER TABLE `users` MODIFY `ssn` VARCHAR(11) NOT NULL") + + print(("^4[esx_migration:v.1.13.3:ssn]^7 Successfully migrated %d users."):format(#Parameters)) + + return true +end diff --git a/resources/[core]/es_extended/server/migration/v1.13.5/jobType/main.lua b/resources/[core]/es_extended/server/migration/v1.13.5/jobType/main.lua new file mode 100644 index 0000000..d06f525 --- /dev/null +++ b/resources/[core]/es_extended/server/migration/v1.13.5/jobType/main.lua @@ -0,0 +1,35 @@ +local esxVersion = "v1.13.5" + +Core.Migrations = Core.Migrations or {} +Core.Migrations[esxVersion] = Core.Migrations[esxVersion] or {} + +if GetResourceKvpInt(("esx_migration:%s"):format(esxVersion)) == 1 then + return +end + +---@return boolean restartRequired +Core.Migrations[esxVersion].jobTypes = function() + print("^4[esx_migration:v1.13.5:jobTypes]^7 Adding job type column to jobs table.") + + local col = MySQL.scalar.await([[ + SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'jobs' + AND COLUMN_NAME = 'type' + ]]) + + if col == 0 then + print("^4[esx_migration:v1.13.5:jobTypes]^7 Column not found, altering jobs table.") + MySQL.update.await([[ + ALTER TABLE `jobs` + ADD COLUMN `type` VARCHAR(50) NOT NULL DEFAULT 'civ' AFTER `label` + ]]) + else + print("^4[esx_migration:v1.13.5:jobTypes]^7 Column already exists, migration not needed.") + return false + end + + print("^4[esx_migration:v1.13.5:jobTypes]^7 Migration complete.") + return true +end diff --git a/resources/[core]/es_extended/server/modules/callback.lua b/resources/[core]/es_extended/server/modules/callback.lua new file mode 100644 index 0000000..c0fa8f7 --- /dev/null +++ b/resources/[core]/es_extended/server/modules/callback.lua @@ -0,0 +1,155 @@ +---@diagnostic disable: duplicate-set-field + +-- ============================================= +-- MARK: Variables +-- ============================================= + +Callbacks = {} + +Callbacks.requests = {} +Callbacks.storage = {} +Callbacks.id = 0 + +-- ============================================= +-- MARK: Internal Functions +-- ============================================= + +function Callbacks:Register(name, resource, cb) + self.storage[name] = { + resource = resource, + cb = cb + } +end + +function Callbacks:Execute(cb, ...) + local success, errorString = pcall(cb, ...) + + if not success then + print(("[^1ERROR^7] Failed to execute Callback with RequestId: ^5%s^7"):format(self.currentId)) + print("^3Callback Error:^7 " .. tostring(errorString)) -- just log, don't throw + self.currentId = nil + return + end + + self.currentId = nil +end + +function Callbacks:Trigger(player, event, cb, invoker, ...) + self.requests[self.id] = { + await = type(cb) == "boolean", + cb = cb or promise:new() + } + local table = self.requests[self.id] + + TriggerClientEvent("esx:triggerClientCallback", player, event, self.id, invoker, ...) + + self.id += 1 + + return table.cb +end + +function Callbacks:ServerRecieve(player, event, requestId, invoker, ...) + self.currentId = requestId + + if not self.storage[event] then + return error(("Server Callback with requestId ^5%s^1 Was Called by ^5%s^1 but does not exist."):format(event, invoker)) + end + + local returnCb = function(...) + TriggerClientEvent("esx:serverCallback", player, requestId, invoker, ...) + end + local callback = self.storage[event].cb + + self:Execute(callback, player, returnCb, ...) +end + +function Callbacks:RecieveClient(requestId, invoker, ...) + self.currentId = requestId + + if not self.requests[self.currentId] then + return error(("Client Callback with requestId ^5%s^1 Was Called by ^5%s^1 but does not exist."):format(self.currentId, invoker)) + end + + local callback = self.requests[self.currentId] + + self.requests[requestId] = nil + if callback.await then + callback.cb:resolve({ ... }) + else + self:Execute(callback.cb, ...) + end +end + +-- ============================================= +-- MARK: ESX Functions +-- ============================================= + +---@param player number playerId +---@param eventName string +---@param callback function +---@param ... any +function ESX.TriggerClientCallback(player, eventName, callback, ...) + local invokingResource = GetInvokingResource() + local invoker = (invokingResource and invokingResource ~= "Unknown") and invokingResource or "es_extended" + + Callbacks:Trigger(player, eventName, callback, invoker, ...) +end + +---@param player number playerId +---@param eventName string +---@param ... any +---@return ... +function ESX.AwaitClientCallback(player, eventName, ...) + local invokingResource = GetInvokingResource() + local invoker = (invokingResource and invokingResource ~= "Unknown") and invokingResource or "es_extended" + + local p = Callbacks:Trigger(player, eventName, false, invoker, ...) + if not p then return end + + SetTimeout(15000, function() + if p.state == "pending" then + p:reject("Server Callback Timed Out") + end + end) + + Citizen.Await(p) + + return table.unpack(p.value) +end + +---@param eventName string +---@param callback function +---@return nil +function ESX.RegisterServerCallback(eventName, callback) + local invokingResource = GetInvokingResource() + local invoker = (invokingResource and invokingResource ~= "Unknown") and invokingResource or "es_extended" + + Callbacks:Register(eventName, invoker, callback) +end + +---@param eventName string +---@return boolean +function ESX.DoesServerCallbackExist(eventName) + return Callbacks.storage[eventName] ~= nil +end + +-- ============================================= +-- MARK: Events +-- ============================================= + +RegisterNetEvent("esx:clientCallback", function(requestId, invoker, ...) + Callbacks:RecieveClient(requestId, invoker, ...) +end) + +RegisterNetEvent("esx:triggerServerCallback", function(eventName, requestId, invoker, ...) + local source = source + Callbacks:ServerRecieve(source, eventName, requestId, invoker, ...) +end) + +AddEventHandler("onResourceStop", function(resource) + for k, v in pairs(Callbacks.storage) do + if v.resource == resource then + Callbacks.storage[k] = nil + end + end +end) diff --git a/resources/[core]/es_extended/server/modules/commands.lua b/resources/[core]/es_extended/server/modules/commands.lua new file mode 100644 index 0000000..2320e82 --- /dev/null +++ b/resources/[core]/es_extended/server/modules/commands.lua @@ -0,0 +1,774 @@ +ESX.RegisterCommand( + { "setcoords", "tp" }, + "admin", + function(xPlayer, args) + xPlayer.setCoords({ x = args.x, y = args.y, z = args.z }) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Set Coordinates /setcoords Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "X Coord", value = args.x, inline = true }, + { name = "Y Coord", value = args.y, inline = true }, + { name = "Z Coord", value = args.z, inline = true }, + }) + end + end, + false, + { + help = TranslateCap("command_setcoords"), + validate = true, + arguments = { + { name = "x", help = TranslateCap("command_setcoords_x"), type = "coordinate" }, + { name = "y", help = TranslateCap("command_setcoords_y"), type = "coordinate" }, + { name = "z", help = TranslateCap("command_setcoords_z"), type = "coordinate" }, + }, + } +) + +ESX.RegisterCommand( + "setjob", + "admin", + function(xPlayer, args, showError) + if not ESX.DoesJobExist(args.job, args.grade) then + return showError(TranslateCap("command_setjob_invalid")) + end + + args.playerId.setJob(args.job, args.grade) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Set Job /setjob Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Job", value = args.job, inline = true }, + { name = "Grade", value = args.grade, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_setjob"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "job", help = TranslateCap("command_setjob_job"), type = "string" }, + { name = "grade", help = TranslateCap("command_setjob_grade"), type = "number" }, + }, + } +) + +local upgrades = Config.SpawnVehMaxUpgrades and { + plate = "ADMINCAR", + modEngine = 3, + modBrakes = 2, + modTransmission = 2, + modSuspension = 3, + modArmor = true, + windowTint = 1, +} or {} + +ESX.RegisterCommand( + "car", + "admin", + function(xPlayer, args, showError) + if not xPlayer then + return showError("[^1ERROR^7] The xPlayer value is nil") + end + + local playerPed = GetPlayerPed(xPlayer.source) + local playerCoords = GetEntityCoords(playerPed) + local playerHeading = GetEntityHeading(playerPed) + local playerVehicle = GetVehiclePedIsIn(playerPed, false) + + if not args.car or type(args.car) ~= "string" then + args.car = "adder" + end + + if playerVehicle then + DeleteEntity(playerVehicle) + end + + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Spawn Car /car Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Vehicle", value = args.car, inline = true }, + }) + end + + local xRoutingBucket = GetPlayerRoutingBucket(xPlayer.source) + + ESX.OneSync.SpawnVehicle(args.car, playerCoords, playerHeading, upgrades, function(networkId) + if networkId then + local vehicle = NetworkGetEntityFromNetworkId(networkId) + + if xRoutingBucket ~= 0 then + SetEntityRoutingBucket(vehicle, xRoutingBucket) + end + + for _ = 1, 100 do + Wait(0) + SetPedIntoVehicle(playerPed, vehicle, -1) + + if GetVehiclePedIsIn(playerPed, false) == vehicle then + break + end + end + + if GetVehiclePedIsIn(playerPed, false) ~= vehicle then + showError("[^1ERROR^7] The player could not be seated in the vehicle") + end + end + end) + end, + false, + { + help = TranslateCap("command_car"), + validate = false, + arguments = { + { name = "car", validate = false, help = TranslateCap("command_car_car"), type = "string" }, + }, + } +) + +ESX.RegisterCommand( + { "cardel", "dv" }, + "admin", + function(xPlayer, args) + local ped = GetPlayerPed(xPlayer.source) + local pedVehicle = GetVehiclePedIsIn(ped, false) + + if DoesEntityExist(pedVehicle) then + DeleteEntity(pedVehicle) + end + + local coords = GetEntityCoords(ped) + local Vehicles = ESX.OneSync.GetVehiclesInArea(coords, tonumber(args.radius) or 5.0) + for i = 1, #Vehicles do + local Vehicle = NetworkGetEntityFromNetworkId(Vehicles[i]) + if DoesEntityExist(Vehicle) then + DeleteEntity(Vehicle) + end + end + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Delete Vehicle /dv Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + }) + end + end, + false, + { + help = TranslateCap("command_cardel"), + validate = false, + arguments = { + { name = "radius", validate = false, help = TranslateCap("command_cardel_radius"), type = "number" }, + }, + } +) + +ESX.RegisterCommand( + { "fix", "repair" }, + "admin", + function(xPlayer, args, showError) + local xTarget = args.playerId + local ped = GetPlayerPed(xTarget.source) + local pedVehicle = GetVehiclePedIsIn(ped, false) + if not pedVehicle or GetPedInVehicleSeat(pedVehicle, -1) ~= ped then + showError(TranslateCap("not_in_vehicle")) + return + end + xTarget.triggerEvent("esx:repairPedVehicle") + xPlayer.showNotification(TranslateCap("command_repair_success"), true, false, 140) + if xPlayer.source ~= xTarget.source then + xTarget.showNotification(TranslateCap("command_repair_success_target"), true, false, 140) + end + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Fix Vehicle /fix Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = xTarget.name, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_repair"), + validate = false, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + }, + } +) + +ESX.RegisterCommand( + "setaccountmoney", + "admin", + function(xPlayer, args, showError) + if not args.playerId.getAccount(args.account) then + return showError(TranslateCap("command_giveaccountmoney_invalid")) + end + args.playerId.setAccountMoney(args.account, args.amount, "Government Grant") + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Set Account Money /setaccountmoney Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Account", value = args.account, inline = true }, + { name = "Amount", value = args.amount, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_setaccountmoney"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "account", help = TranslateCap("command_giveaccountmoney_account"), type = "string" }, + { name = "amount", help = TranslateCap("command_setaccountmoney_amount"), type = "number" }, + }, + } +) + +ESX.RegisterCommand( + "giveaccountmoney", + "admin", + function(xPlayer, args, showError) + if not args.playerId.getAccount(args.account) then + return showError(TranslateCap("command_giveaccountmoney_invalid")) + end + args.playerId.addAccountMoney(args.account, args.amount, "Government Grant") + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Give Account Money /giveaccountmoney Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Account", value = args.account, inline = true }, + { name = "Amount", value = args.amount, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_giveaccountmoney"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "account", help = TranslateCap("command_giveaccountmoney_account"), type = "string" }, + { name = "amount", help = TranslateCap("command_giveaccountmoney_amount"), type = "number" }, + }, + } +) + +ESX.RegisterCommand( + "removeaccountmoney", + "admin", + function(xPlayer, args, showError) + if not args.playerId.getAccount(args.account) then + return showError(TranslateCap("command_removeaccountmoney_invalid")) + end + args.playerId.removeAccountMoney(args.account, args.amount, "Government Tax") + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Remove Account Money /removeaccountmoney Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Account", value = args.account, inline = true }, + { name = "Amount", value = args.amount, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_removeaccountmoney"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "account", help = TranslateCap("command_removeaccountmoney_account"), type = "string" }, + { name = "amount", help = TranslateCap("command_removeaccountmoney_amount"), type = "number" }, + }, + } +) + +if not Config.CustomInventory then + ESX.RegisterCommand( + "giveitem", + "admin", + function(xPlayer, args) + args.playerId.addInventoryItem(args.item, args.count) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Give Item /giveitem Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Item", value = args.item, inline = true }, + { name = "Quantity", value = args.count, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_giveitem"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "item", help = TranslateCap("command_giveitem_item"), type = "item" }, + { name = "count", help = TranslateCap("command_giveitem_count"), type = "number", Validator = { + validate = function(x) return x > 0 end, + err = TranslateCap("commanderror_argumentmismatch_positive_number", "count") + }}, + }, + } + ) + + ESX.RegisterCommand( + "giveweapon", + "admin", + function(xPlayer, args, showError) + if args.playerId.hasWeapon(args.weapon) then + return showError(TranslateCap("command_giveweapon_hasalready")) + end + args.playerId.addWeapon(args.weapon, args.ammo) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Give Weapon /giveweapon Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Weapon", value = args.weapon, inline = true }, + { name = "Ammo", value = args.ammo, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_giveweapon"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "weapon", help = TranslateCap("command_giveweapon_weapon"), type = "weapon" }, + { name = "ammo", help = TranslateCap("command_giveweapon_ammo"), type = "number" }, + }, + } + ) + + ESX.RegisterCommand( + "giveammo", + "admin", + function(xPlayer, args, showError) + if not args.playerId.hasWeapon(args.weapon) then + return showError(TranslateCap("command_giveammo_noweapon_found")) + end + args.playerId.addWeaponAmmo(args.weapon, args.ammo) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Give Ammunition /giveammo Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Weapon", value = args.weapon, inline = true }, + { name = "Ammo", value = args.ammo, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_giveweapon"), + validate = false, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "weapon", help = TranslateCap("command_giveammo_weapon"), type = "weapon" }, + { name = "ammo", help = TranslateCap("command_giveammo_ammo"), type = "number" }, + }, + } + ) + + ESX.RegisterCommand( + "giveweaponcomponent", + "admin", + function(xPlayer, args, showError) + if args.playerId.hasWeapon(args.weaponName) then + local component = ESX.GetWeaponComponent(args.weaponName, args.componentName) + + if component then + if args.playerId.hasWeaponComponent(args.weaponName, args.componentName) then + showError(TranslateCap("command_giveweaponcomponent_hasalready")) + else + args.playerId.addWeaponComponent(args.weaponName, args.componentName) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Give Weapon Component /giveweaponcomponent Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Weapon", value = args.weaponName, inline = true }, + { name = "Component", value = args.componentName, inline = true }, + }) + end + end + else + showError(TranslateCap("command_giveweaponcomponent_invalid")) + end + else + showError(TranslateCap("command_giveweaponcomponent_missingweapon")) + end + end, + true, + { + help = TranslateCap("command_giveweaponcomponent"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "weaponName", help = TranslateCap("command_giveweapon_weapon"), type = "weapon" }, + { name = "componentName", help = TranslateCap("command_giveweaponcomponent_component"), type = "string" }, + }, + } + ) +end + +ESX.RegisterCommand({ "clear", "cls" }, "user", function(xPlayer) + xPlayer.triggerEvent("chat:clear") +end, false, { help = TranslateCap("command_clear") }) + +ESX.RegisterCommand({ "clearall", "clsall" }, "admin", function(xPlayer) + TriggerClientEvent("chat:clear", -1) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Clear Chat /clearall Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + }) + end +end, true, { help = TranslateCap("command_clearall") }) + +ESX.RegisterCommand("refreshjobs", "admin", function() + ESX.RefreshJobs() +end, true, { help = TranslateCap("command_clearall") }) + +if not Config.CustomInventory then + ESX.RegisterCommand("refreshitems", "admin", function(xPlayer) + local itemCount = ESX.RefreshItems() + + xPlayer.showNotification(Translate("command_refreshitems_success", itemCount), true, false, 140) + end, true, { help = TranslateCap("command_refreshitems") }) + + ESX.RegisterCommand( + "clearinventory", + "admin", + function(xPlayer, args) + for _, v in ipairs(args.playerId.inventory) do + if v.count > 0 then + args.playerId.setInventoryItem(v.name, 0) + end + end + TriggerEvent("esx:playerInventoryCleared", args.playerId) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Clear Inventory /clearinventory Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_clearinventory"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + }, + } + ) + + ESX.RegisterCommand( + "clearloadout", + "admin", + function(xPlayer, args) + for i = #args.playerId.loadout, 1, -1 do + args.playerId.removeWeapon(args.playerId.loadout[i].name) + end + TriggerEvent("esx:playerLoadoutCleared", args.playerId) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "/clearloadout Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_clearloadout"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + }, + } + ) +end + +ESX.RegisterCommand( + "setgroup", + "admin", + function(xPlayer, args) + if not args.playerId then + args.playerId = xPlayer.source + end + if args.group == "superadmin" then + args.group = "admin" + print("[^3WARNING^7] ^5Superadmin^7 detected, setting group to ^5admin^7") + end + args.playerId.setGroup(args.group) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "/setgroup Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Group", value = args.group, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_setgroup"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "group", help = TranslateCap("command_setgroup_group"), type = "string" }, + }, + } +) + +ESX.RegisterCommand( + "save", + "admin", + function(_, args) + Core.SavePlayer(args.playerId) + print(("[^2Info^0] Saved Player - ^5%s^0"):format(args.playerId.source)) + end, + true, + { + help = TranslateCap("command_save"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + }, + } +) + +ESX.RegisterCommand("saveall", "admin", function() + Core.SavePlayers() +end, true, { help = TranslateCap("command_saveall") }) + +ESX.RegisterCommand("group", { "user", "admin" }, function(xPlayer, _, _) + print(("%s, you are currently: ^5%s^0"):format(xPlayer.getName(), xPlayer.getGroup())) +end, true) + +ESX.RegisterCommand("job", { "user", "admin" }, function(xPlayer, _, _) + local job = xPlayer.getJob() + + print(("%s, your job is: ^5%s^0 - ^5%s^0 - ^5%s^0"):format(xPlayer.getName(), job.name, job.grade_label, job.onDuty and "On Duty" or "Off Duty")) +end, false) + +ESX.RegisterCommand("info", { "user", "admin" }, function(xPlayer) + local job = xPlayer.getJob().name + print(("^2ID: ^5%s^0 | ^2Name: ^5%s^0 | ^2Group: ^5%s^0 | ^2Job: ^5%s^0"):format(xPlayer.source, xPlayer.getName(), xPlayer.getGroup(), job)) +end, false) + +ESX.RegisterCommand("playtime", { "user", "admin" }, function(xPlayer) + local playtime = xPlayer.getPlayTime() + local days = math.floor(playtime / 86400) + local hours = math.floor((playtime % 86400) / 3600) + local minutes = math.floor((playtime % 3600) / 60) + print(("Playtime: ^5%s^0 Days | ^5%s^0 Hours | ^5%s^0 Minutes"):format(days, hours, minutes)) +end, false) + +ESX.RegisterCommand("coords", "admin", function(xPlayer) + local ped = GetPlayerPed(xPlayer.source) + local coords = GetEntityCoords(ped, false) + local heading = GetEntityHeading(ped) + print(("Coords - Vector3: ^5%s^0"):format(vector3(coords.x, coords.y, coords.z))) + print(("Coords - Vector4: ^5%s^0"):format(vector4(coords.x, coords.y, coords.z, heading))) +end, false) + +ESX.RegisterCommand("tpm", "admin", function(xPlayer) + xPlayer.triggerEvent("esx:tpm") + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Admin Teleport /tpm Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + }) + end +end, false) + +ESX.RegisterCommand( + "goto", + "admin", + function(xPlayer, args) + local targetCoords = args.playerId.getCoords() + local srcDim = GetPlayerRoutingBucket(xPlayer.source) + local targetDim = GetPlayerRoutingBucket(args.playerId.source) + + if srcDim ~= targetDim then + SetPlayerRoutingBucket(xPlayer.source, targetDim) + end + xPlayer.setCoords(targetCoords) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Admin Teleport /goto Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Target Coords", value = targetCoords, inline = true }, + }) + end + end, + false, + { + help = TranslateCap("command_goto"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + }, + } +) + +ESX.RegisterCommand( + "bring", + "admin", + function(xPlayer, args) + local targetCoords = args.playerId.getCoords() + local playerCoords = xPlayer.getCoords() + local targetDim = GetPlayerRoutingBucket(args.playerId.source) + local srcDim = GetPlayerRoutingBucket(xPlayer.source) + + if targetDim ~= srcDim then + SetPlayerRoutingBucket(args.playerId.source, srcDim) + end + args.playerId.setCoords(playerCoords) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Admin Teleport /bring Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Target Coords", value = targetCoords, inline = true }, + }) + end + end, + false, + { + help = TranslateCap("command_bring"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + }, + } +) + +ESX.RegisterCommand( + "kill", + "admin", + function(xPlayer, args) + args.playerId.triggerEvent("esx:killPlayer") + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Kill Command /kill Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_kill"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + }, + } +) + +ESX.RegisterCommand( + "freeze", + "admin", + function(xPlayer, args) + args.playerId.triggerEvent("esx:freezePlayer", "freeze") + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Admin Freeze /freeze Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_freeze"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + }, + } +) + +ESX.RegisterCommand( + "unfreeze", + "admin", + function(xPlayer, args) + args.playerId.triggerEvent("esx:freezePlayer", "unfreeze") + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Admin UnFreeze /unfreeze Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_unfreeze"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + }, + } +) + +ESX.RegisterCommand("noclip", "admin", function(xPlayer) + xPlayer.triggerEvent("esx:noclip") + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Admin NoClip /noclip Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + }) + end +end, false) + +ESX.RegisterCommand("players", "admin", function() + local xPlayers = ESX.GetExtendedPlayers() -- Returns all xPlayers + print(("^5%s^2 online player(s)^0"):format(#xPlayers)) + for i = 1, #xPlayers do + local xPlayer = xPlayers[i] + print(("^1[^2ID: ^5%s^0 | ^2Name : ^5%s^0 | ^2Group : ^5%s^0 | ^2Identifier : ^5%s^1]^0\n"):format(xPlayer.source, xPlayer.getName(), xPlayer.getGroup(), xPlayer.identifier)) + end +end, true) + +ESX.RegisterCommand( + {"setdim", "setbucket"}, + "admin", + function(xPlayer, args) + SetPlayerRoutingBucket(args.playerId.source, args.dimension) + if Config.AdminLogging then + ESX.DiscordLogFields("UserActions", "Admin Set Dim /setdim Triggered!", "pink", { + { name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true }, + { name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true }, + { name = "Target", value = args.playerId.name, inline = true }, + { name = "Dimension", value = args.dimension, inline = true }, + }) + end + end, + true, + { + help = TranslateCap("command_setdim"), + validate = true, + arguments = { + { name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" }, + { name = "dimension", help = TranslateCap("commandgeneric_dimension"), type = "number" }, + }, + } +) diff --git a/resources/[core]/es_extended/server/modules/createJob.lua b/resources/[core]/es_extended/server/modules/createJob.lua new file mode 100644 index 0000000..a5712cf --- /dev/null +++ b/resources/[core]/es_extended/server/modules/createJob.lua @@ -0,0 +1,101 @@ + +local NOTIFY_TYPES = { + INFO = "^5[%s]^7-^6[INFO]^7 %s", + SUCCESS = "^5[%s]^7-^2[SUCCESS]^7 %s", + ERROR = "^5[%s]^7-^1[ERROR]^7 %s" +} + +local function doesJobAndGradesExist(name, grades) + if not ESX.Jobs[name] then + return false + end + + for _, grade in ipairs(grades) do + if not ESX.DoesJobExist(name, grade.grade) then + return false + end + end + + return true +end + +local function generateNewJobTable(name, label, grades, jobType) + local job = { name = name, label = label, type = jobType, grades = {} } + for _, v in pairs(grades) do + job.grades[tostring(v.grade)] = { job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = v.skin_male or '{}', skin_female = v.skin_female or '{}' } + end + + return job +end + +local function notify(notifyType,resourceName,message,...) + local formattedMessage = string.format(message, ...) + + if not NOTIFY_TYPES[notifyType] then + return print(NOTIFY_TYPES.INFO:format(resourceName,formattedMessage)) + end + + return print(NOTIFY_TYPES[notifyType]:format(resourceName,formattedMessage)) +end + +--- Create Job at Runtime +--- @param name string +--- @param label string +--- @param grades table +--- @param jobType string +function ESX.CreateJob(name, label, grades, jobType) + local currentResourceName = GetInvokingResource() + local success = false + + if not name or name == '' then + notify("ERROR",currentResourceName, 'Missing argument `name`') + return success + end + + if not label or label == '' then + notify("ERROR",currentResourceName, 'Missing argument `label`') + return success + end + + if not grades or not next(grades) then + notify("ERROR",currentResourceName, 'Missing argument `grades`') + return success + end + + if type(jobType) ~= "string" then + jobType = "civ" + end + + local currentJobExist = doesJobAndGradesExist(name, grades) + + if currentJobExist then + notify("ERROR",currentResourceName, 'Job or grades already exists: `%s`', name) + return success + end + + local queries = { + { query = 'INSERT INTO `jobs` (`name`, `label`, `type`) VALUES (?, ?, ?)', values = { name, label, jobType } } + } + + for _, grade in pairs(grades) do + queries[#queries + 1] = { + query = 'INSERT INTO job_grades (job_name, grade, name, label, salary, skin_male, skin_female) VALUES (?, ?, ?, ?, ?, ?, ?)', + values = { name, grade.grade, grade.name, grade.label, grade.salary, grade.skin_male and json.encode(grade.skin_male) or '{}', grade.skin_female and json.encode(grade.skin_female) or '{}' } + } + end + + success = exports.oxmysql:transaction_async(queries) + + if not success then + notify("ERROR", currentResourceName, 'Failed to insert one or more grades for job: `%s`', name) + return success + end + + ESX.Jobs[name] = generateNewJobTable(name, label, grades, jobType) + + notify("SUCCESS", currentResourceName, 'Job created successfully: `%s`', name) + + TriggerEvent('esx:jobCreated', name, ESX.Jobs[name]) + + return success +end diff --git a/resources/[core]/es_extended/server/modules/npwd.lua b/resources/[core]/es_extended/server/modules/npwd.lua new file mode 100644 index 0000000..78aa863 --- /dev/null +++ b/resources/[core]/es_extended/server/modules/npwd.lua @@ -0,0 +1,52 @@ +local npwd = GetResourceState("npwd"):find("start") and exports.npwd or nil + +AddEventHandler("onServerResourceStart", function(resource) + if resource ~= "npwd" then + return + end + + npwd = GetResourceState("npwd"):find("start") and exports.npwd or nil + + if not npwd then + return + end + for _, xPlayer in pairs(ESX.Players) do + npwd:newPlayer({ + source = xPlayer.source, + identifier = xPlayer.identifier, + firstname = xPlayer.get("firstName"), + lastname = xPlayer.get("lastName"), + }) + end +end) + +AddEventHandler("onServerResourceStop", function(resource) + if resource == "npwd" then + npwd = nil + end +end) + +AddEventHandler("esx:playerLoaded", function(playerId, xPlayer) + if not npwd then + return + end + + if not xPlayer then + xPlayer = ESX.GetPlayerFromId(playerId) + end + + npwd:newPlayer({ + source = playerId, + identifier = xPlayer.identifier, + firstname = xPlayer.get("firstName"), + lastname = xPlayer.get("lastName"), + }) +end) + +AddEventHandler("esx:playerLogout", function(playerId) + if not npwd then + return + end + + npwd:unloadPlayer(playerId) +end) diff --git a/resources/[core]/es_extended/server/modules/onesync.lua b/resources/[core]/es_extended/server/modules/onesync.lua new file mode 100644 index 0000000..573dc88 --- /dev/null +++ b/resources/[core]/es_extended/server/modules/onesync.lua @@ -0,0 +1,387 @@ +ESX.OneSync = {} + +---@param source number|vector3 +---@param closest boolean +---@param distance? number +---@param ignore? table +---@param routingBucket? number +local function getNearbyPlayers(source, closest, distance, ignore, routingBucket) + local result = {} + local count = 0 + local playerPed + local playerCoords + ignore = ignore or {} + + if not distance then + distance = 100 + end + + if type(source) == "number" then + playerPed = GetPlayerPed(source) + + if not source then + error("Received invalid first argument (source); should be playerId") + end + + playerCoords = GetEntityCoords(playerPed) + + if not playerCoords then + error("Received nil value (playerCoords); perhaps source is nil at first place?") + end + end + + if type(source) == "vector3" then + playerCoords = source + + if not playerCoords then + error("Received nil value (playerCoords); perhaps source is nil at first place?") + end + end + + for _, xPlayer in pairs(ESX.Players) do + if not ignore[xPlayer.source] and (not routingBucket or GetPlayerRoutingBucket(xPlayer.source) == routingBucket) then + local entity = GetPlayerPed(xPlayer.source) + local coords = GetEntityCoords(entity) + + if not closest then + local dist = #(playerCoords - coords) + if dist <= distance then + count = count + 1 + result[count] = { id = xPlayer.source, ped = NetworkGetNetworkIdFromEntity(entity), coords = coords, dist = dist } + end + else + if xPlayer.source ~= source then + local dist = #(playerCoords - coords) + if dist <= (result.dist or distance) then + result = { id = xPlayer.source, ped = NetworkGetNetworkIdFromEntity(entity), coords = coords, dist = dist } + end + end + end + end + end + + return result +end + +---@param source vector3|number playerId or vector3 coordinates +---@param maxDistance number +---@param ignore? table playerIds to ignore, where the key is playerId and value is true +---@param routingBucket? number +function ESX.OneSync.GetPlayersInArea(source, maxDistance, ignore, routingBucket) + return getNearbyPlayers(source, false, maxDistance, ignore, routingBucket) +end + +---@param source vector3|number playerId or vector3 coordinates +---@param maxDistance number +---@param ignore? table playerIds to ignore, where the key is playerId and value is true +---@param routingBucket? number +function ESX.OneSync.GetClosestPlayer(source, maxDistance, ignore, routingBucket) + return getNearbyPlayers(source, true, maxDistance, ignore, routingBucket) +end + +---@param vehicleModel number|string +---@param coords vector3|table +---@param heading number +---@param vehicleProperties table +---@param cb? fun(netId: number) +---@param vehicleType string? +---@return number? netId +function ESX.OneSync.SpawnVehicle(vehicleModel, coords, heading, vehicleProperties, cb, vehicleType) + if cb and not ESX.IsFunctionReference(cb) then + error("Invalid callback function") + end + + vehicleModel = joaat(vehicleModel) + + local promise = not cb and promise.new() + + local function resolve(result) + if promise then + promise:resolve(result) + elseif cb then + cb(result) + end + + return result + end + + local function reject(err) + if promise then + promise:reject(err) + end + error(err) + end + + CreateThread(function() + if not vehicleType then + local xPlayer = ESX.GetExtendedPlayers()[1] + if xPlayer then + vehicleType = ESX.GetVehicleType(vehicleModel, xPlayer.source) + end + end + + if not vehicleType then + return reject("No players found nearby to check vehicle type! Alternatively, you can specify the vehicle type manually.") + end + + local createdVehicle = CreateVehicleServerSetter(vehicleModel, vehicleType, coords.x, coords.y, coords.z, heading) + local tries = 0 + + local hasNetOwner = next(ESX.OneSync.GetClosestPlayer(coords, 300, nil, 0) or {}) ~= nil + + while not createdVehicle or createdVehicle == 0 + or (hasNetOwner and NetworkGetEntityOwner(createdVehicle) == -1) + or (not hasNetOwner and not DoesEntityExist(createdVehicle)) do + Wait(200) + tries = tries + 1 + if tries > 40 then + return reject(("Could not spawn vehicle - ^5%s^7!"):format(vehicleModel)) + end + end + + -- luacheck: ignore + SetEntityOrphanMode(createdVehicle, 2) + local networkId = NetworkGetNetworkIdFromEntity(createdVehicle) + Entity(createdVehicle).state:set("VehicleProperties", vehicleProperties, true) + + resolve(networkId) + end) + + if promise then + return Citizen.Await(promise) + end +end + +---@param model number|string +---@param coords vector3|table +---@param heading number +---@param cb? fun(netId: number) +---@return number? netId +function ESX.OneSync.SpawnObject(model, coords, heading, cb) + if type(model) == "string" then + model = joaat(model) + end + + local promise = not cb and promise.new() + local objectCoords = type(coords) == "vector3" and coords or vector3(coords.x, coords.y, coords.z) + + local function resolve(result) + if promise then + promise:resolve(result) + elseif cb then + cb(result) + end + end + + local function reject(err) + if promise then + promise:reject(err) + end + error(err) + end + + CreateThread(function() + local entity = CreateObject(model, objectCoords.x, objectCoords.y, objectCoords.z, true, true, false) + local tries = 0 + + while not DoesEntityExist(entity) do + Wait(200) + + tries = tries + 1 + + if tries > 40 then + return reject(("Could not spawn object - ^5%s^7!"):format(entity)) + end + end + + local networkId = NetworkGetNetworkIdFromEntity(entity) + + SetEntityHeading(entity, heading) + resolve(networkId) + end) + + if promise then + return Citizen.Await(promise) + end +end + +---@param model number|string +---@param coords vector3|table +---@param heading number +---@param cb? fun(netId: number) +---@return number? netId +function ESX.OneSync.SpawnPed(model, coords, heading, cb) + if type(model) == "string" then + model = joaat(model) + end + + local promise = not cb and promise.new() + + local function resolve(result) + if promise then + promise:resolve(result) + elseif cb then + cb(result) + end + end + + local function reject(err) + if promise then + promise:reject(err) + end + error(err) + end + + CreateThread(function() + local entity = CreatePed(0, model, coords.x, coords.y, coords.z, heading, true, true) + local tries = 0 + + while not DoesEntityExist(entity) do + Wait(200) + + tries = tries + 1 + + if tries > 40 then + return reject(("Could not spawn ped - ^5%s^7!"):format(model)) + end + end + + local networkId = NetworkGetNetworkIdFromEntity(entity) + resolve(networkId) + end) + + if promise then + return Citizen.Await(promise) + end +end + +---@param model number|string +---@param vehicle number entityId +---@param seat number +---@param cb? fun(netId: number) +---@return number? netId +function ESX.OneSync.SpawnPedInVehicle(model, vehicle, seat, cb) + if type(model) == "string" then + model = joaat(model) + end + + local promise = not cb and promise.new() + + local function resolve(result) + if promise then + promise:resolve(result) + elseif cb then + cb(result) + end + end + + local function reject(err) + if promise then + promise:reject(err) + end + error(err) + end + + CreateThread(function() + local entity = CreatePedInsideVehicle(vehicle, 1, model, seat, true, true) + local tries = 0 + + while not DoesEntityExist(entity) do + Wait(200) + + tries = tries + 1 + + if tries > 40 then + reject(("Could not spawn ped - ^5%s^7!"):format(model)) + end + end + + local networkId = NetworkGetNetworkIdFromEntity(entity) + resolve(networkId) + end) + + if promise then + return Citizen.Await(promise) + end +end + +local function getNearbyEntities(entities, coords, modelFilter, maxDistance, isPed) + local nearbyEntities = {} + coords = type(coords) == "number" and GetEntityCoords(GetPlayerPed(coords)) or vector3(coords.x, coords.y, coords.z) + for _, entity in pairs(entities) do + if not isPed or (isPed and not IsPedAPlayer(entity)) then + if not modelFilter or modelFilter[GetEntityModel(entity)] then + local entityCoords = GetEntityCoords(entity) + if not maxDistance or #(coords - entityCoords) <= maxDistance then + nearbyEntities[#nearbyEntities + 1] = NetworkGetNetworkIdFromEntity(entity) + end + end + end + end + + return nearbyEntities +end + +---@param coords vector3 +---@param maxDistance number +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return table +function ESX.OneSync.GetPedsInArea(coords, maxDistance, modelFilter) + return getNearbyEntities(GetAllPeds(), coords, modelFilter, maxDistance, true) +end + +---@param coords vector3 +---@param maxDistance number +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return table +function ESX.OneSync.GetObjectsInArea(coords, maxDistance, modelFilter) + return getNearbyEntities(GetAllObjects(), coords, modelFilter, maxDistance) +end + +---@param coords vector3 +---@param maxDistance number +---@param modelFilter table | nil models to ignore, where the key is the model hash and the value is true +---@return table +function ESX.OneSync.GetVehiclesInArea(coords, maxDistance, modelFilter) + return getNearbyEntities(GetAllVehicles(), coords, modelFilter, maxDistance) +end + +local function getClosestEntity(entities, coords, modelFilter, isPed) + local distance, closestEntity, closestCoords = 100, 0, vector3(0, 0, 0) + coords = type(coords) == "number" and GetEntityCoords(GetPlayerPed(coords)) or vector3(coords.x, coords.y, coords.z) + + for _, entity in pairs(entities) do + if not isPed or (isPed and not IsPedAPlayer(entity)) then + if not modelFilter or modelFilter[GetEntityModel(entity)] then + local entityCoords = GetEntityCoords(entity) + local dist = #(coords - entityCoords) + if dist < distance then + closestEntity, distance, closestCoords = entity, dist, entityCoords + end + end + end + end + + return NetworkGetNetworkIdFromEntity(closestEntity), distance, closestCoords +end + +---@param coords vector3 +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return number entityId, number distance, vector3 coords +function ESX.OneSync.GetClosestPed(coords, modelFilter) + return getClosestEntity(GetAllPeds(), coords, modelFilter, true) +end + +---@param coords vector3 +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return number entityId, number distance, vector3 coords +function ESX.OneSync.GetClosestObject(coords, modelFilter) + return getClosestEntity(GetAllObjects(), coords, modelFilter) +end + +---@param coords vector3 +---@param modelFilter table models to ignore, where the key is the model hash and the value is true +---@return number entityId, number distance, vector3 coords +function ESX.OneSync.GetClosestVehicle(coords, modelFilter) + return getClosestEntity(GetAllVehicles(), coords, modelFilter) +end diff --git a/resources/[core]/es_extended/server/modules/paycheck.lua b/resources/[core]/es_extended/server/modules/paycheck.lua new file mode 100644 index 0000000..5488170 --- /dev/null +++ b/resources/[core]/es_extended/server/modules/paycheck.lua @@ -0,0 +1,71 @@ +function StartPayCheck() + CreateThread(function() + while true do + Wait(Config.PaycheckInterval) + for player, xPlayer in pairs(ESX.Players) do + local jobLabel = xPlayer.job.label + local job = xPlayer.job.grade_name + local onDuty = xPlayer.job.onDuty + local salary = (job == "unemployed" or onDuty) and xPlayer.job.grade_salary or ESX.Math.Round(xPlayer.job.grade_salary * Config.OffDutyPaycheckMultiplier) + + if xPlayer.paycheckEnabled then + if salary > 0 then + if job == "unemployed" then -- unemployed + xPlayer.addAccountMoney("bank", salary, "Welfare Check") + TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), TranslateCap("received_paycheck"), TranslateCap("received_help", salary), "CHAR_BANK_MAZE", 9) + if Config.LogPaycheck then + ESX.DiscordLogFields("Paycheck", "Paycheck - Unemployment Benefits", "green", { + { name = "Player", value = xPlayer.name, inline = true }, + { name = "ID", value = xPlayer.source, inline = true }, + { name = "Amount", value = salary, inline = true }, + }) + end + elseif Config.EnableSocietyPayouts then -- possibly a society + TriggerEvent("esx_society:getSociety", xPlayer.job.name, function(society) + if society ~= nil then -- verified society + TriggerEvent("esx_addonaccount:getSharedAccount", society.account, function(account) + if account.money >= salary then -- does the society money to pay its employees? + xPlayer.addAccountMoney("bank", salary, "Paycheck") + account.removeMoney(salary) + if Config.LogPaycheck then + ESX.DiscordLogFields("Paycheck", "Paycheck - " .. jobLabel, "green", { + { name = "Player", value = xPlayer.name, inline = true }, + { name = "ID", value = xPlayer.source, inline = true }, + { name = "Amount", value = salary, inline = true }, + }) + end + + TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), TranslateCap("received_paycheck"), TranslateCap("received_salary", salary), "CHAR_BANK_MAZE", 9) + else + TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), "", TranslateCap("company_nomoney"), "CHAR_BANK_MAZE", 1) + end + end) + else -- not a society + xPlayer.addAccountMoney("bank", salary, "Paycheck") + if Config.LogPaycheck then + ESX.DiscordLogFields("Paycheck", "Paycheck - " .. jobLabel, "green", { + { name = "Player", value = xPlayer.name, inline = true }, + { name = "ID", value = xPlayer.source, inline = true }, + { name = "Amount", value = salary, inline = true }, + }) + end + TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), TranslateCap("received_paycheck"), TranslateCap("received_salary", salary), "CHAR_BANK_MAZE", 9) + end + end) + else -- generic job + xPlayer.addAccountMoney("bank", salary, "Paycheck") + if Config.LogPaycheck then + ESX.DiscordLogFields("Paycheck", "Paycheck - Generic", "green", { + { name = "Player", value = xPlayer.name, inline = true }, + { name = "ID", value = xPlayer.source, inline = true }, + { name = "Amount", value = salary, inline = true }, + }) + end + TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), TranslateCap("received_paycheck"), TranslateCap("received_salary", salary), "CHAR_BANK_MAZE", 9) + end + end + end + end + end + end) +end diff --git a/resources/[core]/es_extended/shared/config/adjustments.lua b/resources/[core]/es_extended/shared/config/adjustments.lua new file mode 100644 index 0000000..334e95d --- /dev/null +++ b/resources/[core]/es_extended/shared/config/adjustments.lua @@ -0,0 +1,80 @@ +Config.DisableHealthRegeneration = false -- Player will no longer regenerate health +Config.DisableVehicleRewards = false -- Disables Player Receiving weapons from vehicles +Config.DisableNPCDrops = false -- stops NPCs from dropping weapons on death +Config.DisableDispatchServices = true -- Disable Dispatch services +Config.DisableScenarios = true -- Disable Scenarios +Config.DisableAimAssist = false -- disables AIM assist (mainly on controllers) +Config.DisableVehicleSeatShuff = false -- Disables vehicle seat shuff +Config.DisableDisplayAmmo = false -- Disable ammunition display +Config.EnablePVP = true -- Allow Player to player combat +Config.EnableWantedLevel = false -- Use Normal GTA wanted Level? + +Config.RemoveHudComponents = { + [1] = false, --WANTED_STARS, + [2] = false, --WEAPON_ICON + [3] = false, --CASH + [4] = false, --MP_CASH + [5] = false, --MP_MESSAGE + [6] = true, --VEHICLE_NAME + [7] = true, -- AREA_NAME + [8] = true, -- VEHICLE_CLASS + [9] = true, --STREET_NAME + [10] = false, --HELP_TEXT + [11] = false, --FLOATING_HELP_TEXT_1 + [12] = false, --FLOATING_HELP_TEXT_2 + [13] = false, --CASH_CHANGE + [14] = false, --RETICLE + [15] = false, --SUBTITLE_TEXT + [16] = false, --RADIO_STATIONS + [17] = false, --SAVING_GAME, + [18] = false, --GAME_STREAM + [19] = false, --WEAPON_WHEEL + [20] = false, --WEAPON_WHEEL_STATS + [21] = false, --HUD_COMPONENTS + [22] = false, --HUD_WEAPONS +} + +Config.Multipliers = { + pedDensity = 1.0, + scenarioPedDensityInterior = 0.0, + scenarioPedDensityExterior = 1.0, + ambientVehicleRange = 1.0, + parkedVehicleDensity = 1.0, + randomVehicleDensity = 1.0, + vehicleDensity = 1.0 +} + +-- Pattern string format +--1 will lead to a random number from 0-9. +--A will lead to a random letter from A-Z. +-- . will lead to a random letter or number, with a 50% probability of being either. +--^1 will lead to a literal 1 being emitted. +--^A will lead to a literal A being emitted. +--Any other character will lead to said character being emitted. +-- A string shorter than 8 characters will be padded on the right. +Config.CustomAIPlates = "........" -- Custom plates for AI vehicles + +--[[ + PlaceHolders: + {server_name} - Server Display Name + {server_endpoint} - Server IP:Server Port + {server_players} - Current Player Count + {server_maxplayers} - Max Player Count + + {player_name} - Player Name + {player_rp_name} - Player RP Name + {player_id} - Player ID + {player_street} - Player Street Name +]] + +Config.DiscordActivity = { + appId = 0, -- Discord Application ID, + assetName = "LargeIcon", --image name for the "large" icon. + assetText = "{server_name}", -- Text to display on the asset + buttons = { + { label = "Join Server", url = "fivem://connect/{server_endpoint}" }, + { label = "Discord", url = "https://discord.esx-framework.org" }, + }, + presence = "{player_name} [{player_id}] | {server_players}/{server_maxplayers}", + refresh = 1 * 60 * 1000, -- 1 minute +} diff --git a/resources/[core]/es_extended/shared/config/logs.lua b/resources/[core]/es_extended/shared/config/logs.lua new file mode 100644 index 0000000..34c013a --- /dev/null +++ b/resources/[core]/es_extended/shared/config/logs.lua @@ -0,0 +1,23 @@ +Config.DiscordLogs = { + Webhooks = { + default = "", + test = "", + Chat = "", + UserActions = "", + Resources = "", + Paycheck = "", + }, + + Colors = { -- https://www.spycolor.com/ + default = 14423100, + blue = 255, + red = 16711680, + green = 65280, + white = 16777215, + black = 0, + orange = 16744192, + yellow = 16776960, + pink = 16761035, + lightgreen = 65309, + }, +} diff --git a/resources/[core]/es_extended/shared/config/main.lua b/resources/[core]/es_extended/shared/config/main.lua new file mode 100644 index 0000000..0bb5511 --- /dev/null +++ b/resources/[core]/es_extended/shared/config/main.lua @@ -0,0 +1,75 @@ +Config = {} + +local txAdminLocale = GetConvar("txAdmin-locale", "en") +local esxLocale = GetConvar("esx:locale", "invalid") +Config.Locale = (esxLocale ~= "invalid") and esxLocale or (txAdminLocale ~= "custom" and txAdminLocale) or "en" + +-- For ox inventory, this will automatically be adjusted, do not change! For other inventories, leave as false unless specifically instructed to change. +Config.CustomInventory = false + +Config.Accounts = { + bank = { + label = TranslateCap("account_bank"), + round = true, + }, + black_money = { + label = TranslateCap("account_black_money"), + round = true, + }, + money = { + label = TranslateCap("account_money"), + round = true, + }, +} + +Config.StartingAccountMoney = { bank = 50000 } + +Config.StartingInventoryItems = false -- table/false + +Config.DefaultSpawns = { -- If you want to have more spawn positions and select them randomly uncomment commented code or add more locations + { x = 222.2027, y = -864.0162, z = 30.2922, heading = 1.0 }, + --{x = 224.9865, y = -865.0871, z = 30.2922, heading = 1.0}, + --{x = 227.8436, y = -866.0400, z = 30.2922, heading = 1.0}, + --{x = 230.6051, y = -867.1450, z = 30.2922, heading = 1.0}, + --{x = 233.5459, y = -868.2626, z = 30.2922, heading = 1.0} +} + +Config.AdminGroups = { + ["owner"] = true, + ["admin"] = true, +} + +Config.ValidCharacterSets = { -- Only enable additional charsets if your server is multilingual. By default everything is false. + ['el'] = false, -- Greek + ['sr'] = false, -- Cyrillic + ['he'] = false, -- Hebrew + ['ar'] = false, -- Arabic + ['zh-cn'] = false -- Chinese, Japanese, Korean +} + +Config.EnablePaycheck = true -- enable paycheck +Config.LogPaycheck = false -- Logs paychecks to a nominated Discord channel via webhook (default is false) +Config.EnableSocietyPayouts = false -- pay from the society account that the player is employed at? Requirement: esx_society +Config.MaxWeight = 24 -- the max inventory weight without a backpack +Config.PaycheckInterval = 7 * 60000 -- how often to receive paychecks in milliseconds +Config.SaveDeathStatus = true -- Save the death status of a player +Config.EnableDebug = false -- Use Debug options? + +Config.DefaultJobDuty = true -- A players default duty status when changing jobs +Config.OffDutyPaycheckMultiplier = 0.5 -- The multiplier for off duty paychecks. 0.5 = 50% of the on duty paycheck + +Config.Multichar = GetResourceState("esx_multicharacter") ~= "missing" +Config.Identity = true -- Select a character identity data before they have loaded in (this happens by default with multichar) +Config.DistanceGive = 4.0 -- Max distance when giving items, weapons etc. + +Config.AdminLogging = false -- Logs the usage of certain commands by those with group.admin ace permissions (default is false) + +------------------------------------- +-- DO NOT CHANGE BELOW THIS LINE !!! +------------------------------------- +if GetResourceState("ox_inventory") ~= "missing" then + Config.CustomInventory = "ox" +end + +Config.EnableDefaultInventory = Config.CustomInventory == false -- Display the default Inventory ( F2 ) +Config.Identifier = GetConvar("esx:identifier", "license") \ No newline at end of file diff --git a/resources/[core]/es_extended/shared/config/weapons.lua b/resources/[core]/es_extended/shared/config/weapons.lua new file mode 100644 index 0000000..7afc367 --- /dev/null +++ b/resources/[core]/es_extended/shared/config/weapons.lua @@ -0,0 +1,1108 @@ +Config.DefaultWeaponTints = { + [0] = TranslateCap("tint_default"), + [1] = TranslateCap("tint_green"), + [2] = TranslateCap("tint_gold"), + [3] = TranslateCap("tint_pink"), + [4] = TranslateCap("tint_army"), + [5] = TranslateCap("tint_lspd"), + [6] = TranslateCap("tint_orange"), + [7] = TranslateCap("tint_platinum"), +} +Config.MK2WeaponTints = { + [0] = TranslateCap('tint_classic_black'), + [1] = TranslateCap('tint_classic_gray'), + [2] = TranslateCap('tint_classic_two_tone'), + [3] = TranslateCap('tint_classic_white'), + [4] = TranslateCap('tint_classic_beige'), + [5] = TranslateCap('tint_classic_green'), + [6] = TranslateCap('tint_classic_blue'), + [7] = TranslateCap('tint_classic_earth'), + [8] = TranslateCap('tint_classic_brown_black'), + [9] = TranslateCap('tint_contrast_red'), + [10] = TranslateCap('tint_contrast_blue'), + [11] = TranslateCap('tint_contrast_yellow'), + [12] = TranslateCap('tint_contrast_orange'), + [13] = TranslateCap('tint_bold_pink'), + [14] = TranslateCap('tint_bold_purple_yellow'), + [15] = TranslateCap('tint_bold_orange'), + [16] = TranslateCap('tint_bold_green_purple'), + [17] = TranslateCap('tint_bold_red_feat'), + [18] = TranslateCap('tint_bold_green_feat'), + [19] = TranslateCap('tint_bold_cyan_feat'), + [20] = TranslateCap('tint_bold_yellow_feat'), + [21] = TranslateCap('tint_bold_red_white'), + [22] = TranslateCap('tint_bold_blue_white'), + [23] = TranslateCap('tint_metallic_gold'), + [24] = TranslateCap('tint_metallic_platinum'), + [25] = TranslateCap('tint_metallic_gray_lilac'), + [26] = TranslateCap('tint_metallic_purple_lime'), + [27] = TranslateCap('tint_metallic_red'), + [28] = TranslateCap('tint_metallic_green'), + [29] = TranslateCap('tint_metallic_blue'), + [30] = TranslateCap('tint_metallic_white_aqua'), + [31] = TranslateCap('tint_metallic_orange_yellow'), + [32] = TranslateCap('tint_metallic_red_yellow') +} + +Config.Weapons = { + -- Melee + { name = "WEAPON_DAGGER", label = TranslateCap("weapon_dagger"), components = {} }, + { name = "WEAPON_BAT", label = TranslateCap("weapon_bat"), components = {} }, + { name = "WEAPON_BATTLEAXE", label = TranslateCap("weapon_battleaxe"), components = {} }, + { + name = "WEAPON_KNUCKLE", + label = TranslateCap("weapon_knuckle"), + components = { + { name = "knuckle_base", label = TranslateCap("component_knuckle_base"), hash = `COMPONENT_KNUCKLE_VARMOD_BASE` }, + { name = "knuckle_pimp", label = TranslateCap("component_knuckle_pimp"), hash = `COMPONENT_KNUCKLE_VARMOD_PIMP` }, + { name = "knuckle_ballas", label = TranslateCap("component_knuckle_ballas"), hash = `COMPONENT_KNUCKLE_VARMOD_BALLAS` }, + { name = "knuckle_dollar", label = TranslateCap("component_knuckle_dollar"), hash = `COMPONENT_KNUCKLE_VARMOD_DOLLAR` }, + { name = "knuckle_diamond", label = TranslateCap("component_knuckle_diamond"), hash = `COMPONENT_KNUCKLE_VARMOD_DIAMOND` }, + { name = "knuckle_hate", label = TranslateCap("component_knuckle_hate"), hash = `COMPONENT_KNUCKLE_VARMOD_HATE` }, + { name = "knuckle_love", label = TranslateCap("component_knuckle_love"), hash = `COMPONENT_KNUCKLE_VARMOD_LOVE` }, + { name = "knuckle_player", label = TranslateCap("component_knuckle_player"), hash = `COMPONENT_KNUCKLE_VARMOD_PLAYER` }, + { name = "knuckle_king", label = TranslateCap("component_knuckle_king"), hash = `COMPONENT_KNUCKLE_VARMOD_KING` }, + { name = "knuckle_vagos", label = TranslateCap("component_knuckle_vagos"), hash = `COMPONENT_KNUCKLE_VARMOD_VAGOS` }, + }, + }, + { name = "WEAPON_BOTTLE", label = TranslateCap("weapon_bottle"), components = {} }, + { name = "WEAPON_CROWBAR", label = TranslateCap("weapon_crowbar"), components = {} }, + { name = "WEAPON_FLASHLIGHT", label = TranslateCap("weapon_flashlight"), components = {} }, + { name = "WEAPON_GOLFCLUB", label = TranslateCap("weapon_golfclub"), components = {} }, + { name = "WEAPON_HAMMER", label = TranslateCap("weapon_hammer"), components = {} }, + { name = "WEAPON_HATCHET", label = TranslateCap("weapon_hatchet"), components = {} }, + { name = "WEAPON_KNIFE", label = TranslateCap("weapon_knife"), components = {} }, + { name = "WEAPON_MACHETE", label = TranslateCap("weapon_machete"), components = {} }, + { name = "WEAPON_NIGHTSTICK", label = TranslateCap("weapon_nightstick"), components = {} }, + { name = "WEAPON_WRENCH", label = TranslateCap("weapon_wrench"), components = {} }, + { name = "WEAPON_POOLCUE", label = TranslateCap("weapon_poolcue"), components = {} }, + { name = "WEAPON_STONE_HATCHET", label = TranslateCap("weapon_stone_hatchet"), components = {} }, + { + name = "WEAPON_SWITCHBLADE", + label = TranslateCap("weapon_switchblade"), + components = { + { name = "handle_default", label = TranslateCap("component_handle_default"), hash = `COMPONENT_SWITCHBLADE_VARMOD_BASE` }, + { name = "handle_vip", label = TranslateCap("component_handle_vip"), hash = `COMPONENT_SWITCHBLADE_VARMOD_VAR1` }, + { name = "handle_bodyguard", label = TranslateCap("component_handle_bodyguard"), hash = `COMPONENT_SWITCHBLADE_VARMOD_VAR2` }, + }, + }, + -- Handguns + { + name = "WEAPON_APPISTOL", + label = TranslateCap("weapon_appistol"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_APPISTOL_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_APPISTOL_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_PI_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_APPISTOL_VARMOD_LUXE` }, + }, + }, + { name = "WEAPON_CERAMICPISTOL", label = TranslateCap("weapon_ceramicpistol"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` } }, + { + name = "WEAPON_COMBATPISTOL", + label = TranslateCap("weapon_combatpistol"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_COMBATPISTOL_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_COMBATPISTOL_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_PI_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_COMBATPISTOL_VARMOD_LOWRIDER` }, + }, + }, + { name = "WEAPON_DOUBLEACTION", label = TranslateCap("weapon_doubleaction"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` } }, + { name = "WEAPON_NAVYREVOLVER", label = TranslateCap("weapon_navyrevolver"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` } }, + { name = "WEAPON_FLAREGUN", label = TranslateCap("weapon_flaregun"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_flaregun"), hash = `AMMO_FLAREGUN` } }, + { name = "WEAPON_GADGETPISTOL", label = TranslateCap("weapon_gadgetpistol"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` } }, + { + name = "WEAPON_HEAVYPISTOL", + label = TranslateCap("weapon_heavypistol"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_HEAVYPISTOL_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_HEAVYPISTOL_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_PI_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_HEAVYPISTOL_VARMOD_LUXE` }, + }, + }, + { + name = "WEAPON_REVOLVER", + label = TranslateCap("weapon_revolver"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_REVOLVER_CLIP_01` }, + { name = "vip_finish", label = TranslateCap("component_vip_finish"), hash = `COMPONENT_REVOLVER_VARMOD_BOSS` }, + { name = "bodyguard_finish", label = TranslateCap("component_bodyguard_finish"), hash = `COMPONENT_REVOLVER_VARMOD_GOON` }, + }, + }, + { + name = "WEAPON_REVOLVER_MK2", + label = TranslateCap("weapon_revolver_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_REVOLVER_MK2_CLIP_01` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_REVOLVER_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_REVOLVER_MK2_CLIP_INCENDIARY` }, + { name = "ammo_hollowpoint", label = TranslateCap("component_ammo_hollowpoint"), hash = `COMPONENT_REVOLVER_MK2_CLIP_HOLLOWPOINT` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_REVOLVER_MK2_CLIP_FMJ` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_AT_SIGHTS` }, + { name = "scope_small", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_AT_SCOPE_MACRO_MK2` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_PI_FLSH` }, + { name = "compensator", label = TranslateCap("component_compensator"), hash = `COMPONENT_AT_PI_COMP_03` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_REVOLVER_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_REVOLVER_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_REVOLVER_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_REVOLVER_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_REVOLVER_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_REVOLVER_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_REVOLVER_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_REVOLVER_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_REVOLVER_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_REVOLVER_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_REVOLVER_MK2_CAMO_IND_01` }, + }, + }, + { name = "WEAPON_MARKSMANPISTOL", label = TranslateCap("weapon_marksmanpistol"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` } }, + { + name = "WEAPON_PISTOL", + label = TranslateCap("weapon_pistol"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_PISTOL_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_PISTOL_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_PI_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP_02` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_PISTOL_VARMOD_LUXE` }, + }, + }, + { + name = "WEAPON_PISTOL_MK2", + label = TranslateCap("weapon_pistol_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_PISTOL_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_PISTOL_MK2_CLIP_02` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_PISTOL_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_PISTOL_MK2_CLIP_INCENDIARY` }, + { name = "ammo_hollowpoint", label = TranslateCap("component_ammo_hollowpoint"), hash = `COMPONENT_PISTOL_MK2_CLIP_HOLLOWPOINT` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_PISTOL_MK2_CLIP_FMJ` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_PI_RAIL` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_PI_FLSH_02` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP_02` }, + { name = "compensator", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_COMP` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_PISTOL_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_PISTOL_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_PISTOL_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_PISTOL_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_PISTOL_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_PISTOL_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_PISTOL_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_PISTOL_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_PISTOL_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_PISTOL_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_PISTOL_MK2_CAMO_IND_01` }, + { name = "camo_slide_finish", label = TranslateCap("component_camo_slide_finish"), hash = `COMPONENT_PISTOL_MK2_CAMO_SLIDE` }, + { name = "camo_slide_finish2", label = TranslateCap("component_camo_slide_finish2"), hash = `COMPONENT_PISTOL_MK2_CAMO_02_SLIDE` }, + { name = "camo_slide_finish3", label = TranslateCap("component_camo_slide_finish3"), hash = `COMPONENT_PISTOL_MK2_CAMO_03_SLIDE` }, + { name = "camo_slide_finish4", label = TranslateCap("component_camo_slide_finish4"), hash = `COMPONENT_PISTOL_MK2_CAMO_04_SLIDE` }, + { name = "camo_slide_finish5", label = TranslateCap("component_camo_slide_finish5"), hash = `COMPONENT_PISTOL_MK2_CAMO_05_SLIDE` }, + { name = "camo_slide_finish6", label = TranslateCap("component_camo_slide_finish6"), hash = `COMPONENT_PISTOL_MK2_CAMO_06_SLIDE` }, + { name = "camo_slide_finish7", label = TranslateCap("component_camo_slide_finish7"), hash = `COMPONENT_PISTOL_MK2_CAMO_07_SLIDE` }, + { name = "camo_slide_finish8", label = TranslateCap("component_camo_slide_finish8"), hash = `COMPONENT_PISTOL_MK2_CAMO_08_SLIDE` }, + { name = "camo_slide_finish9", label = TranslateCap("component_camo_slide_finish9"), hash = `COMPONENT_PISTOL_MK2_CAMO_09_SLIDE` }, + { name = "camo_slide_finish10", label = TranslateCap("component_camo_slide_finish10"), hash = `COMPONENT_PISTOL_MK2_CAMO_10_SLIDE` }, + { name = "camo_slide_finish11", label = TranslateCap("component_camo_slide_finish11"), hash = `COMPONENT_PISTOL_MK2_CAMO_IND_01_SLIDE` }, + }, + }, + { + name = "WEAPON_PISTOL50", + label = TranslateCap("weapon_pistol50"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_PISTOL50_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_PISTOL50_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_PI_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_PISTOL50_VARMOD_LUXE` }, + }, + }, + { + name = "WEAPON_SNSPISTOL", + label = TranslateCap("weapon_snspistol"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_SNSPISTOL_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_SNSPISTOL_CLIP_02` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_SNSPISTOL_VARMOD_LOWRIDER` }, + }, + }, + { + name = "WEAPON_SNSPISTOL_MK2", + label = TranslateCap("weapon_snspistol_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_SNSPISTOL_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_SNSPISTOL_MK2_CLIP_02` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_SNSPISTOL_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_SNSPISTOL_MK2_CLIP_INCENDIARY` }, + { name = "ammo_hollowpoint", label = TranslateCap("component_ammo_hollowpoint"), hash = `COMPONENT_SNSPISTOL_MK2_CLIP_HOLLOWPOINT` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_SNSPISTOL_MK2_CLIP_FMJ` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_PI_RAIL_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_PI_FLSH_03` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP_02` }, + { name = "compensator", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_COMP_02` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_IND_01` }, + { name = "camo_slide_finish", label = TranslateCap("component_camo_slide_finish"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_SLIDE` }, + { name = "camo_slide_finish2", label = TranslateCap("component_camo_slide_finish2"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_02_SLIDE` }, + { name = "camo_slide_finish3", label = TranslateCap("component_camo_slide_finish3"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_03_SLIDE` }, + { name = "camo_slide_finish4", label = TranslateCap("component_camo_slide_finish4"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_04_SLIDE` }, + { name = "camo_slide_finish5", label = TranslateCap("component_camo_slide_finish5"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_05_SLIDE` }, + { name = "camo_slide_finish6", label = TranslateCap("component_camo_slide_finish6"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_06_SLIDE` }, + { name = "camo_slide_finish7", label = TranslateCap("component_camo_slide_finish7"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_07_SLIDE` }, + { name = "camo_slide_finish8", label = TranslateCap("component_camo_slide_finish8"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_08_SLIDE` }, + { name = "camo_slide_finish9", label = TranslateCap("component_camo_slide_finish9"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_09_SLIDE` }, + { name = "camo_slide_finish10", label = TranslateCap("component_camo_slide_finish10"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_10_SLIDE` }, + { name = "camo_slide_finish11", label = TranslateCap("component_camo_slide_finish11"), hash = `COMPONENT_SNSPISTOL_MK2_CAMO_IND_01_SLIDE` }, + }, + }, + { name = "WEAPON_STUNGUN", label = TranslateCap("weapon_stungun"), tints = Config.DefaultWeaponTints, components = {} }, + { name = "WEAPON_STUNROD", label = TranslateCap("weapon_stunrod"), tints = Config.DefaultWeaponTints, components = {} }, + { name = "WEAPON_RAYPISTOL", label = TranslateCap("weapon_raypistol"), tints = Config.DefaultWeaponTints, components = {} }, + { + name = "WEAPON_VINTAGEPISTOL", + label = TranslateCap("weapon_vintagepistol"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_VINTAGEPISTOL_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_VINTAGEPISTOL_CLIP_02` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP` }, + }, + }, + -- Shotguns + { + name = "WEAPON_ASSAULTSHOTGUN", + label = TranslateCap("weapon_assaultshotgun"), + ammo = { label = TranslateCap("ammo_shells"), hash = `AMMO_SHOTGUN` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_ASSAULTSHOTGUN_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_ASSAULTSHOTGUN_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + }, + }, + { name = "WEAPON_AUTOSHOTGUN", label = TranslateCap("weapon_autoshotgun"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_shells"), hash = `AMMO_SHOTGUN` } }, + { + name = "WEAPON_BULLPUPSHOTGUN", + label = TranslateCap("weapon_bullpupshotgun"), + ammo = { label = TranslateCap("ammo_shells"), hash = `AMMO_SHOTGUN` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + }, + }, + { + name = "WEAPON_COMBATSHOTGUN", + label = TranslateCap("weapon_combatshotgun"), + ammo = { label = TranslateCap("ammo_shells"), hash = `AMMO_SHOTGUN` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + }, + }, + { name = "WEAPON_DBSHOTGUN", label = TranslateCap("weapon_dbshotgun"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_shells"), hash = `AMMO_SHOTGUN` } }, + { + name = "WEAPON_HEAVYSHOTGUN", + label = TranslateCap("weapon_heavyshotgun"), + ammo = { label = TranslateCap("ammo_shells"), hash = `AMMO_SHOTGUN` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_HEAVYSHOTGUN_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_HEAVYSHOTGUN_CLIP_02` }, + { name = "clip_drum", label = TranslateCap("component_clip_drum"), hash = `COMPONENT_HEAVYSHOTGUN_CLIP_03` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + }, + }, + { name = "WEAPON_MUSKET", label = TranslateCap("weapon_musket"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SHOTGUN` } }, + { + name = "WEAPON_PUMPSHOTGUN", + label = TranslateCap("weapon_pumpshotgun"), + ammo = { label = TranslateCap("ammo_shells"), hash = `AMMO_SHOTGUN` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_SR_SUPP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_PUMPSHOTGUN_VARMOD_LOWRIDER` }, + }, + }, + { + name = "WEAPON_PUMPSHOTGUN_MK2", + label = TranslateCap("weapon_pumpshotgun_mk2"), + ammo = { label = TranslateCap("ammo_shells"), hash = `AMMO_SHOTGUN` }, + tints = Config.MK2WeaponTints, + components = { + { name = "shells_default", label = TranslateCap("component_shells_default"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CLIP_01` }, + { name = "shells_incendiary", label = TranslateCap("component_shells_incendiary"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CLIP_INCENDIARY` }, + { name = "shells_armor", label = TranslateCap("component_shells_armor"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CLIP_ARMORPIERCING` }, + { name = "shells_hollowpoint", label = TranslateCap("component_shells_hollowpoint"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CLIP_HOLLOWPOINT` }, + { name = "shells_explosive", label = TranslateCap("component_shells_explosive"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CLIP_EXPLOSIVE` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_AT_SIGHTS` }, + { name = "scope_small", label = TranslateCap("component_scope_small"), hash = `COMPONENT_AT_SCOPE_MACRO_MK2` }, + { name = "scope_medium", label = TranslateCap("component_scope_medium"), hash = `COMPONENT_AT_SCOPE_SMALL_MK2` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_SR_SUPP_03` }, + { name = "muzzle_squared", label = TranslateCap("component_muzzle_squared"), hash = `COMPONENT_AT_MUZZLE_08` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_PUMPSHOTGUN_MK2_CAMO_IND_01` }, + }, + }, + { + name = "WEAPON_SAWNOFFSHOTGUN", + label = TranslateCap("weapon_sawnoffshotgun"), + ammo = { label = TranslateCap("ammo_shells"), hash = `AMMO_SHOTGUN` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_SAWNOFFSHOTGUN_VARMOD_LUXE` }, + }, + }, + -- SMG & LMG + { + name = "WEAPON_ASSAULTSMG", + label = TranslateCap("weapon_assaultsmg"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SMG` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_ASSAULTSMG_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_ASSAULTSMG_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_MACRO` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_ASSAULTSMG_VARMOD_LOWRIDER` }, + }, + }, + { + name = "WEAPON_COMBATMG", + label = TranslateCap("weapon_combatmg"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_MG` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_COMBATMG_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_COMBATMG_CLIP_02` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_MEDIUM` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_COMBATMG_VARMOD_LOWRIDER` }, + }, + }, + { + name = "WEAPON_COMBATMG_MK2", + label = TranslateCap("weapon_combatmg_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_MG` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_COMBATMG_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_COMBATMG_MK2_CLIP_02` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_COMBATMG_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_COMBATMG_MK2_CLIP_INCENDIARY` }, + { name = "ammo_hollowpoint", label = TranslateCap("component_ammo_hollowpoint"), hash = `COMPONENT_COMBATMG_MK2_CLIP_ARMORPIERCING` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_COMBATMG_MK2_CLIP_FMJ` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP_02` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_AT_SIGHTS` }, + { name = "scope_medium", label = TranslateCap("component_scope_medium"), hash = `COMPONENT_AT_SCOPE_SMALL_MK2` }, + { name = "scope_large", label = TranslateCap("component_scope_large"), hash = `COMPONENT_AT_SCOPE_MEDIUM_MK2` }, + { name = "muzzle_flat", label = TranslateCap("component_muzzle_flat"), hash = `COMPONENT_AT_MUZZLE_01` }, + { name = "muzzle_tactical", label = TranslateCap("component_muzzle_tactical"), hash = `COMPONENT_AT_MUZZLE_02` }, + { name = "muzzle_fat", label = TranslateCap("component_muzzle_fat"), hash = `COMPONENT_AT_MUZZLE_03` }, + { name = "muzzle_precision", label = TranslateCap("component_muzzle_precision"), hash = `COMPONENT_AT_MUZZLE_04` }, + { name = "muzzle_heavy", label = TranslateCap("component_muzzle_heavy"), hash = `COMPONENT_AT_MUZZLE_05` }, + { name = "muzzle_slanted", label = TranslateCap("component_muzzle_slanted"), hash = `COMPONENT_AT_MUZZLE_06` }, + { name = "muzzle_split", label = TranslateCap("component_muzzle_split"), hash = `COMPONENT_AT_MUZZLE_07` }, + { name = "barrel_default", label = TranslateCap("component_barrel_default"), hash = `COMPONENT_AT_MG_BARREL_01` }, + { name = "barrel_heavy", label = TranslateCap("component_barrel_heavy"), hash = `COMPONENT_AT_MG_BARREL_02` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_COMBATMG_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_COMBATMG_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_COMBATMG_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_COMBATMG_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_COMBATMG_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_COMBATMG_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_COMBATMG_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_COMBATMG_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_COMBATMG_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_COMBATMG_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_COMBATMG_MK2_CAMO_IND_01` }, + }, + }, + { + name = "WEAPON_COMBATPDW", + label = TranslateCap("weapon_combatpdw"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SMG` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_COMBATPDW_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_COMBATPDW_CLIP_02` }, + { name = "clip_drum", label = TranslateCap("component_clip_drum"), hash = `COMPONENT_COMBATPDW_CLIP_03` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_SMALL` }, + }, + }, + { + name = "WEAPON_GUSENBERG", + label = TranslateCap("weapon_gusenberg"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_MG` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_GUSENBERG_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_GUSENBERG_CLIP_02` }, + }, + }, + { + name = "WEAPON_MACHINEPISTOL", + label = TranslateCap("weapon_machinepistol"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_MACHINEPISTOL_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_MACHINEPISTOL_CLIP_02` }, + { name = "clip_drum", label = TranslateCap("component_clip_drum"), hash = `COMPONENT_MACHINEPISTOL_CLIP_03` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP` }, + }, + }, + { + name = "WEAPON_MG", + label = TranslateCap("weapon_mg"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_MG` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_MG_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_MG_CLIP_02` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_SMALL_02` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_MG_VARMOD_LOWRIDER` }, + }, + }, + { + name = "WEAPON_MICROSMG", + label = TranslateCap("weapon_microsmg"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SMG` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_MICROSMG_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_MICROSMG_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_PI_FLSH` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_MACRO` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_MICROSMG_VARMOD_LUXE` }, + }, + }, + { + name = "WEAPON_MINISMG", + label = TranslateCap("weapon_minismg"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SMG` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_MINISMG_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_MINISMG_CLIP_02` }, + }, + }, + { + name = "WEAPON_SMG", + label = TranslateCap("weapon_smg"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SMG` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_SMG_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_SMG_CLIP_02` }, + { name = "clip_drum", label = TranslateCap("component_clip_drum"), hash = `COMPONENT_SMG_CLIP_03` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_MACRO_02` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_SMG_VARMOD_LUXE` }, + }, + }, + { + name = "WEAPON_TECPISTOL", + label = TranslateCap("weapon_tecpistol"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SMG` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_TECPISTOL_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_TECPISTOL_CLIP_02` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_MACRO` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + }, + }, + { + name = "WEAPON_SMG_MK2", + label = TranslateCap("weapon_smg_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SMG` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_SMG_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_SMG_MK2_CLIP_02` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_SMG_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_SMG_MK2_CLIP_INCENDIARY` }, + { name = "ammo_hollowpoint", label = TranslateCap("component_ammo_hollowpoint"), hash = `COMPONENT_SMG_MK2_CLIP_HOLLOWPOINT` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_SMG_MK2_CLIP_FMJ` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_AT_SIGHTS_SMG` }, + { name = "scope_small", label = TranslateCap("component_scope_small"), hash = `COMPONENT_AT_SCOPE_MACRO_02_SMG_MK2` }, + { name = "scope_medium", label = TranslateCap("component_scope_medium"), hash = `COMPONENT_AT_SCOPE_SMALL_SMG_MK2` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_PI_SUPP` }, + { name = "muzzle_flat", label = TranslateCap("component_muzzle_flat"), hash = `COMPONENT_AT_MUZZLE_01` }, + { name = "muzzle_tactical", label = TranslateCap("component_muzzle_tactical"), hash = `COMPONENT_AT_MUZZLE_02` }, + { name = "muzzle_fat", label = TranslateCap("component_muzzle_fat"), hash = `COMPONENT_AT_MUZZLE_03` }, + { name = "muzzle_precision", label = TranslateCap("component_muzzle_precision"), hash = `COMPONENT_AT_MUZZLE_04` }, + { name = "muzzle_heavy", label = TranslateCap("component_muzzle_heavy"), hash = `COMPONENT_AT_MUZZLE_05` }, + { name = "muzzle_slanted", label = TranslateCap("component_muzzle_slanted"), hash = `COMPONENT_AT_MUZZLE_06` }, + { name = "muzzle_split", label = TranslateCap("component_muzzle_split"), hash = `COMPONENT_AT_MUZZLE_07` }, + { name = "barrel_default", label = TranslateCap("component_barrel_default"), hash = `COMPONENT_AT_SB_BARREL_01` }, + { name = "barrel_heavy", label = TranslateCap("component_barrel_heavy"), hash = `COMPONENT_AT_SB_BARREL_02` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_SMG_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_SMG_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_SMG_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_SMG_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_SMG_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_SMG_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_SMG_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_SMG_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_SMG_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_SMG_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_SMG_MK2_CAMO_IND_01` }, + }, + }, + { name = "WEAPON_RAYCARBINE", label = TranslateCap("weapon_raycarbine"), ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SMG` }, tints = Config.DefaultWeaponTints, components = {} }, + -- Rifles + { + name = "WEAPON_ADVANCEDRIFLE", + label = TranslateCap("weapon_advancedrifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_ADVANCEDRIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_ADVANCEDRIFLE_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_SMALL` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_ADVANCEDRIFLE_VARMOD_LUXE` }, + }, + }, + { + name = "WEAPON_ASSAULTRIFLE", + label = TranslateCap("weapon_assaultrifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_ASSAULTRIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_ASSAULTRIFLE_CLIP_02` }, + { name = "clip_drum", label = TranslateCap("component_clip_drum"), hash = `COMPONENT_ASSAULTRIFLE_CLIP_03` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_MACRO` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_ASSAULTRIFLE_VARMOD_LUXE` }, + }, + }, + { + name = "WEAPON_ASSAULTRIFLE_MK2", + label = TranslateCap("weapon_assaultrifle_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CLIP_02` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CLIP_INCENDIARY` }, + { name = "ammo_armor", label = TranslateCap("component_ammo_armor"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CLIP_ARMORPIERCING` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CLIP_FMJ` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_AT_SIGHTS` }, + { name = "scope_small", label = TranslateCap("component_scope_small"), hash = `COMPONENT_AT_SCOPE_MACRO_MK2` }, + { name = "scope_large", label = TranslateCap("component_scope_large"), hash = `COMPONENT_AT_SCOPE_MEDIUM_MK2` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "muzzle_flat", label = TranslateCap("component_muzzle_flat"), hash = `COMPONENT_AT_MUZZLE_01` }, + { name = "muzzle_tactical", label = TranslateCap("component_muzzle_tactical"), hash = `COMPONENT_AT_MUZZLE_02` }, + { name = "muzzle_fat", label = TranslateCap("component_muzzle_fat"), hash = `COMPONENT_AT_MUZZLE_03` }, + { name = "muzzle_precision", label = TranslateCap("component_muzzle_precision"), hash = `COMPONENT_AT_MUZZLE_04` }, + { name = "muzzle_heavy", label = TranslateCap("component_muzzle_heavy"), hash = `COMPONENT_AT_MUZZLE_05` }, + { name = "muzzle_slanted", label = TranslateCap("component_muzzle_slanted"), hash = `COMPONENT_AT_MUZZLE_06` }, + { name = "muzzle_split", label = TranslateCap("component_muzzle_split"), hash = `COMPONENT_AT_MUZZLE_07` }, + { name = "barrel_default", label = TranslateCap("component_barrel_default"), hash = `COMPONENT_AT_AR_BARREL_01` }, + { name = "barrel_heavy", label = TranslateCap("component_barrel_heavy"), hash = `COMPONENT_AT_AR_BARREL_02` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_ASSAULTRIFLE_MK2_CAMO_IND_01` }, + }, + }, + { + name = "WEAPON_BULLPUPRIFLE", + label = TranslateCap("weapon_bullpuprifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_BULLPUPRIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_BULLPUPRIFLE_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_SMALL` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_BULLPUPRIFLE_VARMOD_LOW` }, + }, + }, + { + name = "WEAPON_BULLPUPRIFLE_MK2", + label = TranslateCap("weapon_bullpuprifle_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CLIP_02` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CLIP_INCENDIARY` }, + { name = "ammo_armor", label = TranslateCap("component_ammo_armor"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CLIP_ARMORPIERCING` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CLIP_FMJ` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_AT_SIGHTS` }, + { name = "scope_small", label = TranslateCap("component_scope_small"), hash = `COMPONENT_AT_SCOPE_MACRO_02_MK2` }, + { name = "scope_medium", label = TranslateCap("component_scope_medium"), hash = `COMPONENT_AT_SCOPE_SMALL_MK2` }, + { name = "barrel_default", label = TranslateCap("component_barrel_default"), hash = `COMPONENT_AT_BP_BARREL_01` }, + { name = "barrel_heavy", label = TranslateCap("component_barrel_heavy"), hash = `COMPONENT_AT_BP_BARREL_02` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + { name = "muzzle_flat", label = TranslateCap("component_muzzle_flat"), hash = `COMPONENT_AT_MUZZLE_01` }, + { name = "muzzle_tactical", label = TranslateCap("component_muzzle_tactical"), hash = `COMPONENT_AT_MUZZLE_02` }, + { name = "muzzle_fat", label = TranslateCap("component_muzzle_fat"), hash = `COMPONENT_AT_MUZZLE_03` }, + { name = "muzzle_precision", label = TranslateCap("component_muzzle_precision"), hash = `COMPONENT_AT_MUZZLE_04` }, + { name = "muzzle_heavy", label = TranslateCap("component_muzzle_heavy"), hash = `COMPONENT_AT_MUZZLE_05` }, + { name = "muzzle_slanted", label = TranslateCap("component_muzzle_slanted"), hash = `COMPONENT_AT_MUZZLE_06` }, + { name = "muzzle_split", label = TranslateCap("component_muzzle_split"), hash = `COMPONENT_AT_MUZZLE_07` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP_02` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_BULLPUPRIFLE_MK2_CAMO_IND_01` }, + }, + }, + { + name = "WEAPON_CARBINERIFLE", + label = TranslateCap("weapon_carbinerifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_CARBINERIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_CARBINERIFLE_CLIP_02` }, + { name = "clip_box", label = TranslateCap("component_clip_box"), hash = `COMPONENT_CARBINERIFLE_CLIP_03` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_MEDIUM` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_CARBINERIFLE_VARMOD_LUXE` }, + }, + }, + { + name = "WEAPON_CARBINERIFLE_MK2", + label = TranslateCap("weapon_carbinerifle_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_CARBINERIFLE_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_CARBINERIFLE_MK2_CLIP_02` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_CARBINERIFLE_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_CARBINERIFLE_MK2_CLIP_INCENDIARY` }, + { name = "ammo_armor", label = TranslateCap("component_ammo_armor"), hash = `COMPONENT_CARBINERIFLE_MK2_CLIP_ARMORPIERCING` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_CARBINERIFLE_MK2_CLIP_FMJ` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_AT_SIGHTS` }, + { name = "scope_medium", label = TranslateCap("component_scope_medium"), hash = `COMPONENT_AT_SCOPE_MACRO_MK2` }, + { name = "scope_large", label = TranslateCap("component_scope_large"), hash = `COMPONENT_AT_SCOPE_MEDIUM_MK2` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + { name = "muzzle_flat", label = TranslateCap("component_muzzle_flat"), hash = `COMPONENT_AT_MUZZLE_01` }, + { name = "muzzle_tactical", label = TranslateCap("component_muzzle_tactical"), hash = `COMPONENT_AT_MUZZLE_02` }, + { name = "muzzle_fat", label = TranslateCap("component_muzzle_fat"), hash = `COMPONENT_AT_MUZZLE_03` }, + { name = "muzzle_precision", label = TranslateCap("component_muzzle_precision"), hash = `COMPONENT_AT_MUZZLE_04` }, + { name = "muzzle_heavy", label = TranslateCap("component_muzzle_heavy"), hash = `COMPONENT_AT_MUZZLE_05` }, + { name = "muzzle_slanted", label = TranslateCap("component_muzzle_slanted"), hash = `COMPONENT_AT_MUZZLE_06` }, + { name = "muzzle_split", label = TranslateCap("component_muzzle_split"), hash = `COMPONENT_AT_MUZZLE_07` }, + { name = "barrel_default", label = TranslateCap("component_barrel_default"), hash = `COMPONENT_AT_CR_BARREL_01` }, + { name = "barrel_heavy", label = TranslateCap("component_barrel_heavy"), hash = `COMPONENT_AT_CR_BARREL_02` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_CARBINERIFLE_MK2_CAMO_IND_01` }, + }, + }, + { + name = "WEAPON_COMPACTRIFLE", + label = TranslateCap("weapon_compactrifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_COMPACTRIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_COMPACTRIFLE_CLIP_02` }, + { name = "clip_drum", label = TranslateCap("component_clip_drum"), hash = `COMPONENT_COMPACTRIFLE_CLIP_03` }, + }, + }, + { + name = "WEAPON_MILITARYRIFLE", + label = TranslateCap("weapon_militaryrifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_MILITARYRIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_MILITARYRIFLE_CLIP_02` }, + { name = "ironsights", label = TranslateCap("component_ironsights"), hash = `COMPONENT_MILITARYRIFLE_SIGHT_01` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_SMALL` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + }, + }, + { + name = "WEAPON_SPECIALCARBINE", + label = TranslateCap("weapon_specialcarbine"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_SPECIALCARBINE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_SPECIALCARBINE_CLIP_02` }, + { name = "clip_drum", label = TranslateCap("component_clip_drum"), hash = `COMPONENT_SPECIALCARBINE_CLIP_03` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_MEDIUM` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_SPECIALCARBINE_VARMOD_LOWRIDER` }, + }, + }, + { + name = "WEAPON_SPECIALCARBINE_MK2", + label = TranslateCap("weapon_specialcarbine_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_SPECIALCARBINE_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_SPECIALCARBINE_MK2_CLIP_02` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_SPECIALCARBINE_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_SPECIALCARBINE_MK2_CLIP_INCENDIARY` }, + { name = "ammo_armor", label = TranslateCap("component_ammo_armor"), hash = `COMPONENT_SPECIALCARBINE_MK2_CLIP_ARMORPIERCING` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_SPECIALCARBINE_MK2_CLIP_FMJ` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_AT_SIGHTS` }, + { name = "scope_small", label = TranslateCap("component_scope_small"), hash = `COMPONENT_AT_SCOPE_MACRO_MK2` }, + { name = "scope_large", label = TranslateCap("component_scope_large"), hash = `COMPONENT_AT_SCOPE_MEDIUM_MK2` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "muzzle_flat", label = TranslateCap("component_muzzle_flat"), hash = `COMPONENT_AT_MUZZLE_01` }, + { name = "muzzle_tactical", label = TranslateCap("component_muzzle_tactical"), hash = `COMPONENT_AT_MUZZLE_02` }, + { name = "muzzle_fat", label = TranslateCap("component_muzzle_fat"), hash = `COMPONENT_AT_MUZZLE_03` }, + { name = "muzzle_precision", label = TranslateCap("component_muzzle_precision"), hash = `COMPONENT_AT_MUZZLE_04` }, + { name = "muzzle_heavy", label = TranslateCap("component_muzzle_heavy"), hash = `COMPONENT_AT_MUZZLE_05` }, + { name = "muzzle_slanted", label = TranslateCap("component_muzzle_slanted"), hash = `COMPONENT_AT_MUZZLE_06` }, + { name = "muzzle_split", label = TranslateCap("component_muzzle_split"), hash = `COMPONENT_AT_MUZZLE_07` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP_02` }, + { name = "barrel_default", label = TranslateCap("component_barrel_default"), hash = `COMPONENT_AT_SC_BARREL_01` }, + { name = "barrel_heavy", label = TranslateCap("component_barrel_heavy"), hash = `COMPONENT_AT_SC_BARREL_02` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_SPECIALCARBINE_MK2_CAMO_IND_01` }, + }, + }, + { + name = "WEAPON_HEAVYRIFLE", + label = TranslateCap("weapon_heavyrifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_HEAVYRIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_HEAVYRIFLE_CLIP_02` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_HEAVYRIFLE_SIGHT_01` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_MEDIUM` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + }, + }, + -- Sniper + { + name = "WEAPON_HEAVYSNIPER", + label = TranslateCap("weapon_heavysniper"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SNIPER` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_LARGE` }, + { name = "scope_advanced", label = TranslateCap("component_scope_advanced"), hash = `COMPONENT_AT_SCOPE_MAX` }, + }, + }, + { + name = "WEAPON_HEAVYSNIPER_MK2", + label = TranslateCap("weapon_heavysniper_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SNIPER` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_HEAVYSNIPER_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_HEAVYSNIPER_MK2_CLIP_02` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_HEAVYSNIPER_MK2_CLIP_INCENDIARY` }, + { name = "ammo_armor", label = TranslateCap("component_ammo_armor"), hash = `COMPONENT_HEAVYSNIPER_MK2_CLIP_ARMORPIERCING` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_HEAVYSNIPER_MK2_CLIP_FMJ` }, + { name = "ammo_explosive", label = TranslateCap("component_ammo_explosive"), hash = `COMPONENT_HEAVYSNIPER_MK2_CLIP_EXPLOSIVE` }, + { name = "scope_zoom", label = TranslateCap("component_scope_zoom"), hash = `COMPONENT_AT_SCOPE_LARGE_MK2` }, + { name = "scope_advanced", label = TranslateCap("component_scope_advanced"), hash = `COMPONENT_AT_SCOPE_MAX` }, + { name = "scope_nightvision", label = TranslateCap("component_scope_nightvision"), hash = `COMPONENT_AT_SCOPE_NV` }, + { name = "scope_thermal", label = TranslateCap("component_scope_thermal"), hash = `COMPONENT_AT_SCOPE_THERMAL` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_SR_SUPP_03` }, + { name = "muzzle_squared", label = TranslateCap("component_muzzle_squared"), hash = `COMPONENT_AT_MUZZLE_08` }, + { name = "muzzle_bell", label = TranslateCap("component_muzzle_bell"), hash = `COMPONENT_AT_MUZZLE_09` }, + { name = "barrel_default", label = TranslateCap("component_barrel_default"), hash = `COMPONENT_AT_SR_BARREL_01` }, + { name = "barrel_heavy", label = TranslateCap("component_barrel_heavy"), hash = `COMPONENT_AT_SR_BARREL_02` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_HEAVYSNIPER_MK2_CAMO_IND_01` }, + }, + }, + { + name = "WEAPON_MARKSMANRIFLE", + label = TranslateCap("weapon_marksmanrifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SNIPER` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_MARKSMANRIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_MARKSMANRIFLE_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_LARGE_FIXED_ZOOM` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_MARKSMANRIFLE_VARMOD_LUXE` }, + }, + }, + { + name = "WEAPON_MARKSMANRIFLE_MK2", + label = TranslateCap("weapon_marksmanrifle_mk2"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SNIPER` }, + tints = Config.MK2WeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CLIP_02` }, + { name = "ammo_tracer", label = TranslateCap("component_ammo_tracer"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CLIP_TRACER` }, + { name = "ammo_incendiary", label = TranslateCap("component_ammo_incendiary"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CLIP_INCENDIARY` }, + { name = "ammo_armor", label = TranslateCap("component_ammo_armor"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CLIP_ARMORPIERCING` }, + { name = "ammo_fmj", label = TranslateCap("component_ammo_fmj"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CLIP_FMJ` }, + { name = "scope_holo", label = TranslateCap("component_scope_holo"), hash = `COMPONENT_AT_SIGHTS` }, + { name = "scope_large", label = TranslateCap("component_scope_large"), hash = `COMPONENT_AT_SCOPE_MEDIUM_MK2` }, + { name = "scope_zoom", label = TranslateCap("component_scope_zoom"), hash = `COMPONENT_AT_SCOPE_LARGE_FIXED_ZOOM_MK2` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + { name = "muzzle_flat", label = TranslateCap("component_muzzle_flat"), hash = `COMPONENT_AT_MUZZLE_01` }, + { name = "muzzle_tactical", label = TranslateCap("component_muzzle_tactical"), hash = `COMPONENT_AT_MUZZLE_02` }, + { name = "muzzle_fat", label = TranslateCap("component_muzzle_fat"), hash = `COMPONENT_AT_MUZZLE_03` }, + { name = "muzzle_precision", label = TranslateCap("component_muzzle_precision"), hash = `COMPONENT_AT_MUZZLE_04` }, + { name = "muzzle_heavy", label = TranslateCap("component_muzzle_heavy"), hash = `COMPONENT_AT_MUZZLE_05` }, + { name = "muzzle_slanted", label = TranslateCap("component_muzzle_slanted"), hash = `COMPONENT_AT_MUZZLE_06` }, + { name = "muzzle_split", label = TranslateCap("component_muzzle_split"), hash = `COMPONENT_AT_MUZZLE_07` }, + { name = "barrel_default", label = TranslateCap("component_barrel_default"), hash = `COMPONENT_AT_MRFL_BARREL_01` }, + { name = "barrel_heavy", label = TranslateCap("component_barrel_heavy"), hash = `COMPONENT_AT_MRFL_BARREL_02` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP_02` }, + { name = "camo_finish", label = TranslateCap("component_camo_finish"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO` }, + { name = "camo_finish2", label = TranslateCap("component_camo_finish2"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_02` }, + { name = "camo_finish3", label = TranslateCap("component_camo_finish3"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_03` }, + { name = "camo_finish4", label = TranslateCap("component_camo_finish4"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_04` }, + { name = "camo_finish5", label = TranslateCap("component_camo_finish5"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_05` }, + { name = "camo_finish6", label = TranslateCap("component_camo_finish6"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_06` }, + { name = "camo_finish7", label = TranslateCap("component_camo_finish7"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_07` }, + { name = "camo_finish8", label = TranslateCap("component_camo_finish8"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_08` }, + { name = "camo_finish9", label = TranslateCap("component_camo_finish9"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_09` }, + { name = "camo_finish10", label = TranslateCap("component_camo_finish10"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_10` }, + { name = "camo_finish11", label = TranslateCap("component_camo_finish11"), hash = `COMPONENT_MARKSMANRIFLE_MK2_CAMO_IND_01` }, + }, + }, + { + name = "WEAPON_SNIPERRIFLE", + label = TranslateCap("weapon_sniperrifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SNIPER` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "scope", label = TranslateCap("component_scope"), hash = `COMPONENT_AT_SCOPE_LARGE` }, + { name = "scope_advanced", label = TranslateCap("component_scope_advanced"), hash = `COMPONENT_AT_SCOPE_MAX` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + { name = "luxary_finish", label = TranslateCap("component_luxary_finish"), hash = `COMPONENT_SNIPERRIFLE_VARMOD_LUXE` }, + }, + }, + -- Heavy / Launchers + { + name = "WEAPON_COMPACTLAUNCHER", + label = TranslateCap("weapon_compactlauncher"), + tints = Config.DefaultWeaponTints, + components = {}, + ammo = { label = TranslateCap("ammo_grenadelauncher"), hash = `AMMO_GRENADELAUNCHER` }, + }, + { name = "WEAPON_FIREWORK", label = TranslateCap("weapon_firework"), components = {}, ammo = { label = TranslateCap("ammo_firework"), hash = `AMMO_FIREWORK` } }, + { + name = "WEAPON_GRENADELAUNCHER", + label = TranslateCap("weapon_grenadelauncher"), + tints = Config.DefaultWeaponTints, + components = {}, + ammo = { label = TranslateCap("ammo_grenadelauncher"), hash = `AMMO_GRENADELAUNCHER` }, + }, + { name = "WEAPON_HOMINGLAUNCHER", label = TranslateCap("weapon_hominglauncher"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rockets"), hash = `AMMO_HOMINGLAUNCHER` } }, + { name = "WEAPON_MINIGUN", label = TranslateCap("weapon_minigun"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_MINIGUN` } }, + { name = "WEAPON_RAILGUN", label = TranslateCap("weapon_railgun"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RAILGUN` } }, + { name = "WEAPON_RPG", label = TranslateCap("weapon_rpg"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rockets"), hash = `AMMO_RPG` } }, + { name = "WEAPON_RAYMINIGUN", label = TranslateCap("weapon_rayminigun"), tints = Config.DefaultWeaponTints, components = {}, ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_MINIGUN` } }, + -- Thrown + { name = "WEAPON_BALL", label = TranslateCap("weapon_ball"), components = {}, ammo = { label = TranslateCap("ammo_ball"), hash = `AMMO_BALL` }, throwable = true }, + { name = "WEAPON_BZGAS", label = TranslateCap("weapon_bzgas"), components = {}, ammo = { label = TranslateCap("ammo_bzgas"), hash = `AMMO_BZGAS` }, throwable = true }, + { name = "WEAPON_FLARE", label = TranslateCap("weapon_flare"), components = {}, ammo = { label = TranslateCap("ammo_flare"), hash = `AMMO_FLARE` }, throwable = true }, + { name = "WEAPON_GRENADE", label = TranslateCap("weapon_grenade"), components = {}, ammo = { label = TranslateCap("ammo_grenade"), hash = `AMMO_GRENADE` }, throwable = true }, + { name = "WEAPON_PETROLCAN", label = TranslateCap("weapon_petrolcan"), components = {}, ammo = { label = TranslateCap("ammo_petrol"), hash = `AMMO_PETROLCAN` }, throwable = true }, + { name = "WEAPON_HAZARDCAN", label = TranslateCap("weapon_hazardcan"), components = {}, ammo = { label = TranslateCap("ammo_petrol"), hash = `AMMO_PETROLCAN` }, throwable = true }, + { name = "WEAPON_MOLOTOV", label = TranslateCap("weapon_molotov"), components = {}, ammo = { label = TranslateCap("ammo_molotov"), hash = `AMMO_MOLOTOV` }, throwable = true }, + { name = "WEAPON_PROXMINE", label = TranslateCap("weapon_proxmine"), components = {}, ammo = { label = TranslateCap("ammo_proxmine"), hash = `AMMO_PROXMINE` }, throwable = true }, + { name = "WEAPON_PIPEBOMB", label = TranslateCap("weapon_pipebomb"), components = {}, ammo = { label = TranslateCap("ammo_pipebomb"), hash = `AMMO_PIPEBOMB` }, throwable = true }, + { name = "WEAPON_SNOWBALL", label = TranslateCap("weapon_snowball"), components = {}, ammo = { label = TranslateCap("ammo_snowball"), hash = `AMMO_SNOWBALL` }, throwable = true }, + { name = "WEAPON_STICKYBOMB", label = TranslateCap("weapon_stickybomb"), components = {}, ammo = { label = TranslateCap("ammo_stickybomb"), hash = `AMMO_STICKYBOMB` }, throwable = true }, + { name = "WEAPON_SMOKEGRENADE", label = TranslateCap("weapon_smokegrenade"), components = {}, ammo = { label = TranslateCap("ammo_smokebomb"), hash = `AMMO_SMOKEGRENADE` }, throwable = true }, + -- Tools + { name = "WEAPON_FIREEXTINGUISHER", label = TranslateCap("weapon_fireextinguisher"), components = {}, ammo = { label = TranslateCap("ammo_charge"), hash = `AMMO_FIREEXTINGUISHER` } }, + { name = "WEAPON_DIGISCANNER", label = TranslateCap("weapon_digiscanner"), components = {} }, + { name = "GADGET_PARACHUTE", label = TranslateCap("gadget_parachute"), components = {}, throwable = true }, + { + name = "WEAPON_TACTICALRIFLE", + label = TranslateCap("weapon_tactilerifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_TACTICALRIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_TACTICALRIFLE_CLIP_02` }, + { name = "flashlight", label = TranslateCap("component_flashlight"), hash = `COMPONENT_AT_AR_FLSH_REH` }, + { name = "grip", label = TranslateCap("component_grip"), hash = `COMPONENT_AT_AR_AFGRIP` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP_02` }, + }, + }, + { + name = "WEAPON_BATTLERIFLE", + label = TranslateCap("weapon_battlerifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RIFLE` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_BATTLERIFLE_CLIP_01` }, + { name = "clip_extended", label = TranslateCap("component_clip_extended"), hash = `COMPONENT_BATTLERIFLE_CLIP_02` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_AT_AR_SUPP` }, + }, + }, + { + name = "WEAPON_SNOWLAUNCHER", + label = TranslateCap("weapon_snowlauncher"), + ammo = { label = TranslateCap("ammo_snowball"), hash = `AMMO_SNOWLAUNCHER` }, + tints = Config.DefaultWeaponTints, + components = {}, + }, + { + name = "WEAPON_HACKINGDEVICE", + label = TranslateCap("weapon_hackingdevice"), + tints = Config.DefaultWeaponTints, + components = {}, + }, + { + name = "WEAPON_PRECISIONRIFLE", + label = TranslateCap("weapon_precisionrifle"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_SNIPER` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_PRECISIONRIFLE_CLIP_01` }, + }, + }, + { name = "WEAPON_METALDETECTOR", label = TranslateCap("weapon_metaldetector"), components = {} }, + { + name = "WEAPON_PISTOLXM3", + label = TranslateCap("weapon_pistolxm3"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_PISTOL` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_PISTOLXM3_CLIP_01` }, + { name = "suppressor", label = TranslateCap("component_suppressor"), hash = `COMPONENT_PISTOLXM3_SUPP` }, + }, + }, + { name = "WEAPON_ACIDPACKAGE", label = TranslateCap("weapon_acidpackage"), components = {}, throwable = true }, + { name = "WEAPON_CANDYCANE", label = TranslateCap("weapon_candycane"), components = {} }, + { + name = "WEAPON_RAILGUNXM3", + label = TranslateCap("weapon_railgunxm3"), + ammo = { label = TranslateCap("ammo_rounds"), hash = `AMMO_RAILGUN` }, + tints = Config.DefaultWeaponTints, + components = { + { name = "clip_default", label = TranslateCap("component_clip_default"), hash = `COMPONENT_RAILGUNXM3_CLIP_01` }, + }, + }, +} diff --git a/resources/[core]/es_extended/shared/functions.lua b/resources/[core]/es_extended/shared/functions.lua new file mode 100644 index 0000000..e8fe8a7 --- /dev/null +++ b/resources/[core]/es_extended/shared/functions.lua @@ -0,0 +1,293 @@ +local Charset = {} + +for i = 48, 57 do + table.insert(Charset, string.char(i)) +end +for i = 65, 90 do + table.insert(Charset, string.char(i)) +end +for i = 97, 122 do + table.insert(Charset, string.char(i)) +end + +local weaponsByName = {} +local weaponsByHash = {} + +CreateThread(function() + for index, weapon in pairs(Config.Weapons) do + weaponsByName[weapon.name] = index + weaponsByHash[joaat(weapon.name)] = weapon + end +end) + +---@param length number +---@return string +function ESX.GetRandomString(length) + math.randomseed(GetGameTimer()) + + return length > 0 and ESX.GetRandomString(length - 1) .. Charset[math.random(1, #Charset)] or "" +end + +---@param key? string Key pair to get specific value of config +---@return unknown Returns the whole config if no key is passed, or a specific value +function ESX.GetConfig(key) + if key then + return Config[key] + end + + return Config +end + +---@param weaponName string +---@return number, table +function ESX.GetWeapon(weaponName) + weaponName = string.upper(weaponName) + + assert(weaponsByName[weaponName], "Invalid weapon name!") + + local index = weaponsByName[weaponName] + return index, Config.Weapons[index] +end + +---@param weaponHash number +---@return table +function ESX.GetWeaponFromHash(weaponHash) + weaponHash = type(weaponHash) == "string" and joaat(weaponHash) or weaponHash + + return weaponsByHash[weaponHash] +end + +---@param byHash boolean +---@return table +function ESX.GetWeaponList(byHash) + return byHash and weaponsByHash or Config.Weapons +end + +---@param weaponName string +---@return string +function ESX.GetWeaponLabel(weaponName) + weaponName = string.upper(weaponName) + + assert(weaponsByName[weaponName], "Invalid weapon name!") + + local index = weaponsByName[weaponName] + return Config.Weapons[index].label or "" +end + +---@param weaponName string +---@param weaponComponent string +---@return ESXWeaponComponent? +function ESX.GetWeaponComponent(weaponName, weaponComponent) + weaponName = string.upper(weaponName) + + assert(weaponsByName[weaponName], "Invalid weapon name!") + local weapon = Config.Weapons[weaponsByName[weaponName]] + + for _, component in ipairs(weapon.components) do + ---@cast component ESXWeaponComponent + if component.name == weaponComponent then + return component + end + end +end + +---@param table table +---@param nb? number +---@return string +function ESX.DumpTable(table, nb) + if nb == nil then + nb = 0 + end + + if type(table) == "table" then + local s = "" + for _ = 1, nb + 1, 1 do + s = s .. " " + end + + s = "{\n" + for k, v in pairs(table) do + if type(k) ~= "number" then + k = '"' .. k .. '"' + end + for _ = 1, nb, 1 do + s = s .. " " + end + s = s .. "[" .. k .. "] = " .. ESX.DumpTable(v, nb + 1) .. ",\n" + end + + for _ = 1, nb, 1 do + s = s .. " " + end + + return s .. "}" + else + return tostring(table) + end +end + +---@param value any +---@param numDecimalPlaces? number +---@return number +function ESX.Round(value, numDecimalPlaces) + return ESX.Math.Round(value, numDecimalPlaces) +end + +---@param value string +---@param ... any +---@return boolean, string? +function ESX.ValidateType(value, ...) + local types = { ... } + if #types == 0 then return true end + + local mapType = {} + for i = 1, #types, 1 do + local validateType = types[i] + assert(type(validateType) == "string", "bad argument types, only expected string") -- should never use anyhing else than string + mapType[validateType] = true + end + + local valueType = type(value) + + local matches = mapType[valueType] ~= nil + + if not matches then + local requireTypes = table.concat(types, " or ") + local errorMessage = ("bad value (%s expected, got %s)"):format(requireTypes, valueType) + + return false, errorMessage + end + + return true +end + +---@param ... any +---@return boolean +function ESX.AssertType(...) + local matches, errorMessage = ESX.ValidateType(...) + + assert(matches, errorMessage) + + return matches +end + +---@param val unknown +function ESX.IsFunctionReference(val) + local typeVal = type(val) + + return typeVal == "function" or (typeVal == "table" and type(getmetatable(val)?.__call) == "function") +end + +---@param conditionFunc function A function that is repeatedly called until it returns a truthy value or the timeout is exceeded. +---@param errorMessage? string Optional. If set, an error will be thrown with this message if the condition is not met within the timeout. If not set, no error will be thrown. +---@param timeoutMs? number Optional. The maximum time to wait (in milliseconds) for the condition to be met. Defaults to 1000ms. +---@return boolean, any: Returns success status and the returned value of the condition function. +function ESX.Await(conditionFunc, errorMessage, timeoutMs) + timeoutMs = timeoutMs or 1000 + + if timeoutMs < 0 then + error("Timeout should be a positive number.") + end + + if not ESX.IsFunctionReference(conditionFunc) then + error("Condition Function should be a function reference.") + end + + -- since errorMessage is optional, we only validate it if the user provided it. + if errorMessage then + ESX.AssertType(errorMessage, "string", "errorMessage should be a string.") + end + + local invokingResource = GetInvokingResource() + local startTimeMs = GetGameTimer() + while GetGameTimer() - startTimeMs < timeoutMs do + local result = conditionFunc() + + if result then + return true, result + end + + Wait(0) + end + + if errorMessage then + error(("[%s] -> %s"):format(invokingResource, errorMessage)) + end + + return false +end + +---@param str string +---@param allowDigits boolean? Allow numbers if necessary +---@return boolean +function ESX.IsValidLocaleString(str, allowDigits) + if not ESX.ValidateType(str, 'string') then + return false + end + + local locale = string.lower(Config.Locale) + + local defaultRanges ={ + {0x0041, 0x005A}, -- Basic Latin uppercase + {0x0061, 0x007A}, -- Basic Latin lowercase + {0x0020, 0x0020}, -- Space + {0x002D, 0x002D}, -- Dash + {0x00C0, 0x02AF} -- Latin Extended + } + + if allowDigits then + defaultRanges[#defaultRanges + 1] = {0x0030, 0x0039} -- 0-9 Numbers + end + + local localeRanges = { + ["el"] = { {0x0370, 0x03FF} }, -- Greek + ["sr"] ={ {0x0400, 0x04FF} }, -- Cyrillic + ["he"] ={ {0x05D0, 0x05EA} }, -- Hebrew letters + ["ar"] = { + {0x0620, 0x063F}, -- Arabic + {0x0641, 0x064A}, + {0x066E, 0x066F}, + {0x0671, 0x06D3}, + {0x06D5, 0x06D5}, + {0x0750, 0x077F}, + {0x08A0, 0x08BD} + }, + ["zh-cn"] ={ {0x4E00, 0x9FFF} } -- CJK + } + + local validRanges = { table.unpack(defaultRanges) } + + if localeRanges[locale] then + for i = 1, #localeRanges[locale] do + validRanges[#validRanges + 1] = localeRanges[locale][i] + end + end + + if Config.ValidCharacterSets then + for charset, enabled in pairs(Config.ValidCharacterSets) do + if enabled and charset ~= locale and localeRanges[charset] then + for i = 1, #localeRanges[charset] do + validRanges[#validRanges + 1] = localeRanges[charset][i] + end + end + end + end + + for _, code in utf8.codes(str) do + local isValid = false + + for i = 1, #validRanges do + local range = validRanges[i] + if code >= range[1] and code <= range[2] then + isValid = true + break + end + end + + if not isValid then + return false + end + end + + return true +end diff --git a/resources/[core]/es_extended/shared/main.lua b/resources/[core]/es_extended/shared/main.lua new file mode 100644 index 0000000..432cf03 --- /dev/null +++ b/resources/[core]/es_extended/shared/main.lua @@ -0,0 +1,14 @@ +ESX = {} + +exports("getSharedObject", function() + return ESX +end) + +AddEventHandler("esx:getSharedObject", function(cb) + if ESX.IsFunctionReference(cb) then + cb(ESX) + end +end) + +-- backwards compatibility (DO NOT TOUCH !) +Config.OxInventory = Config.CustomInventory == "ox" diff --git a/resources/[core]/es_extended/shared/modules/math.lua b/resources/[core]/es_extended/shared/modules/math.lua new file mode 100644 index 0000000..8967c66 --- /dev/null +++ b/resources/[core]/es_extended/shared/modules/math.lua @@ -0,0 +1,50 @@ +ESX.Math = {} + +---@param value number +---@param numDecimalPlaces? number +---@return number +function ESX.Math.Round(value, numDecimalPlaces) + if numDecimalPlaces then + local power = 10 ^ numDecimalPlaces + return math.floor((value * power) + 0.5) / power + else + return math.floor(value + 0.5) + end +end + +-- credit http://richard.warburton.it +---@param value number +---@return string +function ESX.Math.GroupDigits(value) + local left, num, right = string.match(value, "^([^%d]*%d)(%d*)(.-)$") + + return left .. (num:reverse():gsub("(%d%d%d)", "%1" .. TranslateCap("locale_digit_grouping_symbol")):reverse()) .. right +end + +---@param value string | number +---@return string | nil +function ESX.Math.Trim(value) + value = tostring(value) + return (string.gsub(value, "^%s*(.-)%s*$", "%1")) +end + +---@param minRange number +---@param maxRange number +---@return number +function ESX.Math.Random(minRange, maxRange) + math.randomseed(GetGameTimer()) + return math.random(minRange or 1, maxRange or 10) +end + +---@param origin vector +---@param target vector +---@return number +function ESX.Math.GetHeadingFromCoords(origin, target) + local dx = origin.x - target.x + local dy = origin.y - target.y + + local heading = math.deg(math.atan(dy, dx)) + 90 + + return (heading + 360) % 360 +end + diff --git a/resources/[core]/es_extended/shared/modules/table.lua b/resources/[core]/es_extended/shared/modules/table.lua new file mode 100644 index 0000000..ab4b147 --- /dev/null +++ b/resources/[core]/es_extended/shared/modules/table.lua @@ -0,0 +1,241 @@ +ESX.Table = {} + +-- nil proof alternative to #table +---@param t table +---@return number +function ESX.Table.SizeOf(t) + local count = 0 + + for _, _ in pairs(t) do + count = count + 1 + end + + return count +end + +---@param t table +---@return table +function ESX.Table.Set(t) + local set = {} + for _, v in ipairs(t) do + set[v] = true + end + return set +end + +---@param t table +---@param value any +---@return number +function ESX.Table.IndexOf(t, value) + for i = 1, #t, 1 do + if t[i] == value then + return i + end + end + + return -1 +end + +---@param t table +---@param value any +---@return number +function ESX.Table.LastIndexOf(t, value) + for i = #t, 1, -1 do + if t[i] == value then + return i + end + end + + return -1 +end + +---@param t table +---@param cb function +---@return any +function ESX.Table.Find(t, cb) + for i = 1, #t, 1 do + if cb(t[i]) then + return t[i] + end + end + + return nil +end + +---@param t table +---@param cb function +---@return number +function ESX.Table.FindIndex(t, cb) + for i = 1, #t, 1 do + if cb(t[i]) then + return i + end + end + + return -1 +end + +---@param t table +---@param cb function +---@return table +function ESX.Table.Filter(t, cb) + local newTable = {} + + for i = 1, #t, 1 do + if cb(t[i]) then + newTable[#newTable + 1] = t[i] + end + end + + return newTable +end + +---@param t table +---@param cb function +---@return table +function ESX.Table.Map(t, cb) + local newTable = {} + + for i = 1, #t, 1 do + newTable[i] = cb(t[i], i) + end + + return newTable +end + +---@param t table +---@return table +function ESX.Table.Reverse(t) + local newTable = {} + + for i = #t, 1, -1 do + table.insert(newTable, t[i]) + end + + return newTable +end + +---@param t table +---@return table +function ESX.Table.Clone(t) + if type(t) ~= "table" then + return t + end + + local meta = getmetatable(t) + local target = {} + + for k, v in pairs(t) do + if type(v) == "table" then + target[k] = ESX.Table.Clone(v) + else + target[k] = v + end + end + + setmetatable(target, meta) + + return target +end + +---@param t1 table +---@param t2 table +---@return table +function ESX.Table.Concat(t1, t2) + local t3 = ESX.Table.Clone(t1) + + for i = 1, #t2, 1 do + table.insert(t3, t2[i]) + end + + return t3 +end + +---@param t table +---@param sep string +---@return string +function ESX.Table.Join(t, sep) + local str = "" + + for i = 1, #t, 1 do + if i > 1 then + str = str .. (sep or ",") + end + + str = str .. t[i] + end + + return str +end + +-- Credits: https://github.com/JonasDev99/qb-garages/blob/b0335d67cb72a6b9ac60f62a87fb3946f5c2f33d/server/main.lua#L5 +---@param tab table +---@param val any +---@return boolean +function ESX.Table.TableContains(tab, val) + if type(val) == "table" then + for _, value in pairs(tab) do + if ESX.Table.TableContains(val, value) then + return true + end + end + return false + else + for _, value in pairs(tab) do + if value == val then + return true + end + end + end + return false +end + +-- Credit: https://stackoverflow.com/a/15706820 +-- Description: sort function for pairs +---@param t table +---@param order function +---@return function +function ESX.Table.Sort(t, order) + -- collect the keys + local keys = {} + + for k, _ in pairs(t) do + keys[#keys + 1] = k + end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a, b) + return order(t, a, b) + end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end + +---@param t table +---@return Array +function ESX.Table.ToArray(t) + local array = {} + for _, v in pairs(t) do + array[#array + 1] = v + end + return array +end + +---@param t table +---@return table +function ESX.Table.Wipe(t) + return table.wipe(t) +end \ No newline at end of file diff --git a/resources/[core]/es_extended/shared/modules/timeout.lua b/resources/[core]/es_extended/shared/modules/timeout.lua new file mode 100644 index 0000000..b0590d5 --- /dev/null +++ b/resources/[core]/es_extended/shared/modules/timeout.lua @@ -0,0 +1,28 @@ +local TimeoutCount = 0 +local CancelledTimeouts = {} + +---@param msec number +---@param cb function +---@return number +ESX.SetTimeout = function(msec, cb) + local id = TimeoutCount + 1 + + SetTimeout(msec, function() + if CancelledTimeouts[id] then + CancelledTimeouts[id] = nil + return + end + + cb() + end) + + TimeoutCount = id + + return id +end + +---@param id number +---@return nil +ESX.ClearTimeout = function(id) + CancelledTimeouts[id] = true +end diff --git a/resources/[core]/esx_chat_theme/LICENSE b/resources/[core]/esx_chat_theme/LICENSE new file mode 100644 index 0000000..2aa46e2 --- /dev/null +++ b/resources/[core]/esx_chat_theme/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + esx_clotheshop + Copyright (C) 2015-2023 Jérémie N'gadi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + esx_clotheshop Copyright (C) 2015-2023 Jérémie N'gadi + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/resources/[core]/esx_chat_theme/README.md b/resources/[core]/esx_chat_theme/README.md new file mode 100644 index 0000000..2e0e309 --- /dev/null +++ b/resources/[core]/esx_chat_theme/README.md @@ -0,0 +1,15 @@ +

[ESX] Chat Theme

Discord - Documentation + +A ESX-Based Chat-theme for your server + +# License + +esx_chat_theme - ESX Chat Theme + +Copyright (C) 2024 Jérémie N'gadi + +This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version. + +This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details. + +You should have received a copy Of the GNU General Public License along with this program. If Not, see http://www.gnu.org/licenses/. diff --git a/resources/[core]/esx_chat_theme/fxmanifest.lua b/resources/[core]/esx_chat_theme/fxmanifest.lua new file mode 100644 index 0000000..08b3d3d --- /dev/null +++ b/resources/[core]/esx_chat_theme/fxmanifest.lua @@ -0,0 +1,17 @@ +version '1.13.5' +author 'ESX-Framework' +description 'A ESX Stylised theme for the chat resource.' + +file 'style.css' +file 'shadow.js' + +chat_theme 'esx' { + styleSheet = 'style.css', + script = 'shadow.js', + msgTemplates = { + default = '{0}{1}' + } +} + +game 'common' +fx_version 'adamant' diff --git a/resources/[core]/esx_chat_theme/shadow.js b/resources/[core]/esx_chat_theme/shadow.js new file mode 100644 index 0000000..6393b2d --- /dev/null +++ b/resources/[core]/esx_chat_theme/shadow.js @@ -0,0 +1,74 @@ +(function() { +var Filters = {} + +var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); +svg.setAttribute("style", "display:block;width:0px;height:0px"); +var defs = document.createElementNS("http://www.w3.org/2000/svg", "defs"); + +var blurFilter = document.createElementNS("http://www.w3.org/2000/svg", "filter"); +blurFilter.setAttribute("id", "svgBlurFilter"); +var feGaussianFilter = document.createElementNS("http://www.w3.org/2000/svg", "feGaussianBlur"); +feGaussianFilter.setAttribute("stdDeviation", "0 0"); +blurFilter.appendChild(feGaussianFilter); +defs.appendChild(blurFilter); +Filters._svgBlurFilter = feGaussianFilter; + +// Drop Shadow Filter +var dropShadowFilter = document.createElementNS("http://www.w3.org/2000/svg", "filter"); +dropShadowFilter.setAttribute("id", "svgDropShadowFilter"); +var feGaussianFilter = document.createElementNS("http://www.w3.org/2000/svg", "feGaussianBlur"); +feGaussianFilter.setAttribute("in", "SourceAlpha"); +feGaussianFilter.setAttribute("stdDeviation", "3"); +dropShadowFilter.appendChild(feGaussianFilter); +Filters._svgDropshadowFilterBlur = feGaussianFilter; + +var feOffset = document.createElementNS("http://www.w3.org/2000/svg", "feOffset"); +feOffset.setAttribute("dx", "0"); +feOffset.setAttribute("dy", "0"); +feOffset.setAttribute("result", "offsetblur"); +dropShadowFilter.appendChild(feOffset); +Filters._svgDropshadowFilterOffset = feOffset; + +var feFlood = document.createElementNS("http://www.w3.org/2000/svg", "feFlood"); +feFlood.setAttribute("flood-color", "rgba(0,0,0,1)"); +dropShadowFilter.appendChild(feFlood); +Filters._svgDropshadowFilterFlood = feFlood; + +var feComposite = document.createElementNS("http://www.w3.org/2000/svg", "feComposite"); +feComposite.setAttribute("in2", "offsetblur"); +feComposite.setAttribute("operator", "in"); +dropShadowFilter.appendChild(feComposite); +var feComposite = document.createElementNS("http://www.w3.org/2000/svg", "feComposite"); +feComposite.setAttribute("in2", "SourceAlpha"); +feComposite.setAttribute("operator", "out"); +feComposite.setAttribute("result", "outer"); +dropShadowFilter.appendChild(feComposite); + +var feMerge = document.createElementNS("http://www.w3.org/2000/svg", "feMerge"); +var feMergeNode = document.createElementNS("http://www.w3.org/2000/svg", "feMergeNode"); +feMerge.appendChild(feMergeNode); +var feMergeNode = document.createElementNS("http://www.w3.org/2000/svg", "feMergeNode"); +feMerge.appendChild(feMergeNode); +Filters._svgDropshadowMergeNode = feMergeNode; +dropShadowFilter.appendChild(feMerge); +defs.appendChild(dropShadowFilter); +svg.appendChild(defs); +document.documentElement.appendChild(svg); + +const blurScale = 4; +const scale = (document.body.clientWidth / 1280); + +Filters._svgDropshadowFilterBlur.setAttribute("stdDeviation", + 1 * blurScale + " " + + 1 * blurScale +); +Filters._svgDropshadowFilterOffset.setAttribute("dx", + String(Math.cos(45 * Math.PI / 180) * 1 * scale)); +Filters._svgDropshadowFilterOffset.setAttribute("dy", + String(Math.sin(45 * Math.PI / 180) * 1 * scale)); +Filters._svgDropshadowFilterFlood.setAttribute("flood-color", + 'rgba(0, 0, 0, 1)'); +Filters._svgDropshadowMergeNode.setAttribute("in", + "SourceGraphic"); + +})(); \ No newline at end of file diff --git a/resources/[core]/esx_chat_theme/style.css b/resources/[core]/esx_chat_theme/style.css new file mode 100644 index 0000000..844d720 --- /dev/null +++ b/resources/[core]/esx_chat_theme/style.css @@ -0,0 +1,103 @@ +* { + font-family: inherit; +} + +.chat-window { + background: inherit !important; +} + +@font-face { + font-family: 'Font2'; + src: url(https://runtime.fivem.net/temp/ChaletLondonNineteenSixty.otf?a); +} + +@font-face { + font-family: 'Font2_cond'; + src: url(https://runtime.fivem.net/temp/chaletcomprime-colognesixty-webfont.ttf?a); +} + +.msg { + font-family: Font2, sans-serif; + color: #ffffff; + + font-size: calc(1.7vh); /* 13px in 720p, calc'd by width */ + filter: url(#svgDropShadowFilter); + + line-height: calc(2.7vh * 1.2); + + margin-bottom: 0; +} + +.chat-messages { + margin: 0; + height: 100%; +} + +.msg > span > span > b { + font-family: Font2_cond, sans-serif; + font-weight: normal; + + vertical-align: baseline; + padding-right: 11px; + + line-height: calc(2.7vh * 1.2); + + font-size: calc(2.4vh); +} + +.msg > span > span > span { + vertical-align: baseline; +} + +.msg i:first-of-type { + font-style: normal; + color: #c0c0c0; +} + +.chat-input { + background: inherit !important; + height: auto; + + font-family: Font2, sans-serif; +} + +.chat-input > div { + background-color: rgba(30, 30, 30, 0.7) !important; + border: calc(0.24vh / 2) solid #fb9c04ce; + outline: calc(0.24vh / 2) solid #fb9c04ce; /* to replace margin-background */ + padding: calc(0.2vh / 2); + border-radius: 5px; + filter: url(#svgDropShadowFilter); +} + +.chat-input .prefix { + margin: 0; + margin-left: 0.7%; + margin-right: 0.7%; + margin-top: -0.1%; + line-height: 2.8vh; +} + +.chat-input .prefix.any { + opacity: 0.8; +} + +.chat-input .prefix.any:before { + content: '['; + color: #fb9b04; +} + +.chat-input .prefix.any:after { + content: ']'; + color: #fb9b04; + margin-right: 1%; +} + +.suggestions { + background: transparent; +} + +textarea { + background: transparent; + padding: 0.5vh; +} \ No newline at end of file diff --git a/resources/[core]/esx_context/LICENSE b/resources/[core]/esx_context/LICENSE new file mode 100644 index 0000000..dae70ee --- /dev/null +++ b/resources/[core]/esx_context/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + esx_context + Copyright (C) 2022-2024 ESX Framework + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + esx_context Copyright (C) 2022-2024 ESX Framework + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[core]/esx_context/README.md b/resources/[core]/esx_context/README.md new file mode 100644 index 0000000..92a18fc --- /dev/null +++ b/resources/[core]/esx_context/README.md @@ -0,0 +1,15 @@ +

[ESX] Context

Discord - Website - Documentation + +A elegant, easy to use Context Menu system to make User Interactions clean and hassle free + +# Legal + +esx_context + +Copyright (C) 2022-2024 ESX Framework + +This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version. + +This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details. + +You should have received a copy Of the GNU General Public License along with this program. If Not, see http://www.gnu.org/licenses/. diff --git a/resources/[core]/esx_context/config.lua b/resources/[core]/esx_context/config.lua new file mode 100644 index 0000000..5830130 --- /dev/null +++ b/resources/[core]/esx_context/config.lua @@ -0,0 +1 @@ +PREVIEW_KEYBIND = "LMENU" diff --git a/resources/[core]/esx_context/fxmanifest.lua b/resources/[core]/esx_context/fxmanifest.lua new file mode 100644 index 0000000..05dbd61 --- /dev/null +++ b/resources/[core]/esx_context/fxmanifest.lua @@ -0,0 +1,24 @@ +fx_version 'bodacious' + +game 'gta5' +author 'ESX-Framework & Brayden' +description 'A simplistic context menu for ESX.' +lua54 'yes' +version '1.13.5' + +ui_page 'index.html' + +shared_script '@es_extended/imports.lua' + +client_scripts { + 'config.lua', + 'main.lua', +} + +files { + 'index.html' +} + +dependencies { + 'es_extended' +} diff --git a/resources/[core]/esx_context/index.html b/resources/[core]/esx_context/index.html new file mode 100644 index 0000000..9e40e85 --- /dev/null +++ b/resources/[core]/esx_context/index.html @@ -0,0 +1,452 @@ + + + + + + + + + + ESX Context HUD + + + + + +

+
+ +
+ Unselectable Item + Testing, testing a description here. +
+
+
+ +
+ Disabled Item + Testing, testing a description here. +
+
+
+ +
+ Item + Testing, testing a description here. Generic words to force overflow. +
+
+
+ + + + diff --git a/resources/[core]/esx_context/main.lua b/resources/[core]/esx_context/main.lua new file mode 100644 index 0000000..4b39260 --- /dev/null +++ b/resources/[core]/esx_context/main.lua @@ -0,0 +1,264 @@ +local activeMenu +local Debug = ESX.GetConfig().EnableDebug + +-- Global functions +-- [ Post | Open | Closed ] + +function Post(fn, ...) + SendNUIMessage({ + func = fn, + args = { ... }, + }) +end + +function Open(position, eles, onSelect, onClose, canClose) + local canCloseMenu = canClose == nil and true or canClose + activeMenu = { + position = position, + eles = eles, + canClose = canCloseMenu, + onSelect = onSelect, + onClose = onClose, + } + + LocalPlayer.state:set("context:active", true) + + Post("Open", eles, position) +end + +function Closed() + SetNuiFocus(false, false) + + local menu = activeMenu + local cb = menu.onClose + + activeMenu = nil + + LocalPlayer.state:set("context:active", false) + + if cb then + cb(menu) + end +end + +-- Exports +-- [ Preview | Open | Close ] + +exports("Preview", Open) + +exports("Open", function(...) + Open(...) + SetNuiFocus(true, true) +end) + +exports("Close", function() + if not activeMenu then + return + end + + Post("Closed") + + Closed() +end) + +exports("Refresh", function(eles, position) + if not activeMenu then + return + end + + activeMenu.eles = eles or activeMenu.eles + activeMenu.position = position or activeMenu.position + + Post("Open", activeMenu.eles, activeMenu.position) +end) + +-- NUI Callbacks +-- [ closed | selected | changed ] + +RegisterNUICallback("closed", function(_, cb) + if not activeMenu or (activeMenu and not activeMenu.canClose) then + return cb(false) + end + cb(true) + Closed() +end) + +RegisterNUICallback("selected", function(data, cb) + if not activeMenu or not activeMenu.onSelect or not data.index then + return + end + + local index = tonumber(data.index) + local ele = activeMenu.eles[index] + + if not ele or ele.input then + return + end + + activeMenu:onSelect(ele) + if cb then + cb("ok") + end +end) + +RegisterNUICallback("changed", function(data, cb) + if not activeMenu or not data.index or not data.value then + return + end + + local index = tonumber(data.index) + local ele = activeMenu.eles[index] + + if not ele or not ele.input then + return + end + + if ele.inputType == "number" then + ele.inputValue = tonumber(data.value) + + if ele.inputMin then + ele.inputValue = math.max(ele.inputMin, ele.inputValue) + end + + if ele.inputMax then + ele.inputValue = math.min(ele.inputMax, ele.inputValue) + end + elseif ele.inputType == "text" then + ele.inputValue = data.value + elseif ele.inputType == "radio" then + ele.inputValue = data.value + end + if cb then + cb("ok") + end +end) + +-- Keybind + +local function focusPreview() + if not activeMenu or not activeMenu.onSelect then + return + end + + SetNuiFocus(true, true) +end + +if PREVIEW_KEYBIND then + RegisterCommand("previewContext", focusPreview, false) + + RegisterKeyMapping("previewContext", "Preview Active Context", "keyboard", PREVIEW_KEYBIND) +end + +exports("focusPreview", focusPreview) + +-- Debug/Test +-- Commands: +-- [ ctx:preview | ctx:open | ctx:close | ctx:form ] + +if Debug then + local position = "right" + + local eles = { + { + unselectable = true, + icon = "fas fa-info-circle", + title = "Unselectable Item (Header/Label?)", + }, + { + icon = "fas fa-check", + title = "Item A", + description = "Some description here. Add some words to make the text overflow.", + }, + { + disabled = true, + icon = "fas fa-times", + title = "Disabled Item", + description = "Some description here. Add some words to make the text overflow.", + }, + { + icon = "fas fa-check", + title = "Item B", + description = "Some description here. Add some words to make the text overflow.", + }, + } + + local function onSelect(menu, ele) + print("Ele selected", ele.title) + + if ele.name == "close" then + exports["esx_context"]:Close() + end + + if ele.name ~= "submit" then + return + end + + for _, element in ipairs(menu.eles) do + if element.input then + print(element.name, element.inputType, element.inputValue) + end + end + + exports["esx_context"]:Close() + end + + local function onClose() + print("Menu closed.") + end + + RegisterCommand("ctx:preview", function() + exports["esx_context"]:Preview(position, eles) + end, false) + + RegisterCommand("ctx:open", function() + exports["esx_context"]:Open(position, eles, onSelect, onClose) + end, false) + + RegisterCommand("ctx:close", function() + exports["esx_context"]:Close() + end, false) + + RegisterCommand("ctx:form", function() + local formMenu = { + { + unselectable = true, + icon = "fas fa-info-circle", + title = "Unselectable Item (Header/Label?)", + }, + { + icon = "", + title = "Input Text", + input = true, + inputType = "text", + inputPlaceholder = "Placeholder...", + name = "firstname", + }, + { + icon = "", + title = "Input Text", + input = true, + inputType = "text", + inputPlaceholder = "Placeholder...", + name = "lastname", + }, + { + icon = "", + title = "Input Number", + input = true, + inputType = "number", + inputPlaceholder = "Placeholder...", + inputValue = 0, + inputMin = 0, + inputMax = 50, + name = "age", + }, + { + icon = "fas fa-check", + title = "Submit", + name = "submit", + }, + } + + exports["esx_context"]:Open(position, formMenu, onSelect, onClose) + end, false) +end diff --git a/resources/[core]/esx_identity/.gitignore b/resources/[core]/esx_identity/.gitignore new file mode 100644 index 0000000..234f2f1 --- /dev/null +++ b/resources/[core]/esx_identity/.gitignore @@ -0,0 +1,22 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/resources/[core]/esx_identity/LICENSE b/resources/[core]/esx_identity/LICENSE new file mode 100644 index 0000000..e57012a --- /dev/null +++ b/resources/[core]/esx_identity/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + esx_identity + Copyright (C) 2015-2024 Jérémie N'gadi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + esx_identity Copyright (C) 2015-2024 Jérémie N'gadi + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[core]/esx_identity/README.md b/resources/[core]/esx_identity/README.md new file mode 100644 index 0000000..4e080d4 --- /dev/null +++ b/resources/[core]/esx_identity/README.md @@ -0,0 +1,30 @@ +

[ESX] Identity

Discord - Documentation + +A Core Resource that Allows the player to Pick their characters, Name, Gender, Height and Date-of-birth. + +![Preview](./preview.png) + +# Infomation + +## Requirements + +[esx_skin](./../esx_skin/README.md) + +## Commands + +``` +/char +/chardel +``` + +## Legal + +esx_identity - Make your Character a Person! + +Copyright (C) 2015-2024 Jérémie N'gadi + +This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version. + +This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details. + +You should have received a copy Of the GNU General Public License along with this program. If Not, see . diff --git a/resources/[core]/esx_identity/client/main.lua b/resources/[core]/esx_identity/client/main.lua new file mode 100644 index 0000000..8108a00 --- /dev/null +++ b/resources/[core]/esx_identity/client/main.lua @@ -0,0 +1,75 @@ +local loadingScreenFinished = false +local ready = false +local guiEnabled = false +local timecycleModifier = "hud_def_blur" + +ESX.SecureNetEvent("esx_identity:alreadyRegistered", function() + while not loadingScreenFinished do + Wait(100) + end + TriggerEvent("esx_skin:playerRegistered") +end) + +ESX.SecureNetEvent("esx_identity:setPlayerData", function(data) + SetTimeout(1, function() + ESX.SetPlayerData("name", ("%s %s"):format(data.firstName, data.lastName)) + ESX.SetPlayerData("firstName", data.firstName) + ESX.SetPlayerData("lastName", data.lastName) + ESX.SetPlayerData("dateofbirth", data.dateOfBirth) + ESX.SetPlayerData("sex", data.sex) + ESX.SetPlayerData("height", data.height) + end) +end) + +AddEventHandler("esx:loadingScreenOff", function() + loadingScreenFinished = true +end) + +RegisterNUICallback("ready", function(_, cb) + ready = true + cb(1) +end) + +function setGuiState(state) + SetNuiFocus(state, state) + guiEnabled = state + + if state then + SetTimecycleModifier(timecycleModifier) + else + ClearTimecycleModifier() + end + + SendNUIMessage({ type = "enableui", enable = state }) +end + +RegisterNetEvent("esx_identity:showRegisterIdentity", function() + TriggerEvent("esx_skin:resetFirstSpawn") + while not (ready and loadingScreenFinished) do + print("Waiting for esx_identity NUI..") + Wait(100) + end + if not ESX.PlayerData.dead then + setGuiState(true) + end +end) + +RegisterNUICallback("register", function(data, cb) + if not guiEnabled then + return + end + + ESX.TriggerServerCallback("esx_identity:registerIdentity", function(callback) + if not callback then + return + end + + ESX.ShowNotification(TranslateCap("thank_you_for_registering")) + setGuiState(false) + + if not ESX.GetConfig().Multichar then + TriggerEvent("esx_skin:playerRegistered") + end + end, data) + cb(1) +end) diff --git a/resources/[core]/esx_identity/config.lua b/resources/[core]/esx_identity/config.lua new file mode 100644 index 0000000..3da197d --- /dev/null +++ b/resources/[core]/esx_identity/config.lua @@ -0,0 +1,19 @@ +Config = {} +Config.Locale = GetConvar("esx:locale", "en") + +-- [Config.EnableCommands] +-- Enables Commands Such As /char and /chardel +Config.EnableCommands = ESX.GetConfig().EnableDebug + +-- These values are for the date format in the registration menu +-- Choices: DD/MM/YYYY | MM/DD/YYYY | YYYY/MM/DD +Config.DateFormat = "DD/MM/YYYY" + +-- These values are for the second input validation in server/main.lua +Config.MaxNameLength = 20 -- Max Name Length. +Config.MinHeight = 120 -- 120 cm lowest height +Config.MaxHeight = 220 -- 220 cm max height. +Config.MaxAge = 100 -- 100 years old is the oldest you can be. + +Config.FullCharDelete = true -- Delete all reference to character. +Config.EnableDebugging = ESX.GetConfig().EnableDebug -- prints for debugging :) diff --git a/resources/[core]/esx_identity/esx_identity.sql b/resources/[core]/esx_identity/esx_identity.sql new file mode 100644 index 0000000..15f55f6 --- /dev/null +++ b/resources/[core]/esx_identity/esx_identity.sql @@ -0,0 +1,7 @@ +ALTER TABLE `users` + ADD COLUMN `firstname` VARCHAR(16) NULL DEFAULT NULL, + ADD COLUMN `lastname` VARCHAR(16) NULL DEFAULT NULL, + ADD COLUMN `dateofbirth` VARCHAR(10) NULL DEFAULT NULL, + ADD COLUMN `sex` VARCHAR(1) NULL DEFAULT NULL, + ADD COLUMN `height` INT NULL DEFAULT NULL +; \ No newline at end of file diff --git a/resources/[core]/esx_identity/fxmanifest.lua b/resources/[core]/esx_identity/fxmanifest.lua new file mode 100644 index 0000000..b993b0a --- /dev/null +++ b/resources/[core]/esx_identity/fxmanifest.lua @@ -0,0 +1,33 @@ +fx_version 'adamant' + +game 'gta5' +description 'Allows the player to Pick their characters: Name, Gender, Height and Date-of-birth.' +lua54 'yes' +version '1.13.5' + +shared_scripts { + '@es_extended/imports.lua', + '@es_extended/locale.lua', +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'locales/*.lua', + 'config.lua', + 'server/main.lua' +} + +client_scripts { + 'locales/*.lua', + 'config.lua', + 'client/main.lua' +} + +files ({ + 'web/dist/assets/**', + 'web/dist/**', +}) + +ui_page 'web/dist/index.html' + +dependency 'es_extended' diff --git a/resources/[core]/esx_identity/locales/cs.lua b/resources/[core]/esx_identity/locales/cs.lua new file mode 100644 index 0000000..1482b15 --- /dev/null +++ b/resources/[core]/esx_identity/locales/cs.lua @@ -0,0 +1,11 @@ +return { + ["show_registration"] = "zobrazit registracni menu", + ["show_active_character"] = "zobrazit aktivni postavy", + ["delete_character"] = "smazat svou stavajici postavu a vytvorit novou", + ["deleted_character"] = "vase postava byla smazana.", + ["not_registered"] = "nemas zaregistrovanou postavu.", + ["active_character"] = "aktivni postava: %s %s", + ["already_registered"] = "jiz mas zaregistrovanou postavu.", + ["failed_identity"] = "nastaveni vasi postavy selhalo, zkus to prosim znovu pozdeji nebo kontaktuj majitele serveru!", + ["create_a_character"] = "aby jsi mohl/a hrat, tak se musis registrovat.", +} diff --git a/resources/[core]/esx_identity/locales/da.lua b/resources/[core]/esx_identity/locales/da.lua new file mode 100644 index 0000000..f5c0c1d --- /dev/null +++ b/resources/[core]/esx_identity/locales/da.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Vis aktiv karakter", + ["active_character"] = "Aktiv karakter: %s", + ["error_active_character"] = "Der opstod en fejl under indhentning af dine data.", + ["delete_character"] = "Slet din nuværende karakter.", + ["deleted_character"] = "Karakter slettet", + ["error_delete_character"] = "Der opstod et problem med at slette din karakter.", + ["thank_you_for_registering"] = "Registreringen lykkedes. God fornøjelse!", + ["debug_xPlayer_get_first_name"] = "Returnerer dit fornavn", + ["debug_xPlayer_get_last_name"] = "Returnerer dit efternavn", + ["debug_xPlayer_get_full_name"] = "Returnerer dit fulde navn", + ["debug_xPlayer_get_sex"] = "Returnerer dit køn", + ["debug_xPlayer_get_dob"] = "Returnerer din fødselsdato", + ["debug_xPlayer_get_height"] = "Giver din højde tilbage", + ["error_debug_xPlayer_get_first_name"] = "Der opstod et problem med at få dit fornavn.", + ["error_debug_xPlayer_get_last_name"] = "Der opstod et problem med at få dit efternavn.", + ["error_debug_xPlayer_get_full_name"] = "Der opstod et problem under indhentning af dit fulde navn.", + ["error_debug_xPlayer_get_sex"] = "Der var et problem med at få dit sex.", + ["error_debug_xPlayer_get_dob"] = "Der var et problem med at få din fødselsdato.", + ["error_debug_xPlayer_get_height"] = "Der var et problem med at få din højde.", + ["return_debug_xPlayer_get_first_name"] = "Fornavn: %s", + ["return_debug_xPlayer_get_last_name"] = "Efternavn: %s", + ["return_debug_xPlayer_get_full_name"] = "Fulde Navn: %s", + ["return_debug_xPlayer_get_sex"] = "Køn: %s", + ["return_debug_xPlayer_get_dob"] = "Fødselsdato: %s", + ["return_debug_xPlayer_get_height"] = "Højde: %s Tommer", + ["data_incorrect"] = "Ugyldige data. Prøv venligst igen.", + ["invalid_format"] = "Ugyldigt dataformat. Prøv venligst igen.", + ["no_identifier"] = "[ESX Identitet]\nDer var et problem under indlæsning af din karakter!\nFejlkode: identifikator mangler\n\nDette skyldes, at din identifikator mangler. Venligst vend tilbage senere eller rapporter dette problem til serverejeren.", + ["missing_identity"] = "[ESX Identitet]\nDer var et problem med at indlæse din karakter!\nFejlkode: identitet mangler\n\nDet ser ud til, at din identitet mangler, prøv at oprette forbindelse igen.", + ["deleted_identity"] = "Tegn slettet. Tilmeld dig igen for at oprette en ny karakter.", + ["already_registered"] = "Du har allerede tilmeldt dig.", + ["invalid_firstname_format"] = "Ugyldigt format (fornavn): Prøv venligst igen.", + ["invalid_lastname_format"] = "Ugyldigt format (efternavn): Prøv igen.", + ["invalid_dob_format"] = "Ugyldigt format (DOB): Prøv venligst igen.", + ["invalid_sex_format"] = "Ugyldigt format (køn): Prøv venligst igen.", + ["invalid_height_format"] = "Ugyldigt format (højde): Prøv venligst igen.", +} diff --git a/resources/[core]/esx_identity/locales/de.lua b/resources/[core]/esx_identity/locales/de.lua new file mode 100644 index 0000000..b2285b0 --- /dev/null +++ b/resources/[core]/esx_identity/locales/de.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Aktiven Charakter anzeigen", + ["active_character"] = "Aktiver Charakter: %s", + ["error_active_character"] = "Beim Abrufen deiner Daten ist ein Fehler aufgetreten", + ["delete_character"] = "Lösche deinen aktuellen Charakter.", + ["deleted_character"] = "Charakter gelöscht", + ["error_delete_character"] = "Es gab ein Problem beim löschen deines Charakters.", + ["thank_you_for_registering"] = "Registrierung erfolgreich.", + ["debug_xPlayer_get_first_name"] = "Gibt deinen Vornamen zurück", + ["debug_xPlayer_get_last_name"] = "Gibt deinen Nachnamen zurück", + ["debug_xPlayer_get_full_name"] = "Gibt deinen vollständigen Namen zurück", + ["debug_xPlayer_get_sex"] = "Gibt dein Geschlecht zurück", + ["debug_xPlayer_get_dob"] = "Gibt dein Geburtsdatum zurück", + ["debug_xPlayer_get_height"] = "Gibt deine Körpergröße zurück", + ["error_debug_xPlayer_get_first_name"] = "Es gab ein Problem beim Abrufen deines Vornamens.", + ["error_debug_xPlayer_get_last_name"] = "Es gab ein Problem beim Abrufen deines Nachnamens.", + ["error_debug_xPlayer_get_full_name"] = "Es gab ein Problem beim Abrufen deines vollständigen Namens.", + ["error_debug_xPlayer_get_sex"] = "Es gab ein Problem beim Abrufen deines Geschlechts.", + ["error_debug_xPlayer_get_dob"] = "Es gab ein Problem beim Abrufen deines Geburtsdatums.", + ["error_debug_xPlayer_get_height"] = "Es gab ein Problem beim Abrufen deiner Körpergröße.", + ["return_debug_xPlayer_get_first_name"] = "Vorname: %s", + ["return_debug_xPlayer_get_last_name"] = "Nachname: %s", + ["return_debug_xPlayer_get_full_name"] = "Name: %s", + ["return_debug_xPlayer_get_sex"] = "Geschlecht: %s", + ["return_debug_xPlayer_get_dob"] = "Geburtsdatum: %s", + ["return_debug_xPlayer_get_height"] = "Größe: %s cm", + ["data_incorrect"] = "Ungültige Daten, bitte versuche es erneut", + ["invalid_format"] = "Ungültiges Datenformat, bitte versuche es erneut.", + ["no_identifier"] = "Es gab ein Problem beim Laden deines Charakters!\nFehlercode: identifier-missing\n\nDies wird dadurch verursacht, dass deine R* ID fehlt. Bitte versuche es erneut oder melde dieses Problem dem Support.", + ["missing_identity"] = "Es gab ein Problem beim Laden deines Charakters!\nFehlercode: identifier-missing\n\nDies wird dadurch verursacht, dass deine R* ID fehlt. Bitte versuche es erneut oder melde dieses Problem dem Support.", + ["deleted_identity"] = "Charakter gelöscht. Bitte verbinde dich erneut, um einen neuen Charakter zu erstellen.", + ["already_registered"] = "Du hast dich bereits registriert.", + ["invalid_firstname_format"] = "Ungültiges Format (Vorname): Bitte versuche es erneut.", + ["invalid_lastname_format"] = "Ungültiges Format (Nachname): Bitte versuche es erneut.", + ["invalid_dob_format"] = "Ungültiges Format (Geburtstag): Bitte versuche es erneut.", + ["invalid_sex_format"] = "Ungültiges Format (Geschlecht): Bitte versuche es erneut.", + ["invalid_height_format"] = "Ungültiges Format (Körpergröße): Bitte versuche es erneut.", +} diff --git a/resources/[core]/esx_identity/locales/en.lua b/resources/[core]/esx_identity/locales/en.lua new file mode 100644 index 0000000..fa4737e --- /dev/null +++ b/resources/[core]/esx_identity/locales/en.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Show Active Character", + ["active_character"] = "Active Character: %s", + ["error_active_character"] = "There was an error obtaining your data.", + ["delete_character"] = "Delete Your Current Character.", + ["deleted_character"] = "Character Deleted", + ["error_delete_character"] = "There was a problem deleting your character.", + ["thank_you_for_registering"] = "Registration Successful. Enjoy!", + ["debug_xPlayer_get_first_name"] = "Returns Your First Name", + ["debug_xPlayer_get_last_name"] = "Returns Your Last Name", + ["debug_xPlayer_get_full_name"] = "Returns Your Full Name", + ["debug_xPlayer_get_sex"] = "Returns Your Sex", + ["debug_xPlayer_get_dob"] = "Returns Your DOB", + ["debug_xPlayer_get_height"] = "Returns Your Height", + ["error_debug_xPlayer_get_first_name"] = "There was an issue while obtaining your first name.", + ["error_debug_xPlayer_get_last_name"] = "There was an issue while obtaining your last name.", + ["error_debug_xPlayer_get_full_name"] = "There was an issue while obtaining your full name.", + ["error_debug_xPlayer_get_sex"] = "There was an issue while obtaining your sex.", + ["error_debug_xPlayer_get_dob"] = "There was an issue while obtaining your date of birth.", + ["error_debug_xPlayer_get_height"] = "There was an issue while obtaining your height.", + ["return_debug_xPlayer_get_first_name"] = "First Name: %s", + ["return_debug_xPlayer_get_last_name"] = "Last Name: %s", + ["return_debug_xPlayer_get_full_name"] = "Name: %s", + ["return_debug_xPlayer_get_sex"] = "Sex: %s", + ["return_debug_xPlayer_get_dob"] = "DOB: %s", + ["return_debug_xPlayer_get_height"] = "Height: %s Inches", + ["data_incorrect"] = "Invalid Data, Please try again.", + ["invalid_format"] = "Invalid Data Format, Please try again.", + ["no_identifier"] = "[ESX Identity]\nThere was an issue while loading your character!\nError Code: identifier-missing\n\nThis is caused by your identifier being missing. Please come back later or report this problem to the Server Owner.", + ["missing_identity"] = "[ESX Identity]\nThere was an issue loading your character!\nError Code: identity-missing\n\nIt seems like your identity is missing, try connecting again.", + ["deleted_identity"] = "Character deleted. Please rejoin to create a new character.", + ["already_registered"] = "You have already registered.", + ["invalid_firstname_format"] = "Invalid Format (First Name): Please try again.", + ["invalid_lastname_format"] = "Invalid Format (Last Name): Please try again.", + ["invalid_dob_format"] = "Invalid Format (DOB): Please try again.", + ["invalid_sex_format"] = "Invalid Format (Sex): Please try again.", + ["invalid_height_format"] = "Invalid Format (Height): Please try again.", +} diff --git a/resources/[core]/esx_identity/locales/es.lua b/resources/[core]/esx_identity/locales/es.lua new file mode 100644 index 0000000..3961d82 --- /dev/null +++ b/resources/[core]/esx_identity/locales/es.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Mostrar personaje actual", + ["active_character"] = "Personaje actual: %s", + ["error_active_character"] = "Se produjo un error al recuperar tu nombre. Por favor contacta con un administrador", + ["delete_character"] = "Elimina tu personaje y crea uno nuevo", + ["deleted_character"] = "Tu personaje ha sido eliminado", + ["error_delete_character"] = "Se produjo un error al eliminar tu personaje. Por favor contacta con un administrador", + ["thank_you_for_registering"] = "Gracias por registrarte. Bienvenido a la ciudad", + ["debug_xPlayer_get_first_name"] = "Devuelve tu nombre", + ["debug_xPlayer_get_last_name"] = "Devuelve tu apellido", + ["debug_xPlayer_get_full_name"] = "Devuelve tu nombre completo", + ["debug_xPlayer_get_sex"] = "Devuelve tu sexo", + ["debug_xPlayer_get_dob"] = "Devuelve tu fecha de nacimiento", + ["debug_xPlayer_get_height"] = "Devuelve tu altura", + ["error_debug_xPlayer_get_first_name"] = "Se produjo un error al recuperar tu nombre", + ["error_debug_xPlayer_get_last_name"] = "Se produjo un error al recuperar tu apellido", + ["error_debug_xPlayer_get_full_name"] = "Se produjo un error al recuperar tu nombre completo", + ["error_debug_xPlayer_get_sex"] = "Se produjo un error al recuperar tu sexo", + ["error_debug_xPlayer_get_dob"] = "Se produjo un error al recuperar tu fecha de nacimiento", + ["error_debug_xPlayer_get_height"] = "Se produjo un error al recuperar tu altura", + ["return_debug_xPlayer_get_first_name"] = "Nombre: %s", + ["return_debug_xPlayer_get_last_name"] = "Apellido: %s", + ["return_debug_xPlayer_get_full_name"] = "Nombre completo: %s", + ["return_debug_xPlayer_get_sex"] = "Sexo: %s", + ["return_debug_xPlayer_get_dob"] = "Fecha de nacimiento: %s", + ["return_debug_xPlayer_get_height"] = "Altura: %s centímetros", + ["data_incorrect"] = "Datos introducidos de forma incorrecta. Inténtalo de nuevo", + ["invalid_format"] = "Datos con formato incorrecto. Inténtalo de nuevo", + ["no_identifier"] = "¡Se ha producido un error al cargar tu personaje!\nCódigo de error: identifier-missing\n\nSe desconoce la causa de este error, no se pudo encontrar su identificador. Intentalo más tarde o informa de este problema al equipo administrativo del servidor", + ["missing_identity"] = "¡Se ha producido un error al cargar tu personaje!\nCódigo de error: identity-missing\n\nParece que falta su identidad, intenta conectarte nuevamente", + ["deleted_identity"] = "Tu personaje ha sido borrado. Vuelva a iniciar sesión para crear un nuevo personaje", + ["already_registered"] = "Ya estás registrado.", + ["invalid_firstname_format"] = "Formato Inválido (Nombre): Inténtalo de nuevo.", + ["invalid_lastname_format"] = "Formato Inválido (Apellido): Inténtalo de nuevo.", + ["invalid_dob_format"] = "Formato Inválido (Fec. Nac.): Inténtalo de nuevo.", + ["invalid_sex_format"] = "Formato Inválido (Sexo): Inténtalo de nuevo.", + ["invalid_height_format"] = "Formato Inválido (Altura): Inténtalo de nuevo.", +} diff --git a/resources/[core]/esx_identity/locales/fi.lua b/resources/[core]/esx_identity/locales/fi.lua new file mode 100644 index 0000000..f2c8793 --- /dev/null +++ b/resources/[core]/esx_identity/locales/fi.lua @@ -0,0 +1,33 @@ +return { + ["show_active_character"] = "Näytä nykyinen hahmosi", + ["active_character"] = "Nykyinen hahmosi: %s", + ["error_active_character"] = "Hahmosi hakemisessa ilmeni ongelma. Ota yhteyttä ylläpitoon.", + ["delete_character"] = "Poista hahmosi ja luo uusi.", + ["deleted_character"] = "Hahmosi on poistetu.", + ["error_delete_character"] = "Hahmosi poistossa ilmeni ongelma. Ota yhteyttä ylläpitoon.", + ["thank_you_for_registering"] = "Kiitos registeröitymisestä. Pidä hauskaa!", + ["registration_error"] = "Registeröinnissä ilmeni ongelma. Ota yhteyttä ylläpitoon.", + ["debug_xPlayer_get_first_name"] = "Palauta etunimi", + ["debug_xPlayer_get_last_name"] = "Palauta sukunimi", + ["debug_xPlayer_get_full_name"] = "Palauta kokonimi", + ["debug_xPlayer_get_sex"] = "Palauta sukupuoli", + ["debug_xPlayer_get_dob"] = "Palauta syntymäpäivä", + ["debug_xPlayer_get_height"] = "Palauta pituus", + ["error_debug_xPlayer_get_first_name"] = "Hahmosi etunimen haussa ilmeni ongelma.", + ["error_debug_xPlayer_get_last_name"] = "Hahmosi sukunimen haussa ilmeni ongelma.", + ["error_debug_xPlayer_get_full_name"] = "Hahmosi kokonimen haussa ilmeni ongelma.", + ["error_debug_xPlayer_get_sex"] = "Hahmosi sukupuolen haussa ilmeni ongelma.", + ["error_debug_xPlayer_get_dob"] = "Hahmosi syntymäpäivän haussa ilmeni ongelma.", + ["error_debug_xPlayer_get_height"] = "Hahmosi pituuden haussa ilmeni ongelma.", + ["return_debug_xPlayer_get_first_name"] = "Etunimi: %s", + ["return_debug_xPlayer_get_last_name"] = "Sukunimi: %s", + ["return_debug_xPlayer_get_full_name"] = "Kokonimi: %s", + ["return_debug_xPlayer_get_sex"] = "Sukupuoli: %s", + ["return_debug_xPlayer_get_dob"] = "Syntymäpäivä: %s", + ["return_debug_xPlayer_get_height"] = "Pituus: %s CM", + ["data_incorrect"] = "Data syötetty väärin. Yritä uudelleen.", + ["invalid_format"] = "Data syötetty väärässä muodossa. Yritä uudelleen.", + ["no_identifier"] = "Hahmosi lataamisessa ilmeni ongelma!\nVirhekoodi: identifier-missing\n\nVirhekoodin syytä ei tiedetä, joten ota yhteyttä ylläpitoon.", + ["missing_identity"] = "Hahmosi lataamisessa ilmeni ongelma!\nVirhekoodi: identity-missing\n\nNäyttää siltä että hahmoasi ei ole olemassa. Kokeile yhdistää uudelleen tai ota yhteyttä ylläpitoon", + ["deleted_identity"] = "Hahmosi on poistetu. Yhdistä palvelimelle uudestaan luodaksesi uusi hahmo.", +} diff --git a/resources/[core]/esx_identity/locales/fr.lua b/resources/[core]/esx_identity/locales/fr.lua new file mode 100644 index 0000000..4a0e007 --- /dev/null +++ b/resources/[core]/esx_identity/locales/fr.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Afficher le personnage actif", + ["active_character"] = "Personnage actif: %s", + ["error_active_character"] = "Une erreur s'est produite lors de l'obtention de vos données.", + ["delete_character"] = "Supprimer votre personnage actuel.", + ["deleted_character"] = "Personnage supprimé", + ["error_delete_character"] = "Un problème est survenu lors de la suppression de votre personnage.", + ["thank_you_for_registering"] = "Inscription réussie. Bon jeu à vous!", + ["debug_xPlayer_get_first_name"] = "Renvoie votre prénom", + ["debug_xPlayer_get_last_name"] = "Renvoie votre nom de famille", + ["debug_xPlayer_get_full_name"] = "Renvoie votre nom complet", + ["debug_xPlayer_get_sex"] = "Renvoie votre genre", + ["debug_xPlayer_get_dob"] = "Renvoie votre date de naissance", + ["debug_xPlayer_get_height"] = "Renvoie votre taille", + ["error_debug_xPlayer_get_first_name"] = "Un problème est survenu lors de l'obtention de votre prénom.", + ["error_debug_xPlayer_get_last_name"] = "Un problème est survenu lors de l'obtention de votre nom de famille.", + ["error_debug_xPlayer_get_full_name"] = "Un problème est survenu lors de l'obtention de votre nom complet.", + ["error_debug_xPlayer_get_sex"] = "Un problème est survenu lors de l'obtention de votre genre.", + ["error_debug_xPlayer_get_dob"] = "Un problème est survenu lors de l'obtention de votre date de naissance.", + ["error_debug_xPlayer_get_height"] = "Un problème est survenu lors de l'obtention de votre taille.", + ["return_debug_xPlayer_get_first_name"] = "Prénom: %s", + ["return_debug_xPlayer_get_last_name"] = "Nom de famille: %s", + ["return_debug_xPlayer_get_full_name"] = "Nom: %s", + ["return_debug_xPlayer_get_sex"] = "Genre: %s", + ["return_debug_xPlayer_get_dob"] = "Date de naissance: %s", + ["return_debug_xPlayer_get_height"] = "Taille: %s pouces", + ["data_incorrect"] = "Données invalides, veuillez réessayer.", + ["invalid_format"] = "Format de données invalide, veuillez réessayer.", + ["no_identifier"] = "[ESX Identity]\nUn problème est survenu lors du chargement de votre personnage !\nCode d'erreur : identifier-missing\n\nIl semble que votre identifiant soit manquant. Veuillez revenir plus tard ou signaler ce problème au propriétaire du serveur.", + ["missing_identity"] = "[ESX Identity]Un problème est survenu lors du chargement de votre personnage !\nCode d'erreur : identity-missing\n\nIl semble que votre identité soit manquante, essayez de vous reconnecter.", + ["deleted_identity"] = "Personnage supprimé. Veuillez vous réinscrire pour créer un nouveau personnage.", + ["already_registered"] = "Vous êtes déjà enregistré.", + ["invalid_firstname_format"] = "Format invalide (Prénom) : Veuillez réessayer.", + ["invalid_lastname_format"] = "Format invalide (Nom de famille) : Veuillez réessayer.", + ["invalid_dob_format"] = "Format invalide (Date de naissance) : Veuillez réessayer.", + ["invalid_sex_format"] = "Format invalide (Genre) : Veuillez réessayer.", + ["invalid_height_format"] = "Format invalide (Taille) : Veuillez réessayer.", +} diff --git a/resources/[core]/esx_identity/locales/he.lua b/resources/[core]/esx_identity/locales/he.lua new file mode 100644 index 0000000..1205e4e --- /dev/null +++ b/resources/[core]/esx_identity/locales/he.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "הצג דמות פעילה", + ["active_character"] = "דמות פעילה: %s", + ["error_active_character"] = "אירעה שגיאה בקבלת הנתונים שלך.", + ["delete_character"] = "מחק את הדמות הנוכחית שלך.", + ["deleted_character"] = "הדמות נמחקה", + ["error_delete_character"] = "אירעה בעיה במחיקת הדמות שלך.", + ["thank_you_for_registering"] = "הרשמה הושלמה. תהנה!", + ["debug_xPlayer_get_first_name"] = "מחזיר את שמך הפרטי", + ["debug_xPlayer_get_last_name"] = "מחזיר את שם משפחתך", + ["debug_xPlayer_get_full_name"] = "מחזיר את שמך המלא", + ["debug_xPlayer_get_sex"] = "מחזיר את המין שלך", + ["debug_xPlayer_get_dob"] = "מחזיר את תאריך הלידה שלך", + ["debug_xPlayer_get_height"] = "מחזיר את גובהך", + ["error_debug_xPlayer_get_first_name"] = "הייתה בעיה בקבלת שמך הפרטי.", + ["error_debug_xPlayer_get_last_name"] = "הייתה בעיה בקבלת שם משפחתך.", + ["error_debug_xPlayer_get_full_name"] = "הייתה בעיה בקבלת שמך המלא.", + ["error_debug_xPlayer_get_sex"] = "הייתה בעיה בקבלת המין שלך.", + ["error_debug_xPlayer_get_dob"] = "הייתה בעיה בקבלת תאריך הלידה שלך.", + ["error_debug_xPlayer_get_height"] = "הייתה בעיה בקבלת הגובה שלך.", + ["return_debug_xPlayer_get_first_name"] = "שם פרטי: %s", + ["return_debug_xPlayer_get_last_name"] = "שם משפחה: %s", + ["return_debug_xPlayer_get_full_name"] = "שם: %s", + ["return_debug_xPlayer_get_sex"] = "מין: %s", + ["return_debug_xPlayer_get_dob"] = "תאריך לידה: %s", + ["return_debug_xPlayer_get_height"] = "גובה: %s אינץ", + ["data_incorrect"] = "נתונים לא תקניים, נסה שוב.", + ["invalid_format"] = "פורמט נתונים לא תקני, נסה שוב.", + ["no_identifier"] = "[ESX Identity]\nהייתה בעיה בטעינת הדמות שלך!\nקוד שגיאה: מזהה חסר\n\nזה נגרם על ידי חוסר המזהה שלך. אנא חזור מאוחר יותר או דווח על הבעיה לבעל השרת.", + ["missing_identity"] = "[ESX Identity]\nהייתה בעיה בטעינת הדמות שלך!\nקוד שגיאה: זהות חסרה\n\nנראה שהזהות שלך חסרה, נסה להתחבר שוב.", + ["deleted_identity"] = "הדמות נמחקה. אנא הצטרף מחדש כדי ליצור דמות חדשה.", + ["already_registered"] = "כבר נרשמת.", + ["invalid_firstname_format"] = "פורמט לא תקני (שם פרטי): נסה שוב.", + ["invalid_lastname_format"] = "פורמט לא תקני (שם משפחה): נסה שוב.", + ["invalid_dob_format"] = "פורמט לא תקני (תאריך לידה): נסה שוב.", + ["invalid_sex_format"] = "פורמט לא תקני (מין): נסה שוב.", + ["invalid_height_format"] = "פורמט לא תקני (גובה): נסה שוב.", +} diff --git a/resources/[core]/esx_identity/locales/hu.lua b/resources/[core]/esx_identity/locales/hu.lua new file mode 100644 index 0000000..3c08cd3 --- /dev/null +++ b/resources/[core]/esx_identity/locales/hu.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Aktív karakterek mutatása", + ["active_character"] = "Aktív karakter: %s", + ["error_active_character"] = "A név nem megfelelő", + ["delete_character"] = "Töröld a karaktered és csinálj újat", + ["deleted_character"] = "A karaktered törölve", + ["error_delete_character"] = "Hiba történt a karakter törlésekor. Kérjük, lépjen kapcsolatba egy Adminisztrátorral.", + ["thank_you_for_registering"] = "Köszönjük hogy regisztrált! Kellemes játékot!", + ["debug_xPlayer_get_first_name"] = "Add meg a Vezetéknevét", + ["debug_xPlayer_get_last_name"] = "Add meg a Keresztnevét", + ["debug_xPlayer_get_full_name"] = "Add meg a teljes nevét", + ["debug_xPlayer_get_sex"] = "Add meg a nemét", + ["debug_xPlayer_get_dob"] = "Add meg a születési időt", + ["debug_xPlayer_get_height"] = "Add meg a magasságát", + ["error_debug_xPlayer_get_first_name"] = "Hiba történt a keresztnév lekérésekor.", + ["error_debug_xPlayer_get_last_name"] = "Hiba történt a vezetéknév lekérésekor.", + ["error_debug_xPlayer_get_full_name"] = "Hiba történt a teljes nevének lekérésekor.", + ["error_debug_xPlayer_get_sex"] = "Hiba történt a nem lekérésekor.", + ["error_debug_xPlayer_get_dob"] = "Hiba történt a születési dátum lekérésekor.", + ["error_debug_xPlayer_get_height"] = "Hiba történt a magasság lekérésekor.", + ["return_debug_xPlayer_get_first_name"] = "Vezetéknév: %s", + ["return_debug_xPlayer_get_last_name"] = "Keresztnév: %s", + ["return_debug_xPlayer_get_full_name"] = "Teljes név: %s", + ["return_debug_xPlayer_get_sex"] = "Nem: %s", + ["return_debug_xPlayer_get_dob"] = "Születési dátum: %s", + ["return_debug_xPlayer_get_height"] = "Magasság: %s hüvelyk", + ["data_incorrect"] = "Hibásan megadott adatok. Kérlek próbáld újra.", + ["invalid_format"] = "Az adatok helytelen formázása. Kérlek próbáld újra.", + ["no_identifier"] = "Hiba történt a karakter betöltésekor! \nHibakód: hiányzó azonosító \n\nA hiba oka nem ismert, az azonosító nem található. Kérjük, gyere vissza később, vagy jelentsd a problémát a szerver adminisztrációs csapatának.", + ["missing_identity"] = "Hiba történt a karaktered betöltésekor! \n Hibakód: hiányzik az identitás \n és \nNem úgy tűnik, hogy hiányzik a személyazonosságod, próbálkozz újra.", + ["deleted_identity"] = "A karaktered törölve", + ["already_registered"] = "Már regisztráltál.", + ["invalid_firstname_format"] = "Érvénytelen formátum (Keresztnév): Próbáld újra.", + ["invalid_lastname_format"] = "Érvénytelen formátum (Vezetéknév): Próbáld újra.", + ["invalid_dob_format"] = "Érvénytelen formátum (Születési Idő): Próbáld újra.", + ["invalid_sex_format"] = "Érvénytelen formátum (Nem): Próbáld újra.", + ["invalid_height_format"] = "Érvénytelen formátum (Magasság): Próbáld újra.", +} diff --git a/resources/[core]/esx_identity/locales/it.lua b/resources/[core]/esx_identity/locales/it.lua new file mode 100644 index 0000000..6bdca47 --- /dev/null +++ b/resources/[core]/esx_identity/locales/it.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Mostra Personaggio Attivo", + ["active_character"] = "Personaggio Attivo: %s", + ["error_active_character"] = "Errore nel recuperare i tuoi dati.", + ["delete_character"] = "Elimina Personaggio Attuale.", + ["deleted_character"] = "Personaggio Eliminato", + ["error_delete_character"] = "Errore nell' eliminazione del personaggio.", + ["thank_you_for_registering"] = "Registrazione effettuata. Divertiti!", + ["debug_xPlayer_get_first_name"] = "Ritorna il tuo nome", + ["debug_xPlayer_get_last_name"] = "Ritorna il tuo cognome", + ["debug_xPlayer_get_full_name"] = "Ritorna il tuo nome completo", + ["debug_xPlayer_get_sex"] = "Ritorna il tuo sesso", + ["debug_xPlayer_get_dob"] = "Ritorna la tua data di nascita", + ["debug_xPlayer_get_height"] = "Ritorna la tua altezza", + ["error_debug_xPlayer_get_first_name"] = "Errore nell' ottenere il tuo nome.", + ["error_debug_xPlayer_get_last_name"] = "Errore nell' ottenere il tuo cognome.", + ["error_debug_xPlayer_get_full_name"] = "Errore nell' ottenere il tuo nome completo.", + ["error_debug_xPlayer_get_sex"] = "Errore nell' ottenere il tuo sesso.", + ["error_debug_xPlayer_get_dob"] = "Errore nell' ottenere la tua data di nascita.", + ["error_debug_xPlayer_get_height"] = "Errore nell' ottenere la tua altezza.", + ["return_debug_xPlayer_get_first_name"] = "Nome: %s", + ["return_debug_xPlayer_get_last_name"] = "Cognome: %s", + ["return_debug_xPlayer_get_full_name"] = "Nome Completo: %s", + ["return_debug_xPlayer_get_sex"] = "Sesso: %s", + ["return_debug_xPlayer_get_dob"] = "Data di nascita: %s", + ["return_debug_xPlayer_get_height"] = "Altezza: %s Pollici", + ["data_incorrect"] = "Dati errati, riprova.", + ["invalid_format"] = "Formato dati errato, riprova.", + ["no_identifier"] = "[ESX Identity]\nErrore nel caricare il tuo personaggio!\nCodice Errore: identificativo-mancante\n\nQuesto è causato dalla mancanza del tuo identificativo. Riprova più tardi o segnalalo al proprietario del server.", + ["missing_identity"] = "[ESX Identity]\nErrore nel caricare il tuo personaggio!!\nCodice Errore: identità-mancante\n\nSembra che la tua identità sia mancante, prova a riconnetterti.", + ["deleted_identity"] = "Personaggio eliminato, Rientra per crearne uno nuovo.", + ["already_registered"] = "Sei già registrato.", + ["invalid_firstname_format"] = "Formato non valido (Nome): Riprova.", + ["invalid_lastname_format"] = "Formato non valido (Cognome): Riprova.", + ["invalid_dob_format"] = "Formato non valido (Data di nascita): Riprova.", + ["invalid_sex_format"] = "Formato non valido (Sesso): Riprova.", + ["invalid_height_format"] = "Formato non valido (Altezza): Riprova.", +} diff --git a/resources/[core]/esx_identity/locales/nl.lua b/resources/[core]/esx_identity/locales/nl.lua new file mode 100644 index 0000000..a5bd008 --- /dev/null +++ b/resources/[core]/esx_identity/locales/nl.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Actieve karakter laten zien", + ["active_character"] = "Actief karakter: %s", + ["error_active_character"] = "Er is een probleem opgetreden tijdens het verzamelen van uw data.", + ["delete_character"] = "Dit karakter verwijderen.", + ["deleted_character"] = "Karakter verwijderd", + ["error_delete_character"] = "Er is een probleem opgetreden tijdens het verwijderen van uw karakter.", + ["thank_you_for_registering"] = "Succesvol geregistreerd!", + ["debug_xPlayer_get_first_name"] = "Stuurt je Voornaam", + ["debug_xPlayer_get_last_name"] = "Stuurt je Achternaam", + ["debug_xPlayer_get_full_name"] = "Stuurt je volledige naam", + ["debug_xPlayer_get_sex"] = "Stuurt je Geslacht", + ["debug_xPlayer_get_dob"] = "Stuurt je Geboortedatum ", + ["debug_xPlayer_get_height"] = "Stuurt je lengte", + ["error_debug_xPlayer_get_first_name"] = "Er was een probleem tijdens het ophalen van je Voornaam.", + ["error_debug_xPlayer_get_last_name"] = "Er was een probleem tijdens het ophalen van je achternaam.", + ["error_debug_xPlayer_get_full_name"] = "Er was een probleem tijdens het ophalen van je volle naam.", + ["error_debug_xPlayer_get_sex"] = "Er was een probleem tijdens het ophalen van je Geslacht.", + ["error_debug_xPlayer_get_dob"] = "Er was een probleem tijdens het ophalen van je Geboortedatum.", + ["error_debug_xPlayer_get_height"] = "Er was een probleem tijdens het ophalen van je lengte.", + ["return_debug_xPlayer_get_first_name"] = "Voornaam: %s", + ["return_debug_xPlayer_get_last_name"] = "Achternaam: %s", + ["return_debug_xPlayer_get_full_name"] = "Naam: %s", + ["return_debug_xPlayer_get_sex"] = "Geslacht: %s", + ["return_debug_xPlayer_get_dob"] = "Geboortedatum: %s", + ["return_debug_xPlayer_get_height"] = "Lengte: %s Inches", + ["data_incorrect"] = "Verkeerde data, probeer opnieuw.", + ["invalid_format"] = "Verkeerde volgorde, probeer opnieuw.", + ["no_identifier"] = "[ESX Identity]\nEr was een probleem tijdens het laden van je karakter!\nError Code: identifier-missing\n\nDit komt omdat je identifier mist, contacteer het server beheer.", + ["missing_identity"] = "[ESX Identity]\nEr was een probleem tijdens het laden van je karakter!\nError Code: identity-missing\n\nHet lijkt erop dat je identiteit mist, reconnect met de server.", + ["deleted_identity"] = "Karakter verwijderd, reconnect om een nieuwe te registreren.", + ["already_registered"] = "Je bent al geregistreerd.", + ["invalid_firstname_format"] = "Ongeldige Volgorde (Voornaam): Probeer het nog een keer.", + ["invalid_lastname_format"] = "Ongeldige Volgorde (Achternaam): Probeer het nog een keer.", + ["invalid_dob_format"] = "Ongeldige Volgorde (Geboortedatum): Probeer het nog een keer.", + ["invalid_sex_format"] = "Ongeldige Volgorde (Geslacht): Probeer het nog een keer.", + ["invalid_height_format"] = "Ongeldige Volgorde (Lengte): Probeer het nog een keer.", +} diff --git a/resources/[core]/esx_identity/locales/pl.lua b/resources/[core]/esx_identity/locales/pl.lua new file mode 100644 index 0000000..7f6551c --- /dev/null +++ b/resources/[core]/esx_identity/locales/pl.lua @@ -0,0 +1,33 @@ +return { + ["show_active_character"] = "Pokaż aktywną postać", + ["active_character"] = "Aktywna postać: %s", + ["error_active_character"] = "Podczas pobierania Twojego imienia wystąpił błąd. Proszę skontaktować się z administratorem.", + ["delete_character"] = "Usuń swoją postać i stwórz nową", + ["deleted_character"] = "Twoja postać została usunięta.", + ["error_delete_character"] = "Wystąpił błąd podczas usuwania twojej postaci. Proszę skontaktować się z administratorem.", + ["thank_you_for_registering"] = "Dziękujemy za rejestrację. Baw się dobrze.", + ["registration_error"] = "Wystąpił błąd podczas rejestracji. Proszę skontaktować się z administratorem.", + ["debug_xPlayer_get_first_name"] = "Podaj swoje imię", + ["debug_xPlayer_get_last_name"] = "Podaj swoje nazwisko", + ["debug_xPlayer_get_full_name"] = "Podaj swoją pełną nazwę", + ["debug_xPlayer_get_sex"] = "Podaj swoją płeć", + ["debug_xPlayer_get_dob"] = "Podaj swoją datę urodzenia", + ["debug_xPlayer_get_height"] = "Podaj swój wzrost", + ["error_debug_xPlayer_get_first_name"] = "Podczas pobierania twojego imienia wystąpił błąd.", + ["error_debug_xPlayer_get_last_name"] = "Podczas pobierania twojego nazwiska wystąpił błąd.", + ["error_debug_xPlayer_get_full_name"] = "Podczas pobierania twojego pełnego imienia wystąpił błąd.", + ["error_debug_xPlayer_get_sex"] = "Podczas pobierania twojej płci wystąpił błąd.", + ["error_debug_xPlayer_get_dob"] = "Podczas pobierania daty urodzenia wystąpił błąd.", + ["error_debug_xPlayer_get_height"] = "Podczas pobierania wzrostu wystąpił błąd.", + ["return_debug_xPlayer_get_first_name"] = "Imię: %s", + ["return_debug_xPlayer_get_last_name"] = "Nazwisko: %s", + ["return_debug_xPlayer_get_full_name"] = "Pełna nazwa: %s", + ["return_debug_xPlayer_get_sex"] = "Płeć: %s", + ["return_debug_xPlayer_get_dob"] = "Data urodzenia: %s", + ["return_debug_xPlayer_get_height"] = "Wzrost: %s centymetrów", + ["data_incorrect"] = "Data została wprowadzona niepoprawnie. Proszę spróbuj ponownie.", + ["invalid_format"] = "Data została wprowadzona niepoprawnie. Proszę spróbuj ponownie.", + ["no_identifier"] = "Wystąpił błąd podczas ładowania twojej postaci!\nKod błędu: identifier-missing\n\nPrzyczyna tego błędu nie jest znana, nie można znaleźć Twojego identyfikatora. Wróć później lub zgłoś ten problem zespołowi administracyjnemu serwera.", + ["missing_identity"] = "Wystąpił błąd podczas ładowania twojej postaci!\nKod błędu: identity-missing\n\nWygląda na to, że brakuje Twojej tożsamości, spróbuj połączyć się ponownie.", + ["deleted_identity"] = "Twoja postać została usunięta. Dołącz ponownie, aby utworzyć nową postać.", +} diff --git a/resources/[core]/esx_identity/locales/pt.lua b/resources/[core]/esx_identity/locales/pt.lua new file mode 100644 index 0000000..1d78f10 --- /dev/null +++ b/resources/[core]/esx_identity/locales/pt.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Mostrar personagem ativa", + ["active_character"] = "Personagem ativa: %s", + ["error_active_character"] = "Houve um erro a obter os teus dados.", + ["delete_character"] = "Apagar a tua personagem atual.", + ["deleted_character"] = "Personagem apagada!", + ["error_delete_character"] = "Houve um problema ao apagar a tua personagem.", + ["thank_you_for_registering"] = "Registo concluído. Diverte-te!", + ["debug_xPlayer_get_first_name"] = "Retorna o teu primeiro nome", + ["debug_xPlayer_get_last_name"] = "Retorna o teu último nome", + ["debug_xPlayer_get_full_name"] = "Retorna o teu nome completo", + ["debug_xPlayer_get_sex"] = "Retorna o teu sexo", + ["debug_xPlayer_get_dob"] = "Retorna a tua data de nascimento", + ["debug_xPlayer_get_height"] = "Retorna a tua altura", + ["error_debug_xPlayer_get_first_name"] = "Houve um problema ao obter o teu primeiro nome.", + ["error_debug_xPlayer_get_last_name"] = "Houve um problema ao obter o teu último nome.", + ["error_debug_xPlayer_get_full_name"] = "Houve um problema ao obter o teu nome completo.", + ["error_debug_xPlayer_get_sex"] = "Houve um problema ao obter o teu sexo.", + ["error_debug_xPlayer_get_dob"] = "Houve um problema ao obter a tua data de nascimento.", + ["error_debug_xPlayer_get_height"] = "Houve um problema ao obter a tua altura.", + ["return_debug_xPlayer_get_first_name"] = "Primeiro nome: %s", + ["return_debug_xPlayer_get_last_name"] = "Último nome: %s", + ["return_debug_xPlayer_get_full_name"] = "Nome: %s", + ["return_debug_xPlayer_get_sex"] = "Sexo: %s", + ["return_debug_xPlayer_get_dob"] = "Data de nascimento: %s", + ["return_debug_xPlayer_get_height"] = "Altura: %s cm", + ["data_incorrect"] = "Dados inválidos, tenta novamente.", + ["invalid_format"] = "Formato dos dados inválido, tenta novamente.", + ["no_identifier"] = "[ESX Identity]\nHouve um erro ao carregar a tua personagem!\nCódigo do erro: identifier-missing\n\nEste erro é devido à falta do teu identificador. Porfavor volta mais tarde ou reporta este problema a um Administrador.", + ["missing_identity"] = "[ESX Identity]\nHouve um erro ao carregar a tua personagem!\nCódigo do erro: identity-missing\n\nParece que a tua identidade está em falta, experimenta reentrar no servidor!", + ["deleted_identity"] = "Personagem apagada. Porfavor reentra para criar uma nova personagem.", + ["already_registered"] = "Tu já estás registado.", + ["invalid_firstname_format"] = "Formato inválido (Primeiro nome): Porfavor tenta novamente!", + ["invalid_lastname_format"] = "Formato inválido (Último nome): Porfavor tenta novamente!", + ["invalid_dob_format"] = "Formato inválido (Data de nascimento): Porfavor tenta novamente!", + ["invalid_sex_format"] = "Formato inválido (Sexo): Porfavor tenta novamente!", + ["invalid_height_format"] = "Formato inválido (Altura): Porfavor tenta novamente!", +} diff --git a/resources/[core]/esx_identity/locales/sl.lua b/resources/[core]/esx_identity/locales/sl.lua new file mode 100644 index 0000000..cf4ad1e --- /dev/null +++ b/resources/[core]/esx_identity/locales/sl.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Prikaži aktivnega lika", + ["active_character"] = "Aktivni lik: %s", + ["error_active_character"] = "Prišlo je do napake pri pridobivanju podatkov.", + ["delete_character"] = "Izbriši trenutnega lika.", + ["deleted_character"] = "Lik je bil izbrisan", + ["error_delete_character"] = "Prišlo je do težave pri brisanju lika.", + ["thank_you_for_registering"] = "Registracija uspešna. Uživajte!", + ["debug_xPlayer_get_first_name"] = "Vrne vaše ime", + ["debug_xPlayer_get_last_name"] = "Vrne vaše priimek", + ["debug_xPlayer_get_full_name"] = "Vrne vaše polno ime", + ["debug_xPlayer_get_sex"] = "Vrne vaš spol", + ["debug_xPlayer_get_dob"] = "Vrne vaš datum rojstva", + ["debug_xPlayer_get_height"] = "Vrne vašo višino", + ["error_debug_xPlayer_get_first_name"] = "Prišlo je do težave pri pridobivanju vašega imena.", + ["error_debug_xPlayer_get_last_name"] = "Prišlo je do težave pri pridobivanju vašega priimka.", + ["error_debug_xPlayer_get_full_name"] = "Prišlo je do težave pri pridobivanju vašega polnega imena.", + ["error_debug_xPlayer_get_sex"] = "Prišlo je do težave pri pridobivanju vašega spola.", + ["error_debug_xPlayer_get_dob"] = "Prišlo je do težave pri pridobivanju vašega datuma rojstva.", + ["error_debug_xPlayer_get_height"] = "Prišlo je do težave pri pridobivanju vaše višine.", + ["return_debug_xPlayer_get_first_name"] = "Ime: %s", + ["return_debug_xPlayer_get_last_name"] = "Priimek: %s", + ["return_debug_xPlayer_get_full_name"] = "Ime: %s", + ["return_debug_xPlayer_get_sex"] = "Spol: %s", + ["return_debug_xPlayer_get_dob"] = "Datum rojstva: %s", + ["return_debug_xPlayer_get_height"] = "Višina: %s palcev", + ["data_incorrect"] = "Neveljavni podatki. Poskusite znova.", + ["invalid_format"] = "Neveljavna oblika podatkov. Poskusite znova.", + ["no_identifier"] = "[ESX Identity]\nPrišlo je do težave pri nalaganju vašega lika!\nNapaka: manjkajoč-identifier\n\nTo je posledica manjkajočega identifikatorja. Prosimo, poskusite znova kasneje ali to težavo prijavite lastniku strežnika.", + ["missing_identity"] = "[ESX Identity]\nPrišlo je do težave pri nalaganju vašega lika!\nNapaka: manjkajoč-identity\n\nZdi se, da manjka vaša identiteta. Poskusite znova.", + ["deleted_identity"] = "Lik izbrisan. Prosimo, ponovno se pridružite in ustvarite nov lik.", + ["already_registered"] = "Že ste registrirani.", + ["invalid_firstname_format"] = "Neveljavna oblika (Ime). Poskusite znova.", + ["invalid_lastname_format"] = "Neveljavna oblika (Priimek). Poskusite znova.", + ["invalid_dob_format"] = "Neveljavna oblika (Datum rojstva). Poskusite znova.", + ["invalid_sex_format"] = "Neveljavna oblika (Spol). Poskusite znova.", + ["invalid_height_format"] = "Neveljavna oblika (Višina). Poskusite znova.", +} diff --git a/resources/[core]/esx_identity/locales/sr.lua b/resources/[core]/esx_identity/locales/sr.lua new file mode 100644 index 0000000..f34819e --- /dev/null +++ b/resources/[core]/esx_identity/locales/sr.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Prikazi karaktere", + ["active_character"] = "Karakteri: %s", + ["error_active_character"] = "Imamo problem sa ucitavanjem karaktera.", + ["delete_character"] = "Obrisite karaktera.", + ["deleted_character"] = "Karakter obrisan", + ["error_delete_character"] = "Doslo je do greske pri brisanju karaktera.", + ["thank_you_for_registering"] = "Registracija uspesna. Uzivajte!", + ["debug_xPlayer_get_first_name"] = "Vraca vase ime", + ["debug_xPlayer_get_last_name"] = "Vraca vase prezime", + ["debug_xPlayer_get_full_name"] = "Vraca vase puno ime", + ["debug_xPlayer_get_sex"] = "Vraca vas pol", + ["debug_xPlayer_get_dob"] = "Vraca vas datum rodjenja", + ["debug_xPlayer_get_height"] = "Vraca vasu visinu", + ["error_debug_xPlayer_get_first_name"] = "Doslo je do greske pri pronalazenju vaseg imena.", + ["error_debug_xPlayer_get_last_name"] = "Doslo je do greske pri pronalazenju vaseg prezimena.", + ["error_debug_xPlayer_get_full_name"] = "Doslo je do greske pri pronalazenju vaseg punog imena.", + ["error_debug_xPlayer_get_sex"] = "Doslo je do greske pri pronalazenju vaseg pola.", + ["error_debug_xPlayer_get_dob"] = "Doslo je do greske pri pronalazenju vaseg datuma rodjenja.", + ["error_debug_xPlayer_get_height"] = "Doslo je do greske pri pronalazenju vase visine.", + ["return_debug_xPlayer_get_first_name"] = "Ime: %s", + ["return_debug_xPlayer_get_last_name"] = "Prezime: %s", + ["return_debug_xPlayer_get_full_name"] = "Ime: %s", + ["return_debug_xPlayer_get_sex"] = "Pol: %s", + ["return_debug_xPlayer_get_dob"] = "Datum rodjenja: %s", + ["return_debug_xPlayer_get_height"] = "Visina: %s", + ["data_incorrect"] = "Nevazeci podatci, pokusajte ponovo.", + ["invalid_format"] = "Nevazeci format podataka, pokusajte ponovo.", + ["no_identifier"] = "[ESX Identity]\nDoslo je do greske pri ucitavanju vaseg karaktera!\nError Code: identifier-missing\n\nUpalite steam pa pokusajte ponovo.", + ["missing_identity"] = "[ESX Identity]\nDoslo je do greske pri ucitavanju vaseg karaktera!\nError Code: identity-missing\n\nIzgleda da je vas steam nepostojeci. Pokusajte ponovo.", + ["deleted_identity"] = "Karakter obrisan. Uradite relog kako bi napravili novog karaktera.", + ["already_registered"] = "Vi ste vec registrovani.", + ["invalid_firstname_format"] = "Nevazeci Format (Ime): Pokusajte ponovo.", + ["invalid_lastname_format"] = "Nevazeci Format (Prezime): Pokusajte ponovo.", + ["invalid_dob_format"] = "Nevazeci Format (Datum Rodjenja): Pokusajte ponovo.", + ["invalid_sex_format"] = "Nevazeci Format (Pol): Pokusajte ponovo.", + ["invalid_height_format"] = "Nevazeci Format (Visina): Pokusajte ponovo.", +} diff --git a/resources/[core]/esx_identity/locales/sv.lua b/resources/[core]/esx_identity/locales/sv.lua new file mode 100644 index 0000000..c298c85 --- /dev/null +++ b/resources/[core]/esx_identity/locales/sv.lua @@ -0,0 +1,38 @@ +return { + ["show_active_character"] = "Visa aktiv karaktär", + ["active_character"] = "Aktiv karaktär: %s", + ["error_active_character"] = "Det blev ett fel med att ta din data.", + ["delete_character"] = "Radera din nuvarande karaktär.", + ["deleted_character"] = "Karaktär raderad", + ["error_delete_character"] = "Det uppstod ett problem med att radera din karaktär.", + ["thank_you_for_registering"] = "Din karaktär är skapad. Grattis!", + ["debug_xPlayer_get_first_name"] = "Ger ditt förnamn", + ["debug_xPlayer_get_last_name"] = "Ger ditt efternamn", + ["debug_xPlayer_get_full_name"] = "Ger ditt fulla namn", + ["debug_xPlayer_get_sex"] = "Ger ditt kön", + ["debug_xPlayer_get_dob"] = "Ger ditt födelsedatum", + ["debug_xPlayer_get_height"] = "Ger din längd", + ["error_debug_xPlayer_get_first_name"] = "Det blev ett problem med att få ditt förnamn.", + ["error_debug_xPlayer_get_last_name"] = "Det blev ett problem med att få ditt efternamn.", + ["error_debug_xPlayer_get_full_name"] = "Det blev ett problem med att få ditt fulla namn.", + ["error_debug_xPlayer_get_sex"] = "Det blev ett problem med att få ditt kön.", + ["error_debug_xPlayer_get_dob"] = "Det blev ett problem med att få ditt födelsedatum.", + ["error_debug_xPlayer_get_height"] = "Det blev ett problem med att få din längd.", + ["return_debug_xPlayer_get_first_name"] = "Förnamn: %s", + ["return_debug_xPlayer_get_last_name"] = "Efternamn: %s", + ["return_debug_xPlayer_get_full_name"] = "Namn: %s", + ["return_debug_xPlayer_get_sex"] = "Kön: %s", + ["return_debug_xPlayer_get_dob"] = "Födelsedatum: %s", + ["return_debug_xPlayer_get_height"] = "Längd: %s Cm", + ["data_incorrect"] = "Ogiltigt, försök igen.", + ["invalid_format"] = "Ogiltigt format, försök igen.", + ["no_identifier"] = "[ESX Identity]\nDet blev ett fel med att ladda din karaktär!\nFelkod: identifier-missing\n\nSer ut som att din identifier saknas. Testa senare eller kontakta serverägare.", + ["missing_identity"] = "[ESX Identity]\nThere was an issue loading your character!\nFelkod: identity-missing\n\nSer ut som att din identity saknas, testa anslut igen.", + ["deleted_identity"] = "Karaktär raderad. Restarta ditt spel för att skapa ny karaktär.", + ["already_registered"] = "Du har redan registrerat.", + ["invalid_firstname_format"] = "Ogiltigt format (Förnamn): Försök igen.", + ["invalid_lastname_format"] = "Ogiltigt format (Efternamn): Försök igen.", + ["invalid_dob_format"] = "Ogiltigt format (Födelsedatum): Försök igen.", + ["invalid_sex_format"] = "Ogiltigt format (Kön): Försök igen.", + ["invalid_height_format"] = "Ogiltigt format (Längd): Försök igen.", +} diff --git a/resources/[core]/esx_identity/server/main.lua b/resources/[core]/esx_identity/server/main.lua new file mode 100644 index 0000000..584425b --- /dev/null +++ b/resources/[core]/esx_identity/server/main.lua @@ -0,0 +1,409 @@ +local playerIdentity = {} +local alreadyRegistered = {} +local multichar = ESX.GetConfig().Multichar + +local function deleteIdentityFromDatabase(xPlayer) + MySQL.query.await("UPDATE users SET firstname = ?, lastname = ?, dateofbirth = ?, sex = ?, height = ?, skin = ? WHERE identifier = ?", { nil, nil, nil, nil, nil, nil, xPlayer.identifier }) + + if Config.FullCharDelete then + MySQL.update.await("UPDATE addon_account_data SET money = 0 WHERE account_name IN (?) AND owner = ?", { { "bank_savings", "caution" }, xPlayer.identifier }) + + MySQL.prepare.await("UPDATE datastore_data SET data = ? WHERE name IN (?) AND owner = ?", { "'{}'", { "user_ears", "user_glasses", "user_helmet", "user_mask" }, xPlayer.identifier }) + end +end + +---@param xPlayer StaticPlayer|xPlayer +---@param data {firstName:string?, lastName:string?, dateOfBirth:string?, height:number?, sex:"m"|"f"?} +function SetPlayerData(xPlayer, data) + local name = ("%s %s"):format(data.firstName, data.lastName) + xPlayer.setName(name) + xPlayer.set("firstName", data.firstName) + xPlayer.set("lastName", data.lastName) + xPlayer.set("dateofbirth", data.dateOfBirth) + xPlayer.set("sex", data.sex) + xPlayer.set("height", data.height) + + local state = Player(xPlayer.getSource()).state + state:set("name", name, true) + state:set("firstName", data.firstName, true) + state:set("lastName", data.lastName, true) + state:set("dateofbirth", data.dateOfBirth, true) + state:set("sex", data.sex, true) + state:set("height", data.height, true) +end + +---@param xPlayer xPlayer +local function deleteIdentity(xPlayer) + if not alreadyRegistered[xPlayer.identifier] then + return + end + + SetPlayerData(xPlayer, { firstName = nil, lastName = nil, dateOfBirth = nil, sex = nil, height = nil }) + deleteIdentityFromDatabase(xPlayer) +end + + +local function saveIdentityToDatabase(identifier, identity) + MySQL.update.await("UPDATE users SET firstname = ?, lastname = ?, dateofbirth = ?, sex = ?, height = ? WHERE identifier = ?", { identity.firstName, identity.lastName, identity.dateOfBirth, identity.sex, identity.height, identifier }) +end + +---@param year number Year +---@return boolean: true if the year is a leap year, false otherwise +local function isLeapYear(year) + return (year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0) +end + +---@param dob string Date of Birth in the format DD/MM/YYYY +---@return boolean: true if the date is valid, false otherwise +local function checkDOBFormat(dob) + dob = tostring(dob) + + local dayStr, monthStr, yearStr = dob:match("^(%d%d?)/(%d%d?)/(%d%d%d%d)$") + if not dayStr or not monthStr or not yearStr then + return false + end + + local day, month, year = tonumber(dayStr), tonumber(monthStr), tonumber(yearStr) + if not day or not month or not year then + return false + end + + local currentYear = os.date("*t").year + local minYear = currentYear - Config.MaxAge + local maxYear = currentYear - 18 + + if year < minYear or year > maxYear then return false end + if month < 1 or month > 12 then return false end + + -- Days in each month (starting from January.) + local daysInMonth = { 31, isLeapYear(year) and 29 or 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + return day >= 1 and day <= daysInMonth[month] +end + +local function formatDate(str) + local d, m, y = string.match(str, "(%d+)/(%d+)/(%d+)") + local date = str + + if Config.DateFormat == "MM/DD/YYYY" then + date = m .. "/" .. d .. "/" .. y + elseif Config.DateFormat == "YYYY/MM/DD" then + date = y .. "/" .. m .. "/" .. d + end + + return date +end + +local function checkNameFormat(name) + if ESX.IsValidLocaleString(name) then + local stringLength = string.len(name) + return stringLength > 0 and stringLength < Config.MaxNameLength + end + + return false +end + +local function checkSexFormat(sex) + if not sex then + return false + end + return sex == "m" or sex == "M" or sex == "f" or sex == "F" +end + +local function checkHeightFormat(height) + local numHeight = tonumber(height) or 0 + return numHeight >= Config.MinHeight and numHeight <= Config.MaxHeight +end + +local function convertToLowerCase(str) + return string.lower(str) +end + +local function convertFirstLetterToUpper(str) + return str:gsub("^%l", string.upper) +end + +local function formatName(name) + local loweredName = convertToLowerCase(name) + return convertFirstLetterToUpper(loweredName) +end + +---@param xPlayer StaticPlayer +local function setIdentity(xPlayer) + local playerIdentifier = xPlayer.getIdentifier() + if not alreadyRegistered[playerIdentifier] then + return + end + local currentIdentity = playerIdentity[playerIdentifier] + SetPlayerData(xPlayer, currentIdentity) + + TriggerClientEvent("esx_identity:setPlayerData", xPlayer.src, currentIdentity) + if currentIdentity.saveToDatabase then + saveIdentityToDatabase(playerIdentifier, currentIdentity) + end + + playerIdentity[playerIdentifier] = nil +end + +---@param xPlayer StaticPlayer +local function checkIdentity(xPlayer) + local playerIdentifier = xPlayer.getIdentifier() + MySQL.single("SELECT firstname, lastname, dateofbirth, sex, height FROM users WHERE identifier = ?", { playerIdentifier }, function(result) + if not result then + return TriggerClientEvent("esx_identity:showRegisterIdentity", xPlayer.src) + end + if not result.firstname then + playerIdentity[playerIdentifier] = nil + alreadyRegistered[playerIdentifier] = false + return TriggerClientEvent("esx_identity:showRegisterIdentity", xPlayer.src) + end + + playerIdentity[playerIdentifier] = { + firstName = result.firstname, + lastName = result.lastname, + dateOfBirth = result.dateofbirth, + sex = result.sex, + height = result.height, + } + + alreadyRegistered[playerIdentifier] = true + setIdentity(xPlayer) + end) +end + +if not multichar then + AddEventHandler("playerConnecting", function(_, _, deferrals) + deferrals.defer() + local _, identifier = source, nil + + local correctLicense, _ = pcall(function() + identifier = ESX.GetIdentifier(source) + end) + + Wait(40) + + if not identifier or not correctLicense then + return deferrals.done(TranslateCap("no_identifier")) + end + MySQL.single("SELECT firstname, lastname, dateofbirth, sex, height FROM users WHERE identifier = ?", { identifier }, function(result) + if not result then + playerIdentity[identifier] = nil + alreadyRegistered[identifier] = false + return deferrals.done() + end + if not result.firstname then + playerIdentity[identifier] = nil + alreadyRegistered[identifier] = false + return deferrals.done() + end + + playerIdentity[identifier] = { + firstName = result.firstname, + lastName = result.lastname, + dateOfBirth = result.dateofbirth, + sex = result.sex, + height = result.height, + } + + alreadyRegistered[identifier] = true + + deferrals.done() + end) + end) + + AddEventHandler("onResourceStart", function(resource) + if resource ~= GetCurrentResourceName() then + return + end + Wait(300) + + while not ESX do + Wait(0) + end + + local xPlayers = ESX.ExtendedPlayers() --[=[@as StaticPlayer[]]=] + + for i = 1, #xPlayers do + if xPlayers[i] then + checkIdentity(xPlayers[i]) + end + end + end) + + RegisterNetEvent("esx:playerLoaded", function(_, xPlayer) + local currentIdentity = playerIdentity[xPlayer.identifier] + + if currentIdentity and alreadyRegistered[xPlayer.identifier] then + SetPlayerData(xPlayer, currentIdentity) + + TriggerClientEvent("esx_identity:setPlayerData", xPlayer.source, currentIdentity) + if currentIdentity.saveToDatabase then + saveIdentityToDatabase(xPlayer.identifier, currentIdentity) + end + + Wait(0) + + TriggerClientEvent("esx_identity:alreadyRegistered", xPlayer.source) + + playerIdentity[xPlayer.identifier] = nil + else + TriggerClientEvent("esx_identity:showRegisterIdentity", xPlayer.source) + end + end) +end + +ESX.RegisterServerCallback("esx_identity:registerIdentity", function(source, cb, data) + local xPlayer = ESX.Player(source) + + if not checkNameFormat(data.firstname) then + TriggerClientEvent("esx:showNotification", source, TranslateCap("invalid_firstname_format"), "error") + return cb(false) + end + if not checkNameFormat(data.lastname) then + TriggerClientEvent("esx:showNotification", source, TranslateCap("invalid_lastname_format"), "error") + return cb(false) + end + if not checkSexFormat(data.sex) then + TriggerClientEvent("esx:showNotification", source, TranslateCap("invalid_sex_format"), "error") + return cb(false) + end + if not checkDOBFormat(data.dateofbirth) then + TriggerClientEvent("esx:showNotification", source, TranslateCap("invalid_dob_format"), "error") + return cb(false) + end + if not checkHeightFormat(data.height) then + TriggerClientEvent("esx:showNotification", source, TranslateCap("invalid_height_format"), "error") + return cb(false) + end + + if xPlayer then + local identifier = xPlayer.getIdentifier() + if alreadyRegistered[identifier] then + xPlayer.showNotification(TranslateCap("already_registered"), "error") + return cb(false) + end + + playerIdentity[identifier] = { + firstName = formatName(data.firstname), + lastName = formatName(data.lastname), + dateOfBirth = formatDate(data.dateofbirth), + sex = data.sex, + height = data.height, + } + + local currentIdentity = playerIdentity[identifier] + + SetPlayerData(xPlayer, currentIdentity) + + TriggerClientEvent("esx_identity:setPlayerData", xPlayer.src, currentIdentity) + saveIdentityToDatabase(identifier, currentIdentity) + alreadyRegistered[identifier] = true + playerIdentity[identifier] = nil + return cb(true) + end + + if not multichar then + TriggerClientEvent("esx:showNotification", source, TranslateCap("data_incorrect"), "error") + return cb(false) + end + + local formattedFirstName = formatName(data.firstname) + local formattedLastName = formatName(data.lastname) + local formattedDate = formatDate(data.dateofbirth) + + data.firstname = formattedFirstName + data.lastname = formattedLastName + data.dateofbirth = formattedDate + local Identity = { + firstName = formattedFirstName, + lastName = formattedLastName, + dateOfBirth = formattedDate, + sex = data.sex, + height = data.height, + } + + TriggerEvent("esx_identity:completedRegistration", source, data) + TriggerClientEvent("esx_identity:setPlayerData", source, Identity) + cb(true) +end) + +if Config.EnableCommands then + ESX.RegisterCommand("char", "user", function(xPlayer) + if xPlayer and xPlayer.getName() then + xPlayer.showNotification(TranslateCap("active_character", xPlayer.getName())) + else + xPlayer.showNotification(TranslateCap("error_active_character")) + end + end, false, { help = TranslateCap("show_active_character") }) + + ESX.RegisterCommand("chardel", "user", function(xPlayer) + if xPlayer and xPlayer.getName() then + local identifier = xPlayer.getIdentifier() + if Config.UseDeferrals then + xPlayer.kick(TranslateCap("deleted_identity")) + Wait(1500) + deleteIdentity(xPlayer) + xPlayer.showNotification(TranslateCap("deleted_character")) + playerIdentity[identifier] = nil + alreadyRegistered[identifier] = false + else + deleteIdentity(xPlayer) + xPlayer.showNotification(TranslateCap("deleted_character")) + playerIdentity[identifier] = nil + alreadyRegistered[identifier] = false + TriggerClientEvent("esx_identity:showRegisterIdentity", xPlayer.source) + end + else + xPlayer.showNotification(TranslateCap("error_delete_character")) + end + end, false, { help = TranslateCap("delete_character") }) +end + +if Config.EnableDebugging then + ESX.RegisterCommand("xPlayerGetFirstName", "user", function(xPlayer) + if xPlayer and xPlayer.get("firstName") then + xPlayer.showNotification(TranslateCap("return_debug_xPlayer_get_first_name", xPlayer.get("firstName"))) + else + xPlayer.showNotification(TranslateCap("error_debug_xPlayer_get_first_name")) + end + end, false, { help = TranslateCap("debug_xPlayer_get_first_name") }) + + ESX.RegisterCommand("xPlayerGetLastName", "user", function(xPlayer) + if xPlayer and xPlayer.get("lastName") then + xPlayer.showNotification(TranslateCap("return_debug_xPlayer_get_last_name", xPlayer.get("lastName"))) + else + xPlayer.showNotification(TranslateCap("error_debug_xPlayer_get_last_name")) + end + end, false, { help = TranslateCap("debug_xPlayer_get_last_name") }) + + ESX.RegisterCommand("xPlayerGetFullName", "user", function(xPlayer) + if xPlayer and xPlayer.getName() then + xPlayer.showNotification(TranslateCap("return_debug_xPlayer_get_full_name", xPlayer.getName())) + else + xPlayer.showNotification(TranslateCap("error_debug_xPlayer_get_full_name")) + end + end, false, { help = TranslateCap("debug_xPlayer_get_full_name") }) + + ESX.RegisterCommand("xPlayerGetSex", "user", function(xPlayer) + if xPlayer and xPlayer.get("sex") then + xPlayer.showNotification(TranslateCap("return_debug_xPlayer_get_sex", xPlayer.get("sex"))) + else + xPlayer.showNotification(TranslateCap("error_debug_xPlayer_get_sex")) + end + end, false, { help = TranslateCap("debug_xPlayer_get_sex") }) + + ESX.RegisterCommand("xPlayerGetDOB", "user", function(xPlayer) + if xPlayer and xPlayer.get("dateofbirth") then + xPlayer.showNotification(TranslateCap("return_debug_xPlayer_get_dob", xPlayer.get("dateofbirth"))) + else + xPlayer.showNotification(TranslateCap("error_debug_xPlayer_get_dob")) + end + end, false, { help = TranslateCap("debug_xPlayer_get_dob") }) + + ESX.RegisterCommand("xPlayerGetHeight", "user", function(xPlayer) + if xPlayer and xPlayer.get("height") then + xPlayer.showNotification(TranslateCap("return_debug_xPlayer_get_height", xPlayer.get("height"))) + else + xPlayer.showNotification(TranslateCap("error_debug_xPlayer_get_height")) + end + end, false, { help = TranslateCap("debug_xPlayer_get_height") }) +end diff --git a/resources/[core]/esx_identity/web/.yarn.installed b/resources/[core]/esx_identity/web/.yarn.installed new file mode 100644 index 0000000..e69de29 diff --git a/resources/[core]/esx_identity/web/index.html b/resources/[core]/esx_identity/web/index.html new file mode 100644 index 0000000..1159b9e --- /dev/null +++ b/resources/[core]/esx_identity/web/index.html @@ -0,0 +1,21 @@ + + + + + + + + Vite + Vue + + + + + +

+ + + + \ No newline at end of file diff --git a/resources/[core]/esx_identity/web/package.json b/resources/[core]/esx_identity/web/package.json new file mode 100644 index 0000000..c40a191 --- /dev/null +++ b/resources/[core]/esx_identity/web/package.json @@ -0,0 +1,21 @@ +{ + "name": "esx_identity_new", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "moment": "^2.30.1", + "vee-validate": "^4.14.3", + "vue": "^3.5.10", + "yup": "^1.4.0" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.1.4", + "vite": "^5.4.8" + } +} diff --git a/resources/[core]/esx_identity/web/public/vite.svg b/resources/[core]/esx_identity/web/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/resources/[core]/esx_identity/web/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/[core]/esx_identity/web/src/App.vue b/resources/[core]/esx_identity/web/src/App.vue new file mode 100644 index 0000000..c8dc679 --- /dev/null +++ b/resources/[core]/esx_identity/web/src/App.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/resources/[core]/esx_identity/web/src/assets/vue.svg b/resources/[core]/esx_identity/web/src/assets/vue.svg new file mode 100644 index 0000000..770e9d3 --- /dev/null +++ b/resources/[core]/esx_identity/web/src/assets/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/[core]/esx_identity/web/src/components/Identity.vue b/resources/[core]/esx_identity/web/src/components/Identity.vue new file mode 100644 index 0000000..d51739b --- /dev/null +++ b/resources/[core]/esx_identity/web/src/components/Identity.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/resources/[core]/esx_identity/web/src/main.js b/resources/[core]/esx_identity/web/src/main.js new file mode 100644 index 0000000..5a6e246 --- /dev/null +++ b/resources/[core]/esx_identity/web/src/main.js @@ -0,0 +1,5 @@ +import { createApp } from 'vue' +import './style.css' +import App from './App.vue' + +createApp(App).mount('#app') \ No newline at end of file diff --git a/resources/[core]/esx_identity/web/src/style.css b/resources/[core]/esx_identity/web/src/style.css new file mode 100644 index 0000000..17023ff --- /dev/null +++ b/resources/[core]/esx_identity/web/src/style.css @@ -0,0 +1,195 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); +/* body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} */ + +/* REMOVE LATER, ADD SCSS */ + +body { + font-family: sans-serif; + overflow: hidden; + background-color: transparent; +} + +.none { + display: none; +} + +.dialog { + width: 477px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: #080808; + border-radius: 8px; + border: none; + color: #ffffff; + font-family: "Poppins", sans-serif; +} + +.dialog__header { + background-color: #040404; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + padding: 20px; + text-align: center; +} + +.dialog__header h1 { + font-weight: 700; + margin-bottom: 0; + font-size: 30px; +} + +.dialog__header span { + color: #FD9800; +} + +.dialog__body { + padding-block: 20px; + padding-inline: 65px; +} + +.dialog__body-hint { + text-align: center; + margin-bottom: 20px; +} + +.dialog__body-form { + display: flex; + flex-direction: column; + gap: 35px; + font-weight: 600; + font-size: 15px; +} + +.dialog__form-submit { + border:none; + background-color: #FD9800; + color: #fff; + font-size: 18px; + font-weight:bold; + border-radius: 4px; + padding-block: 5px; +} + +.dialog__form-submit i { + margin-right: 5px; +} + +.dialog__form-group { + display: flex; + align-items: center; + justify-content: space-between; + gap: 30px; + background-color: #040404; + position: relative; +} + +.dialog__form-group--radio { + gap: 0; +} + +.dialog__form-group label { + flex-grow: 1; /* Label will expand to fill available space */ + flex-shrink: 1; /* Allows the label to shrink if necessary */ + padding-inline: 20px; /* Horizontal padding */ +} + +.dialog__form-group input { + background-color: transparent; + border: none; + height: 30px; + width: 180px; /* Fixed width for input */ + flex-shrink: 0; /* Prevent input from shrinking */ + color: white; +} + + +.dialog__form-group input:focus { + background-color: rgba(15, 15, 15, 0.9); + border: none; + border-radius: 5px; + color: #ffffff; + outline: none; + box-shadow: none; +} + +.dialog__form-validation { + position: relative; +} + +.dialog__form-validation i { + position: absolute; + right: 10px; + top: 50%; + transform: translate(0, -50%); +} + +.dialog__form-radio { + display: flex; + align-items: center; +} + +.dialog__form-radio input { + display: none; +} + +.dialog__form-radio label { + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; +} + +.dialog__form-radio input + label { + height: 30px; + display: flex; + align-items: center; +} + +.dialog__form-radio input:checked + label { + color: #30A1FD; + height: 30px; +} + +.dialog__form-radio input:not(:checked) + label { + color: #242424; + height: 30px; +} + +.dialog__form-message { + position: absolute; + top: 35px; + right: 0; + font-size: 9px; +} + +.dialog__form-message--error { + color: #733838; +} + +#male:checked + label { + color: #30A1FD; /* Blue color */ +} + +/* For the female radio button */ +#female:checked + label { + color: #FF69B4; /* Pink color */ +} + +::placeholder { + color: #242424; + font-weight: 600; +} + +input[type="date"]::-webkit-inner-spin-button, +input[type="date"]::-webkit-calendar-picker-indicator { + display: none; + -webkit-appearance: none; +} \ No newline at end of file diff --git a/resources/[core]/esx_identity/web/vite.config.js b/resources/[core]/esx_identity/web/vite.config.js new file mode 100644 index 0000000..4b14147 --- /dev/null +++ b/resources/[core]/esx_identity/web/vite.config.js @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + base: './', + plugins: [vue()], +}) diff --git a/resources/[core]/esx_inventory/client/main.lua b/resources/[core]/esx_inventory/client/main.lua new file mode 100644 index 0000000..3fd8478 --- /dev/null +++ b/resources/[core]/esx_inventory/client/main.lua @@ -0,0 +1,233 @@ +---@class InventoryElement +---@field type "item_account" | "item_standard" | "item_weapon" +---@field label string +---@field icon string +---@field count number +---@field value string +---@field usable boolean +---@field rare boolean +---@field canRemove boolean +---@field unselectable boolean? +---@field ammo number? +---@field canGiveAmmo boolean? + +---@alias InventoryAction "use" | "give" | "remove" | "give_ammo" | "return" + +if not ESX.GetConfig("EnableDefaultInventory") then + error("ESX Default Inventory is disabled in config, please enable it to use this resource.") +end + +-------------------------------- +-- Inventory Element Builders -- +-------------------------------- + +---@param elements InventoryElement[] +local function appendAccounts(elements) + for i = 1, #(ESX.PlayerData.accounts) do + local account = ESX.PlayerData.accounts[i] + if account.money > 0 then + local formattedMoney = TranslateCap("locale_currency", ESX.Math.GroupDigits(account.money)) + local canDrop = account.name ~= "bank" + elements[#elements + 1] = { + type = "item_account", + label = ('%s: %s'):format(account.label, formattedMoney), + icon = "fas fa-money-bill-wave", + count = account.money, + value = account.name, + usable = false, + rare = false, + canRemove = canDrop + } + end + end +end + +---@param elements InventoryElement[] +---@return number +local function appendItems(elements) + local weight = 0 + for i = 1, #ESX.PlayerData.inventory do + local item = ESX.PlayerData.inventory[i] + if item.count > 0 then + weight = weight + (item.weight * item.count) + elements[#elements + 1] = { + type = "item_standard", + label = ("%s x%s"):format(item.label, item.count), + icon = "fas fa-box", + count = item.count, + value = item.name, + usable = item.usable, + rare = item.rare, + canRemove = item.canRemove + } + end + end + + return weight +end + +---@param elements InventoryElement[] +---@return number +local function appendLoadout(elements) + local weight = 0 + local playerPed = ESX.PlayerData.ped + + for i = 1, #ESX.PlayerData.loadout do + local weapon = ESX.PlayerData.loadout[i] + local weaponHash = joaat(weapon.name) + local ammo = GetAmmoInPedWeapon(playerPed, weaponHash) + local label = weapon.ammo and ("%s - %s %s"):format(weapon.label, weapon.ammo, TranslateCap("ammo_rounds")) or weapon.label + elements[#elements + 1] = { + type = "item_weapon", + label = label, + icon = "fas fa-gun", + count = 1, + value = weapon.name, + usable = false, + rare = false, + ammo = ammo, + canGiveAmmo = (weapon.ammo ~= nil), + canRemove = true + } + end + + return weight +end + +---@return InventoryElement[], number +local function buildInventoryElements() + local elements = {} ---@type InventoryElement[] + local totalWeight = 0 + appendAccounts(elements) + totalWeight += appendItems(elements) + totalWeight += appendLoadout(elements) + ---@diagnostic disable-next-line: missing-fields + elements[#elements + 1] = { + label = "Current Weight: " .. totalWeight, + icon = "fas fa-box", + usable = false + } + return elements, totalWeight +end + +--------------------------------- +-- Item Action Menu & Handling -- +--------------------------------- + +---@param selected InventoryElement +---@param playerNearby boolean +---@return table +local function buildItemActionMenu(selected, playerNearby) + local elements2 = {} + if selected.usable then + elements2[#elements2 + 1] = { action = "use", label = TranslateCap("use"), icon = "fas fa-utensils", type = selected.type, value = selected.value } + end + if selected.canRemove then + if playerNearby then + elements2[#elements2 + 1] = { action = "give", label = TranslateCap("give"), icon = "fas fa-hands", type = selected.type, value = selected.value } + end + elements2[#elements2 + 1] = { action = "remove", label = TranslateCap("remove"), icon = "fas fa-trash", type = selected.type, value = selected.value } + end + if selected.type == "item_weapon" and selected.canGiveAmmo and selected.ammo > 0 and playerNearby then + elements2[#elements2 + 1] = { action = "give_ammo", label = TranslateCap("giveammo"), icon = "fas fa-gun", type = selected.type, value = selected.value } + end + elements2[#elements2 + 1] = { action = "return", label = TranslateCap("return"), icon = "fas fa-arrow-left", disableRightArrow = true } + return elements2 +end + +---@param title string +---@param maxCount number +---@return number? +local function openQuantityDialog(title, maxCount) + local p = promise:new() + ESX.UI.Menu.Open("dialog", ESX.currentResourceName, "esx_inventory_quantity", { + title = title + }, function(data, menu) + local qty = tonumber(data.value) + if not qty or qty <= 0 or qty > maxCount then + ESX.ShowNotification(TranslateCap("amount_invalid")) + p:resolve(nil) + else + menu.close() + p:resolve(qty) + end + end, function(_, menu) + menu.close() + p:resolve(nil) + end) + + return Citizen.Await(p) +end + +---@param action InventoryAction +---@param selected InventoryElement +---@param closestPlayer number +local function handleInventoryAction(action, selected, closestPlayer) + local itemType, itemName, playerPed = selected.type, selected.value, ESX.PlayerData.ped + if action == "give" then + local qty = openQuantityDialog(TranslateCap("amount"), selected.count) + if not qty then return end + TriggerServerEvent("esx:giveInventoryItem", GetPlayerServerId(closestPlayer), itemType, itemName, qty) + elseif action == "remove" then + local qty = openQuantityDialog(TranslateCap("amount"), selected.count) + if not qty then return end + TriggerServerEvent("esx:removeInventoryItem", itemType, itemName, qty) + elseif action == "use" then + TriggerServerEvent("esx:useItem", itemName) + elseif action == "give_ammo" then + local pedAmmo = GetAmmoInPedWeapon(playerPed, joaat(itemName)) + local qty = openQuantityDialog(TranslateCap("amount"), pedAmmo) + if not qty then return end + TriggerServerEvent("esx:giveInventoryItem", GetPlayerServerId(closestPlayer), "item_ammo", itemName, qty) + end +end + +---------------------- +-- Main Inventory UI -- +---------------------- + +local function showInventory() + local elements, totalWeight = buildInventoryElements() + ESX.UI.Menu.Open("default", ESX.currentResourceName, "esx_inventory_main", { + title = TranslateCap("inventory", totalWeight, ESX.PlayerData.maxWeight), + elements = elements, + }, function(data, menu) + local selected = data.current --[[@as InventoryElement]] + if selected.unselectable then return end + + local closestPlayer, dist = ESX.Game.GetClosestPlayer() + local playerNearby = closestPlayer ~= -1 and dist <= 3.0 + + ESX.UI.Menu.Open("default", ESX.currentResourceName, "esx_inventory_actions", { + title = selected.label, + elements = buildItemActionMenu(selected, playerNearby), + }, function(data2, menu2) + local action = data2.current.action + if action == "return" then + menu2.close() + return + end + handleInventoryAction(action, selected, closestPlayer) + end, function(_, menu2) menu2.close() end) + end, function(_, menu) menu.close() end) +end +exports("ShowInventory", showInventory) + +ESX.RegisterInput("showinv", TranslateCap("keymap_showinventory"), "keyboard", "F2", function() + if not ESX.PlayerData.dead then + showInventory() + end +end) + +local function refreshInventory() + if not ESX.UI.Menu.IsOpen("default", ESX.currentResourceName, "esx_inventory_main") and + not ESX.UI.Menu.IsOpen("default", ESX.currentResourceName, "esx_inventory_actions") and + not ESX.UI.Menu.IsOpen("dialog", ESX.currentResourceName, "esx_inventory_quantity") then + return + end + Citizen.Wait(0) + ESX.UI.Menu.CloseAll() + showInventory() +end +RegisterNetEvent("esx:addInventoryItem", refreshInventory) +RegisterNetEvent("esx:removeInventoryItem", refreshInventory) diff --git a/resources/[core]/esx_inventory/config/main.lua b/resources/[core]/esx_inventory/config/main.lua new file mode 100644 index 0000000..2b9a476 --- /dev/null +++ b/resources/[core]/esx_inventory/config/main.lua @@ -0,0 +1,3 @@ +Config = { + Locale = GetConvar("esx:locale", "en"), +} diff --git a/resources/[core]/esx_inventory/fxmanifest.lua b/resources/[core]/esx_inventory/fxmanifest.lua new file mode 100644 index 0000000..672a87a --- /dev/null +++ b/resources/[core]/esx_inventory/fxmanifest.lua @@ -0,0 +1,21 @@ +fx_version "cerulean" + +game "gta5" +description "Inventory for the ESX framework" +lua54 "yes" +use_fxv2_oal "yes" +version '1.13.5' + +shared_scripts { + "/config/main.lua", + "@es_extended/imports.lua", + "@es_extended/locale.lua", +} + +client_scripts { + "/client/main.lua", +} + +files { + "/locales/*.lua" +} diff --git a/resources/[core]/esx_inventory/locales/ar.lua b/resources/[core]/esx_inventory/locales/ar.lua new file mode 100644 index 0000000..6ffa6c0 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/ar.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "الحقيبة ( الوزن %s / %s )", + ["use"] = "استخدام", + ["give"] = "إعطاء", + ["remove"] = "رمي", + ["return"] = "رجوع", + ["give_to"] = "إعطاء إلى", + ["amount"] = "الكمية", + ["giveammo"] = "إعطاء ذخيرة", + ["amountammo"] = "عدد الطلقات", + ["noammo"] = "لا يوجد ما يكفي!", + ["gave_item"] = "تم إعطاء %sx %s إلى %s", + ["received_item"] = "استلمت %sx %s من %s", + ["gave_weapon"] = "تم إعطاء %s إلى %s", + ["gave_weapon_ammo"] = "تم إعطاء ~o~%sx %s لسلاح %s إلى %s", + ["gave_weapon_withammo"] = "تم إعطاء %s مع ~o~%sx %s إلى %s", + ["gave_weapon_hasalready"] = "%s لديه بالفعل %s", + ["gave_weapon_noweapon"] = "%s لا يملك هذا السلاح", + ["received_weapon"] = "استلمت %s من %s", + ["received_weapon_ammo"] = "استلمت ~o~%sx %s لسلاحك %s من %s", + ["received_weapon_withammo"] = "استلمت %s مع ~o~%sx %s من %s", + ["received_weapon_hasalready"] = "%s حاول أن يعطيك %s، لكنك تملك هذا السلاح بالفعل", + ["received_weapon_noweapon"] = "%s حاول أن يعطيك ذخيرة لسلاح %s، لكنك لا تملك هذا السلاح", + ["gave_account_money"] = "تم إعطاء $%s (%s) إلى %s", + ["received_account_money"] = "استلمت $%s (%s) من %s", + ["amount_invalid"] = "كمية غير صالحة", + ["players_nearby"] = "لا يوجد لاعبين قريبين", + ["ex_inv_lim"] = "لا يمكن تنفيذ العملية، الوزن تجاوز الحد %s", + ["imp_invalid_quantity"] = "لا يمكن تنفيذ العملية، الكمية غير صالحة", + ["imp_invalid_amount"] = "لا يمكن تنفيذ العملية، المبلغ غير صالح", + ["threw_standard"] = "تم رمي %sx %s", + ["threw_account"] = "تم رمي $%s %s", + ["threw_weapon"] = "تم رمي %s", + ["threw_weapon_ammo"] = "تم رمي %s مع ~o~%sx %s", + ["threw_weapon_already"] = "لديك هذا السلاح بالفعل", + ["threw_cannot_pickup"] = "الحقيبة ممتلئ، لا يمكنك الالتقاط!", + ["threw_pickup_prompt"] = "اضغط E للالتقاط", + ["keymap_showinventory"] = "فتح الحقيبة", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "طلقات" +} diff --git a/resources/[core]/esx_inventory/locales/cs.lua b/resources/[core]/esx_inventory/locales/cs.lua new file mode 100644 index 0000000..039e8ec --- /dev/null +++ b/resources/[core]/esx_inventory/locales/cs.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventář ( Váha %s / %s )", + ["use"] = "Použít", + ["give"] = "Darovat", + ["remove"] = "Odhodit", + ["return"] = "Vrátit", + ["give_to"] = "Darováno", + ["amount"] = "Počet", + ["giveammo"] = "Podat náboje", + ["amountammo"] = "Počet nábojů", + ["noammo"] = "Nedostatek!", + ["gave_item"] = "Daroval %sx %s pro %s", + ["received_item"] = "Získáno %sx %s od %s", + ["gave_weapon"] = "Předání %s pro %s", + ["gave_weapon_ammo"] = "Darování ~o~%sx %s do %s pro %s", + ["gave_weapon_withammo"] = "Darování %s s ~o~%sx %s pro %s", + ["gave_weapon_hasalready"] = "%s již vlastní %s", + ["gave_weapon_noweapon"] = "%s nemá tuto zbraň", + ["received_weapon"] = "Obdrženo %s od %s", + ["received_weapon_ammo"] = "Obdrženo ~o~%sx %s pro zbraň %s od %s", + ["received_weapon_withammo"] = "Obdrženo %s s ~o~%sx %s od %s", + ["received_weapon_hasalready"] = "%s se snažil darovat %s, ale již tuto zbraň máš", + ["received_weapon_noweapon"] = "%s se snažil ti dát náboje %s, ale nemáš potřebnou zbrań", + ["gave_account_money"] = "Darováno $%s (%s) pro %s", + ["received_account_money"] = "Získáno $%s (%s) od %s", + ["amount_invalid"] = "Špatné množství", + ["players_nearby"] = "Žádný hráč není poblíž", + ["ex_inv_lim"] = "Nelze sebrat,protože máš plné kapsy %s", + ["imp_invalid_quantity"] = "Neplatné množství", + ["imp_invalid_amount"] = "Nelze provést, neplatné množství", + ["threw_standard"] = "Zahozeno %sx %s", + ["threw_account"] = "Zahozeno $%s %s", + ["threw_weapon"] = "Zahozeno %s", + ["threw_weapon_ammo"] = "Zahozeno %s s ~o~%sx %s", + ["threw_weapon_already"] = "Již vlastníš tuto zbraň", + ["threw_cannot_pickup"] = "Kapsy máš plné, nemůžeš sebrat!", + ["threw_pickup_prompt"] = "Zmáčkni E pro sebrání!", + ["keymap_showinventory"] = "Otevřít inventář", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/de.lua b/resources/[core]/esx_inventory/locales/de.lua new file mode 100644 index 0000000..ae90a16 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/de.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventar ( Gewicht %s / %s )", + ["use"] = "Benutzen", + ["give"] = "Geben", + ["remove"] = "Entsorgen", + ["return"] = "Zurück", + ["give_to"] = "Geben an", + ["amount"] = "Anzahl", + ["giveammo"] = "Munition geben", + ["amountammo"] = "Munitions Anzahl", + ["noammo"] = "Nicht Genug!", + ["gave_item"] = "Du gibst %sx %s an %s", + ["received_item"] = "Du bekommst %sx %s von %s", + ["gave_weapon"] = "Du gibst %s an %s", + ["gave_weapon_ammo"] = "Du gibst ~o~%sx %s für %s an %s", + ["gave_weapon_withammo"] = "Du gibst %s mit ~o~%sx %s an %s", + ["gave_weapon_hasalready"] = "%s hat bereits %s", + ["gave_weapon_noweapon"] = "%s hat diese Waffe nicht", + ["received_weapon"] = "Du bekommst %s von %s", + ["received_weapon_ammo"] = "Du bekommst ~o~%sx %s für deine %s von %s", + ["received_weapon_withammo"] = "Du bekommst %s mit ~o~%sx %s von %s", + ["received_weapon_hasalready"] = "%s hat versucht dir eine %s zu geben, jedoch hast du diese Waffe bereits!", + ["received_weapon_noweapon"] = "%s hat versucht dir Munition für eine %s zu geben, jedoch hast du diese Waffe nicht!", + ["gave_account_money"] = "Du gibst %s€ (%s) an %s", + ["received_account_money"] = "Du bekommst %s€ (%s) von %s", + ["amount_invalid"] = "Ungültige Anzahl", + ["players_nearby"] = "Keine Personen in der Nähe!", + ["ex_inv_lim"] = "Du kannst diese Aktion nicht ausführen!, Inventarlimit für %s überschritten.", + ["imp_invalid_quantity"] = "Du kannst diese Aktion nicht ausführen!, Ungültige Anzahl!", + ["imp_invalid_amount"] = "Du kannst diese Aktion nicht ausführen!, Ungültige Anzahl", + ["threw_standard"] = "Du entsorgst %sx %s", + ["threw_account"] = "Du Entsorgst %s€ %s", + ["threw_weapon"] = "Du entsorgst %s", + ["threw_weapon_ammo"] = "Du entsorgst %s mit ~o~%sx %s", + ["threw_weapon_already"] = "Du hast diese Waffe bereits!", + ["threw_cannot_pickup"] = "Inventar ist voll! Du kannst dies nicht aufheben", + ["threw_pickup_prompt"] = "Drücke [E] zum aufheben", + ["keymap_showinventory"] = "Inventar Anzeigen", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/el.lua b/resources/[core]/esx_inventory/locales/el.lua new file mode 100644 index 0000000..75acbc5 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/el.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Αποθήκη ( Βάρος %s / %s )", + ["use"] = "Χρήση", + ["give"] = "Δώσε", + ["remove"] = "Πέτα", + ["return"] = "Επιστροφή", + ["give_to"] = "Δώσε σε", + ["amount"] = "Ποσότητα", + ["giveammo"] = "Δώσε σφαίρες", + ["amountammo"] = "Ποσότητα σφαιρών", + ["noammo"] = "Δεν υπάρχουν αρκετές σφαίρες!", + ["gave_item"] = "Δώσατε %sx %s στον/στην %s", + ["received_item"] = "Λάβατε %sx %s από τον/την %s", + ["gave_weapon"] = "Δίνετε %s στον/στην %s", + ["gave_weapon_ammo"] = "Δίνετε ~o~%sx %s για %s στον/στην %s", + ["gave_weapon_withammo"] = "Δίνετε %s με ~o~%sx %s στον/στην %s", + ["gave_weapon_hasalready"] = "Ο/Η %s έχει ήδη ένα %s", + ["gave_weapon_noweapon"] = "Ο/Η %s δεν έχει αυτό το όπλο", + ["received_weapon"] = "Λάβατε %s από τον/την %s", + ["received_weapon_ammo"] = "Λάβατε ~o~%sx %s για το %s από τον/την %s", + ["received_weapon_withammo"] = "Λάβατε %s για ~o~%sx %s από τον/την %s", + ["received_weapon_hasalready"] = "Ο/Η %s προσπάθησε να σας δώσει ένα %s, αλλά το έχετε ήδη", + ["received_weapon_noweapon"] = "Ο/Η %s προσπάθησε να σας δώσει σφαίρες για το %s, αλλά δεν έχετε αυτό το όπλο", + ["gave_account_money"] = "Δίνετε $%s (%s) στον/στην %s", + ["received_account_money"] = "Λάβατε $%s (%s) από τον/την %s", + ["amount_invalid"] = "Μη έγκυρη ποσότητα", + ["players_nearby"] = "Δεν υπάρχουν κοντινοί παίκτες", + ["ex_inv_lim"] = "Δεν είναι δυνατή η ενέργεια, υπέρβαση του μέγιστου βάρους των %s", + ["imp_invalid_quantity"] = "Δεν είναι δυνατή η ενέργεια, η ποσότητα δεν είναι έγκυρη", + ["imp_invalid_amount"] = "Δεν είναι δυνατή η ενέργεια, το ποσό δεν είναι έγκυρο", + ["threw_standard"] = "Ρίχνοντας %sx %s", + ["threw_account"] = "Ρίχνοντας $%s %s", + ["threw_weapon"] = "Ρίχνοντας %s", + ["threw_weapon_ammo"] = "Ρίχνοντας %s με ~o~%sx %s", + ["threw_weapon_already"] = "Ήδη έχετε αυτό το όπλο", + ["threw_cannot_pickup"] = "Η αποθήκη είναι γεμάτη, δεν μπορείτε να σηκώσετε!", + ["threw_pickup_prompt"] = "Πατήστε E για να σηκώσετε", + ["keymap_showinventory"] = "Εμφάνιση Αποθήκης", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/en.lua b/resources/[core]/esx_inventory/locales/en.lua new file mode 100644 index 0000000..926fd4b --- /dev/null +++ b/resources/[core]/esx_inventory/locales/en.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventory ( Weight %s / %s )", + ["use"] = "Use", + ["give"] = "Give", + ["remove"] = "Throw", + ["return"] = "Return", + ["give_to"] = "Give to", + ["amount"] = "Amount", + ["giveammo"] = "Give ammo", + ["amountammo"] = "Ammo Amount", + ["noammo"] = "Not Enough!", + ["gave_item"] = "Giving %sx %s to %s", + ["received_item"] = "Received %sx %s from %s", + ["gave_weapon"] = "Giving %s to %s", + ["gave_weapon_ammo"] = "Giving ~o~%sx %s for %s to %s", + ["gave_weapon_withammo"] = "Giving %s with ~o~%sx %s to %s", + ["gave_weapon_hasalready"] = "%s already has a %s", + ["gave_weapon_noweapon"] = "%s does not have that weapon", + ["received_weapon"] = "Received %s from %s", + ["received_weapon_ammo"] = "Received ~o~%sx %s for your %s from %s", + ["received_weapon_withammo"] = "Received %s with ~o~%sx %s from %s", + ["received_weapon_hasalready"] = "%s has attempted to give you a %s, but you already this weapon", + ["received_weapon_noweapon"] = "%s has attempted to give you ammo for a %s, but you do not have this weapon", + ["gave_account_money"] = "Giving $%s (%s) to %s", + ["received_account_money"] = "Received $%s (%s) from %s", + ["amount_invalid"] = "Invalid quantity", + ["players_nearby"] = "No nearby Players", + ["ex_inv_lim"] = "Cannot perfom action,exceeding max weight of %s", + ["imp_invalid_quantity"] = "Cannot perfom action, the quantity is invalid", + ["imp_invalid_amount"] = "Cannot perfom action, the amount is invalid", + ["threw_standard"] = "Throwing %sx %s", + ["threw_account"] = "Throwing $%s %s", + ["threw_weapon"] = "Throwing %s", + ["threw_weapon_ammo"] = "Throwing %s with ~o~%sx %s", + ["threw_weapon_already"] = "You already have this weapon", + ["threw_cannot_pickup"] = "Inventory is full, Cannot Pickup!", + ["threw_pickup_prompt"] = "Press E to Pickup", + ["keymap_showinventory"] = "Show Inventory", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/es.lua b/resources/[core]/esx_inventory/locales/es.lua new file mode 100644 index 0000000..f0e451f --- /dev/null +++ b/resources/[core]/esx_inventory/locales/es.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventario (Peso %s / %s)", + ["use"] = "Usar", + ["give"] = "Dar", + ["remove"] = "Tirar", + ["return"] = "Devolver", + ["give_to"] = "Dar a", + ["amount"] = "Cantidad", + ["giveammo"] = "Dar munición", + ["amountammo"] = "Cantidad de munición", + ["noammo"] = "¡Insuficiente!", + ["gave_item"] = "Dando %sx %s a %s", + ["received_item"] = "Recibido %sx %s de %s", + ["gave_weapon"] = "Dando %s a %s", + ["gave_weapon_ammo"] = "Dando ~o~%sx %s para %s a %s", + ["gave_weapon_withammo"] = "Dando %s con ~o~%sx %s a %s", + ["gave_weapon_hasalready"] = "%s ya tiene un %s", + ["gave_weapon_noweapon"] = "%s no tiene esa arma", + ["received_weapon"] = "Recibido %s de %s", + ["received_weapon_ammo"] = "Recibido ~o~%sx %s para tu %s de %s", + ["received_weapon_withammo"] = "Recibido %s con ~o~%sx %s de %s", + ["received_weapon_hasalready"] = "%s ha intentado darte un %s, pero ya tienes esta arma", + ["received_weapon_noweapon"] = "%s ha intentado darte munición para un %s, pero no tienes esta arma", + ["gave_account_money"] = "Dando $%s (%s) a %s", + ["received_account_money"] = "Recibido $%s (%s) de %s", + ["amount_invalid"] = "Cantidad inválida", + ["players_nearby"] = "No hay jugadores cerca", + ["ex_inv_lim"] = "No se puede realizar la acción, se excede el peso máximo de %s", + ["imp_invalid_quantity"] = "No se puede realizar la acción, la cantidad es inválida", + ["imp_invalid_amount"] = "No se puede realizar la acción, la cantidad es inválida", + ["threw_standard"] = "Tirando %sx %s", + ["threw_account"] = "Tirando $%s %s", + ["threw_weapon"] = "Tirando %s", + ["threw_weapon_ammo"] = "Tirando %s con ~o~%sx %s", + ["threw_weapon_already"] = "Ya tienes esta arma", + ["threw_cannot_pickup"] = "¡Inventario lleno, no se puede recoger!", + ["threw_pickup_prompt"] = "Pulsa E para recoger", + ["keymap_showinventory"] = "Mostrar inventario", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/fi.lua b/resources/[core]/esx_inventory/locales/fi.lua new file mode 100644 index 0000000..2f2b85a --- /dev/null +++ b/resources/[core]/esx_inventory/locales/fi.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Reppu %s / %s", + ["use"] = "Käytä", + ["give"] = "Anna", + ["remove"] = "Poista", + ["return"] = "Takaisin", + ["give_to"] = "Anna henkilölle", + ["amount"] = "Määrä", + ["giveammo"] = "Anna ammuksia", + ["amountammo"] = "Ammusten määrä", + ["noammo"] = "Sinulla ei ole ammuksia!", + ["gave_item"] = "Sinä annoit %sx %s henkilölle %s", + ["received_item"] = "Sinä sait %sx %s henkilöltä %s", + ["gave_weapon"] = "Sinä annoit 1x %s henkilölle %s", + ["gave_weapon_ammo"] = "Annoit ~o~%sx %s kohteelle %s henkilölle %s", + ["gave_weapon_withammo"] = "Sinä annoit 1x %s ammuksella ~o~%sx %s henkilölle %s", + ["gave_weapon_hasalready"] = "%s omistaa jo %s", + ["gave_weapon_noweapon"] = "%s ei ole kyseistä asetta", + ["received_weapon"] = "Vastaanotit 1x %s henkilöltä %s", + ["received_weapon_ammo"] = "Sinä sait ~o~%sx %s sinun %s varten henkilöltä %s", + ["received_weapon_withammo"] = "Sinä sait 1x %s ammuksella ~o~%sx %s henkilöltä %s", + ["received_weapon_hasalready"] = "%s yritti antaa sinulle %s, mutta sinulla on jo sellainen", + ["received_weapon_noweapon"] = "%s yritti antaa sinulle ammuksia %s:lle, mutta sinulla ei ole sellaista", + ["gave_account_money"] = "Sinä annoit $%s (%s) henkilölle %s", + ["received_account_money"] = "Sinä sait $%s (%s) henkilöltä %s", + ["amount_invalid"] = "Virheellinen määrä", + ["players_nearby"] = "Ei pelaajia lähettyvillä", + ["ex_inv_lim"] = "Toiminto mahdoton, reppu alkaa olla täysi %s", + ["imp_invalid_quantity"] = "Toiminto mahdoton, virheellinen määrä", + ["imp_invalid_amount"] = "Toiminto mahdoton, virhellinen summa", + ["threw_standard"] = "Sinä heitit %sx %s", + ["threw_account"] = "Sinä heitit $%s %s", + ["threw_weapon"] = "Sinä heitit 1x %s", + ["threw_weapon_ammo"] = "Heitit 1x %s ammuksella ~o~%sx %s", + ["threw_weapon_already"] = "Sinulla on jo sama ase", + ["threw_cannot_pickup"] = "Et voi kerätä sitä, koska reppusi on täynnä", + ["threw_pickup_prompt"] = "Paina E kerätäksesi", + ["keymap_showinventory"] = "Avaa reppu", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/fr.lua b/resources/[core]/esx_inventory/locales/fr.lua new file mode 100644 index 0000000..a267274 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/fr.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventaire ( Poids %s / %s )", + ["use"] = "Utiliser", + ["give"] = "Donner", + ["remove"] = "Jeter", + ["return"] = "Retour", + ["give_to"] = "Donner à", + ["amount"] = "Quantité", + ["giveammo"] = "Donner des munitions", + ["amountammo"] = "Nombre de munitions", + ["noammo"] = "Vous n'avez pas autant de munitions!", + ["gave_item"] = "Vous avez donné %sx %s à %s", + ["received_item"] = "Vous avez reçu %sx %s de %s", + ["gave_weapon"] = "Vous avez donné 1x %s à %s", + ["gave_weapon_ammo"] = "Vous avez donné ~o~%sx %s pour %s à %s", + ["gave_weapon_withammo"] = "Vous avez donné 1x %s avec ~o~%sx %s à %s", + ["gave_weapon_hasalready"] = "%s a déjà 1x %s", + ["gave_weapon_noweapon"] = "%s n'a pas cette arme", + ["received_weapon"] = "Vous avez reçu 1x %s de %s", + ["received_weapon_ammo"] = "Vous avez reçu ~o~%sx %s pour votre %s de %s", + ["received_weapon_withammo"] = "Vous avez reçu 1x %s avec ~o~%sx %s de %s", + ["received_weapon_hasalready"] = "%s a tenté de vous donner 1x %s, mais vous en aviez déjà un exemplaire", + ["received_weapon_noweapon"] = "%s a tenté de vous donner des munitions pour %s, mais vous n'avez pas cette arme", + ["gave_account_money"] = "Vous avez donné $%s (%s) à %s", + ["received_account_money"] = "Vous avez reçu $%s (%s) de %s", + ["amount_invalid"] = "Le montant est invalide", + ["players_nearby"] = "Aucun joueur n'est à proximité", + ["ex_inv_lim"] = "Action impossible, dépassement du poids maximum de %s", + ["imp_invalid_quantity"] = "Action impossible, la quantité est invalide", + ["imp_invalid_amount"] = "Action impossible, le montant est invalide", + ["threw_standard"] = "Vous avez jeté %sx %s", + ["threw_account"] = "Vous avez jeté $%s %s", + ["threw_weapon"] = "Vous avez jeté 1x %s", + ["threw_weapon_ammo"] = "Vous avez jeté 1x %s avec ~o~%sx %s", + ["threw_weapon_already"] = "Vous avez déjà cette arme", + ["threw_cannot_pickup"] = "Votre inventaire est plein, vous ne pouvez donc pas ramasser cela!", + ["threw_pickup_prompt"] = "Appuyez sur E pour ramasser", + ["keymap_showinventory"] = "Afficher l'inventaire", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/he.lua b/resources/[core]/esx_inventory/locales/he.lua new file mode 100644 index 0000000..cfa2206 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/he.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "מלאי ( משקל %s / %s )", + ["use"] = "השתמש", + ["give"] = "תן", + ["remove"] = "זרוק", + ["return"] = "חזור", + ["give_to"] = "תן ל", + ["amount"] = "כמות", + ["giveammo"] = "תן תחמושת", + ["amountammo"] = "כמות תחמושת", + ["noammo"] = "לא מספיק!", + ["gave_item"] = "ניתן %sx %s ל %s", + ["received_item"] = "קיבלת %sx %s מ %s", + ["gave_weapon"] = "ניתן %s ל %s", + ["gave_weapon_ammo"] = "ניתן ~o~%sx %s ל %s ל %s", + ["gave_weapon_withammo"] = "ניתן %s עם ~o~%sx %s ל %s", + ["gave_weapon_hasalready"] = "%s כבר יש לו %s", + ["gave_weapon_noweapon"] = "%s אין לו את הנשק הזה", + ["received_weapon"] = "קיבלת %s מ %s", + ["received_weapon_ammo"] = "קיבלת ~o~%sx %s ל %s שלך מ %s", + ["received_weapon_withammo"] = "קיבלת %s עם ~o~%sx %s מ %s", + ["received_weapon_hasalready"] = "%s ניסה לתת לך %s, אך יש לך כבר נשק זה", + ["received_weapon_noweapon"] = "%s ניסה לתת לך תחמושת ל %s, אך אין לך נשק זה", + ["gave_account_money"] = "ניתן $%s (%s) ל %s", + ["received_account_money"] = "קיבלת $%s (%s) מ %s", + ["amount_invalid"] = "כמות לא חוקית", + ["players_nearby"] = "אין שחקנים קרובים", + ["ex_inv_lim"] = "לא ניתן לבצע פעולה, חורג מהמשקל המרבי של %s", + ["imp_invalid_quantity"] = "לא ניתן לבצע פעולה, הכמות אינה חוקית", + ["imp_invalid_amount"] = "לא ניתן לבצע פעולה, הסכום אינו חוקי", + ["threw_standard"] = "זורק %sx %s", + ["threw_account"] = "זורק $%s %s", + ["threw_weapon"] = "זורק %s", + ["threw_weapon_ammo"] = "זורק %s עם ~o~%sx %s", + ["threw_weapon_already"] = "כבר יש לך נשק זה", + ["threw_cannot_pickup"] = "המלאי מלא, לא ניתן לאסוף!", + ["threw_pickup_prompt"] = "לחץ E כדי לאסוף", + ["keymap_showinventory"] = "הצג מלאי", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/hu.lua b/resources/[core]/esx_inventory/locales/hu.lua new file mode 100644 index 0000000..8b43983 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/hu.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventory ( Súly %s / %s )", + ["use"] = "Használ", + ["give"] = "Átad", + ["remove"] = "Eldob", + ["return"] = "Visszatérés", + ["give_to"] = "Adni valakinek", + ["amount"] = "Mennyiség", + ["giveammo"] = "Lőszer adás", + ["amountammo"] = "Lőszer mennyiség", + ["noammo"] = "Nincsen több lövedéked!", + ["gave_item"] = "Átadtál: %sx %s neki: %s", + ["received_item"] = "Kaptál: %sx %s töle: %s", + ["gave_weapon"] = "Átadtál: %s neki: %s", + ["gave_weapon_ammo"] = "Átadtál ~o~%sx %s %s neki: %s", + ["gave_weapon_withammo"] = "Átadtál %s ~o~%sx %s neki: %s", + ["gave_weapon_hasalready"] = "%s már rendelkezik %s", + ["gave_weapon_noweapon"] = "%s nincsen ilyen fegyere", + ["received_weapon"] = "Kaptál: %s töle: %s", + ["received_weapon_ammo"] = "Kaptál ~o~%sx %s %s töle: %s", + ["received_weapon_withammo"] = "Kaptál %s ~o~%sx %s töle: %s", + ["received_weapon_hasalready"] = "%s megpróbálta átadni a következöt: %s, nem már van rendelkezel egy ilyennel", + ["received_weapon_noweapon"] = "%s átakart adni %s, de nincsen ilyen fegyvered", + ["gave_account_money"] = "Átadtál: $%s (%s) neki: %s", + ["received_account_money"] = "Kaptál: $%s (%s) töle: %s", + ["amount_invalid"] = "Érvénytelen mennyiség", + ["players_nearby"] = "Nincsen játékos a közeledben", + ["ex_inv_lim"] = "Nincsen elég szabad helyed %s", + ["imp_invalid_quantity"] = "Érvénytelen mennyiség", + ["imp_invalid_amount"] = "Érvénytelen összeg", + ["threw_standard"] = "Kidobtál: %sx %s", + ["threw_account"] = "Kidobtál: $%s %s", + ["threw_weapon"] = "Kidobtál: %s", + ["threw_weapon_ammo"] = "Kidobtál: %s ~o~%sx %s", + ["threw_weapon_already"] = "Van már ilyen fegyvered", + ["threw_cannot_pickup"] = "Nincsen elég szabad helyed", + ["threw_pickup_prompt"] = "E hogy felvedd", + ["keymap_showinventory"] = "Leltár mutatása", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/id.lua b/resources/[core]/esx_inventory/locales/id.lua new file mode 100644 index 0000000..17e8182 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/id.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventaris ( Berat %s / %s )", + ["use"] = "Gunakan", + ["give"] = "Beri", + ["remove"] = "Buang", + ["return"] = "Kembali", + ["give_to"] = "Beri ke", + ["amount"] = "Jumlah", + ["giveammo"] = "Beri amunisi", + ["amountammo"] = "Jumlah Amunisi", + ["noammo"] = "Tidak cukup!", + ["gave_item"] = "Memberi %sx %s ke %s", + ["received_item"] = "Menerima %sx %s dari %s", + ["gave_weapon"] = "Memberi %s ke %s", + ["gave_weapon_ammo"] = "Memberi ~o~%sx %s untuk %s ke %s", + ["gave_weapon_withammo"] = "Memberi %s dengan ~o~%sx %s ke %s", + ["gave_weapon_hasalready"] = "%s sudah memiliki %s", + ["gave_weapon_noweapon"] = "%s tidak memiliki senjata tersebut", + ["received_weapon"] = "Menerima %s dari %s", + ["received_weapon_ammo"] = "Menerima ~o~%sx %s untuk %s Anda dari %s", + ["received_weapon_withammo"] = "Menerima %s dengan ~o~%sx %s dari %s", + ["received_weapon_hasalready"] = "%s mencoba memberimu %s, tapi kamu sudah memiliki senjata ini", + ["received_weapon_noweapon"] = "%s mencoba memberimu amunisi untuk %s, tapi kamu tidak memiliki senjata ini", + ["gave_account_money"] = "Memberi $%s (%s) ke %s", + ["received_account_money"] = "Menerima $%s (%s) dari %s", + ["amount_invalid"] = "Jumlah salah", + ["players_nearby"] = "Tidak ada Player di sekitar", + ["ex_inv_lim"] = "Tidak dapat melakukan aksi, melebihi batas berat dari %s", + ["imp_invalid_quantity"] = "Tidak dapat melakukan aksi, jumlah salah", + ["imp_invalid_amount"] = "Tidak dapat melakukan aksi, jumlah salah", + ["threw_standard"] = "Membuang %sx %s", + ["threw_account"] = "Membuang $%s %s", + ["threw_weapon"] = "Membuang %s", + ["threw_weapon_ammo"] = "Membuang %s dengan ~o~%sx %s", + ["threw_weapon_already"] = "Kamu sudah memiliki senjata ini", + ["threw_cannot_pickup"] = "Inventaris penuh, Tidak dapat mengambil!", + ["threw_pickup_prompt"] = "Tekan E untuk Mengambil", + ["keymap_showinventory"] = "Buka Inventaris", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/it.lua b/resources/[core]/esx_inventory/locales/it.lua new file mode 100644 index 0000000..fed46c2 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/it.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventario ( Peso %s / %s )", + ["use"] = "Usa", + ["give"] = "Dai", + ["remove"] = "Butta", + ["return"] = "Ritorna", + ["give_to"] = "Dai a", + ["amount"] = "Quantità", + ["giveammo"] = "Dai munizioni", + ["amountammo"] = "Quantità munizioni", + ["noammo"] = "Non abbastanza!", + ["gave_item"] = "Dando %sx %s a %s", + ["received_item"] = "Ricevuto %sx %s da %s", + ["gave_weapon"] = "Dando %s a %s", + ["gave_weapon_ammo"] = "Dando ~o~%sx %s for %s to %s", + ["gave_weapon_withammo"] = "Dando %s con ~o~%sx %s a %s", + ["gave_weapon_hasalready"] = "%s possiede già %s", + ["gave_weapon_noweapon"] = "%s non ha quell' arma", + ["received_weapon"] = "Ricevuto %s da %s", + ["received_weapon_ammo"] = "Ricevuto ~o~%sx %s per il tuo %s da %s", + ["received_weapon_withammo"] = "Ricevuto %s con ~o~%sx %s per %s", + ["received_weapon_hasalready"] = "%s ha tentato di darti %s, ma hai già l'arma", + ["received_weapon_noweapon"] = "%s ha tentato di darti munizioni per %s, ma non hai l'arma", + ["gave_account_money"] = "Dando $%s (%s) a %s", + ["received_account_money"] = "Ricevuto $%s (%s) da %s", + ["amount_invalid"] = "Quantità non valida", + ["players_nearby"] = "Nessun giocatore vicino", + ["ex_inv_lim"] = "Non puoi farlo, eccedi il peso di %s", + ["imp_invalid_quantity"] = "Non puoi farlo, quantità non valida", + ["imp_invalid_amount"] = "Non puoi farlo, importo non valido", + ["threw_standard"] = "Gettando %sx %s", + ["threw_account"] = "Gettando $%s %s", + ["threw_weapon"] = "Gettando %s", + ["threw_weapon_ammo"] = "Gettando %s con ~o~%sx %s", + ["threw_weapon_already"] = "Hai gia quest' arma", + ["threw_cannot_pickup"] = "Inventario pieno, non puoi raccogliere!", + ["threw_pickup_prompt"] = "Premi E per raccogliere", + ["keymap_showinventory"] = "Apri inventario", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/nl.lua b/resources/[core]/esx_inventory/locales/nl.lua new file mode 100644 index 0000000..dfc9e76 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/nl.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventaris ( Gewicht %s / %s )", + ["use"] = "Gebruik", + ["give"] = "Geef", + ["remove"] = "Gooi", + ["return"] = "Terug", + ["give_to"] = "Geef aan", + ["amount"] = "Aantal", + ["giveammo"] = "Geef munitie", + ["amountammo"] = "Hoeveelheid munitie", + ["noammo"] = "Niet genoeg munitie!", + ["gave_item"] = "%sx %s gegeven aan %s", + ["received_item"] = "%sx %s ontvangen van %s", + ["gave_weapon"] = "%s gegeven aan %s", + ["gave_weapon_ammo"] = "~o~%sx %s gegeven voor een %s aan %s", + ["gave_weapon_withammo"] = "%s gegeven met ~o~%sx %s aan %s", + ["gave_weapon_hasalready"] = "%s heeft al een %s", + ["gave_weapon_noweapon"] = "%s heeft dat wapen niet", + ["received_weapon"] = "%s ontvangen van %s", + ["received_weapon_ammo"] = "~o~%sx %s ontvangen voor je %s van %s", + ["received_weapon_withammo"] = "%s ontvangen met ~o~%sx %s van %s", + ["received_weapon_hasalready"] = "%s heeft geprobeerd je een %s te geven, maar je hebt dat wapen al.", + ["received_weapon_noweapon"] = "%s heeft geprobeerd je ammo te geven voor een %s, maar je hebt dit wapen niet", + ["gave_account_money"] = "€%s (%s) gegeven aan %s", + ["received_account_money"] = "€%s (%s) ontvangen van %s", + ["amount_invalid"] = "Ongeldige hoeveelheid", + ["players_nearby"] = "Geen spelers in de buurt", + ["ex_inv_lim"] = "Kan actie niet uitvoeren, overschrijdt max. gewicht van %s", + ["imp_invalid_quantity"] = "Kan actie niet uitvoeren, de hoeveelheid is ongeldig", + ["imp_invalid_amount"] = "Kan actie niet uitvoeren, het aantal is ongeldig", + ["threw_standard"] = "%sx %s weggegooid", + ["threw_account"] = "€%s %s weggegooid", + ["threw_weapon"] = "%s weggegooid", + ["threw_weapon_ammo"] = "%s met ~o~%sx %s weggegooid", + ["threw_weapon_already"] = "Je hebt dit wapen al !", + ["threw_cannot_pickup"] = "Inventaris is vol, je kan dit niet oppakken!", + ["threw_pickup_prompt"] = "Druk op E om op te pakken", + ["keymap_showinventory"] = "Laat inventaris zien", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/pl.lua b/resources/[core]/esx_inventory/locales/pl.lua new file mode 100644 index 0000000..be0ec27 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/pl.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "ekwipunek %s / %s", + ["use"] = "użyj", + ["give"] = "daj", + ["remove"] = "usuń", + ["return"] = "wróć", + ["give_to"] = "daj dla", + ["amount"] = "ilość", + ["giveammo"] = "daj amunicje", + ["amountammo"] = "ilość amunicji", + ["noammo"] = "nie posiadasz wystarczającej ilości amunicji!", + ["gave_item"] = "dałeś/aś %sx %s dla %s", + ["received_item"] = "otrzymałeś/aś %sx %s od %s", + ["gave_weapon"] = "dałeś/aś %s dla %s", + ["gave_weapon_ammo"] = "dałeś/aś ~o~%sx %s do %s dla %s", + ["gave_weapon_withammo"] = "dałeś/aś %s z ~o~%sx %s dla %s", + ["gave_weapon_hasalready"] = "%s już posiada %s", + ["gave_weapon_noweapon"] = "%s nie posiada tej broni", + ["received_weapon"] = "otrzymałeś/aś %s od %s", + ["received_weapon_ammo"] = "otrzymałeś/aś ~o~%sx %s do twojego %s od %s", + ["received_weapon_withammo"] = "otrzymałeś/aś %s z ~o~%sx %s od %s", + ["received_weapon_hasalready"] = "%s próbował/a przekazać ci %s, lecz już posiadasz jedno", + ["received_weapon_noweapon"] = "%s próbował/a przekazać ci amunicje do %s, lecz nie posiadasz tej broni", + ["gave_account_money"] = "dałeś/aś %s$ (%s) dla %s", + ["received_account_money"] = "otrzymałeś/aś %s$ (%s) od %s", + ["amount_invalid"] = "nieprawidłowa ilość", + ["players_nearby"] = "brak graczy w pobliżu", + ["ex_inv_lim"] = "akcja nie jest możliwa, nie możesz mieć więcej %s", + ["imp_invalid_quantity"] = "akcja jest niemożliwa, nieprawidłowa ilość", + ["imp_invalid_amount"] = "akcja jest niemożliwa, nieprawidłowa kwota", + ["threw_standard"] = "wyrzuciłeś/aś %sx %s", + ["threw_account"] = "wyrzuciłeś/aś $%s %s", + ["threw_weapon"] = "wyrzuciłeś/aś %s", + ["threw_weapon_ammo"] = "wyrzuciłeś/aś %s z ~o~%sx %s", + ["threw_weapon_already"] = "już posiadasz taką samą broń", + ["threw_cannot_pickup"] = "nie możesz tego podnieść, gdyż masz pełny ekwipunek!", + ["threw_pickup_prompt"] = "naciśnij E aby podnieść", + ["keymap_showinventory"] = "pokaż ekwipunek", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/sl.lua b/resources/[core]/esx_inventory/locales/sl.lua new file mode 100644 index 0000000..360c664 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/sl.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Shramba ( Teza %s / %s )", + ["use"] = "Uporabi", + ["give"] = "Daj", + ["remove"] = "Vrzi", + ["return"] = "Povratek", + ["give_to"] = "Daj", + ["amount"] = "Vsota", + ["giveammo"] = "Daj Strelivo", + ["amountammo"] = "Količina streliva", + ["noammo"] = "Ni dovolj!", + ["gave_item"] = "Dal si %sx %s k %s", + ["received_item"] = "Dobil si %sx %s od %s", + ["gave_weapon"] = "Dajanje %s do %s", + ["gave_weapon_ammo"] = "Dajanje ~o~%sx %s za %s do %s", + ["gave_weapon_withammo"] = "Dajanje %s z ~o~%sx %s do %s", + ["gave_weapon_hasalready"] = "%s ze ima %s", + ["gave_weapon_noweapon"] = "%s se nima tega orozja", + ["received_weapon"] = "Dobil si %s od %s", + ["received_weapon_ammo"] = "Dobil ~o~%sx %s za tvoj/o %s od %s", + ["received_weapon_withammo"] = "Dobil si %s z ~o~%sx %s od %s", + ["received_weapon_hasalready"] = "%s vam je poskušal dati %s, vendar že imate to orožje", + ["received_weapon_noweapon"] = "%s vam je poskušal dati strelivo za %s, vendar nimate tega orožja", + ["gave_account_money"] = "Dajanje $%s (%s) do %s", + ["received_account_money"] = "Dobil $%s (%s) od %s", + ["amount_invalid"] = "Neveljavna količina", + ["players_nearby"] = "V blizini ni ljudi", + ["ex_inv_lim"] = "Dejanja ni mogoče izvesti, saj presega največjo težo %s", + ["imp_invalid_quantity"] = "Dejanja ni mogoče izvesti, količina je neveljavna", + ["imp_invalid_amount"] = "Dejanja ni mogoče izvesti, znesek je neveljaven", + ["threw_standard"] = "Metanje %sx %s", + ["threw_account"] = "Metanje $%s %s", + ["threw_weapon"] = "Metanje %s", + ["threw_weapon_ammo"] = "Metanje %s z ~o~%sx %s", + ["threw_weapon_already"] = "Ti ze imas to orozje", + ["threw_cannot_pickup"] = "Shramba je poln, nemorem pobrati!", + ["threw_pickup_prompt"] = "Pritisni E da poberes", + ["keymap_showinventory"] = "Pokazi Shrambo", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/sr.lua b/resources/[core]/esx_inventory/locales/sr.lua new file mode 100644 index 0000000..b2f9e95 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/sr.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventar ( Težina %s / %s )", + ["use"] = "Koristi", + ["give"] = "Daj", + ["remove"] = "Baci", + ["return"] = "Nazad", + ["give_to"] = "Daj", + ["amount"] = "Količina", + ["giveammo"] = "Daj municiju", + ["amountammo"] = "Količina municije", + ["noammo"] = "Nemate dovoljno!", + ["gave_item"] = "Davanje %sx %s igraču %s", + ["received_item"] = "Dobijeno %sx %s od %s", + ["gave_weapon"] = "Davanje %s igraču %s", + ["gave_weapon_ammo"] = "Davanje ~o~%sx %s za %s igraču %s", + ["gave_weapon_withammo"] = "Davanje %s sa ~o~%sx %s igraču %s", + ["gave_weapon_hasalready"] = "%s već ima %s", + ["gave_weapon_noweapon"] = "%s nema to oružje", + ["received_weapon"] = "Dobijeno %s od %s", + ["received_weapon_ammo"] = "Dobijeno ~o~%sx %s za vaš %s od %s", + ["received_weapon_withammo"] = "Dobijeno %s sa ~o~%sx %s od %s", + ["received_weapon_hasalready"] = "%s je pokušao da Vam da %s, ali vi već imate to oružje", + ["received_weapon_noweapon"] = "%s je pokušao da Vam da municiju za %s, ali vi nemate to oružje", + ["gave_account_money"] = "Davanje $%s (%s) igraču %s", + ["received_account_money"] = "Dobijeno $%s (%s) od %s", + ["amount_invalid"] = "Nevažeća količina", + ["players_nearby"] = "Nema igrača u blizini", + ["ex_inv_lim"] = "Ne možete uraditi to, premašuje max težinu od %s", + ["imp_invalid_quantity"] = "Nevažeća količina", + ["imp_invalid_amount"] = "Nevažeći iznos", + ["threw_standard"] = "Bacanje %sx %s", + ["threw_account"] = "Bacanje $%s %s", + ["threw_weapon"] = "Bacanje %s", + ["threw_weapon_ammo"] = "Bacanje %s sa ~o~%sx %s", + ["threw_weapon_already"] = "Vi već imate to oružje", + ["threw_cannot_pickup"] = "Inventar je pun, ne možete pokupiti to!", + ["threw_pickup_prompt"] = "Pritisni E da pokupiš", + ["keymap_showinventory"] = "Otvaranje inventara", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/sv.lua b/resources/[core]/esx_inventory/locales/sv.lua new file mode 100644 index 0000000..4a124b5 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/sv.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Inventory ( Vikt %s / %s )", + ["use"] = "Använd", + ["give"] = "Ge", + ["remove"] = "Kasta", + ["return"] = "Tillbaka", + ["give_to"] = "Ge", + ["amount"] = "Antal", + ["giveammo"] = "Ge skott", + ["amountammo"] = "Antal skott", + ["noammo"] = "Inte tillräckligt!", + ["gave_item"] = "Ger %sx %s till %s", + ["received_item"] = "Mottog %sx %s från %s", + ["gave_weapon"] = "Ger %s till %s", + ["gave_weapon_ammo"] = "Ger ~o~%sx %s för %s till %s", + ["gave_weapon_withammo"] = "Ger %s med ~o~%sx %s till %s", + ["gave_weapon_hasalready"] = "%s har redan en %s", + ["gave_weapon_noweapon"] = "%s har inte detta vapen", + ["received_weapon"] = "Mottog %s från %s", + ["received_weapon_ammo"] = "Mottog ~o~%sx %s för din %s från %s", + ["received_weapon_withammo"] = "Mottog %s med ~o~%sx %s från %s", + ["received_weapon_hasalready"] = "%s har försökt ge dig en %s, men du har redan detta", + ["received_weapon_noweapon"] = "%s har försökt ge dig skott till en %s, men du har inte detta vapen", + ["gave_account_money"] = "Ger %skr (%s) till %s", + ["received_account_money"] = "Mottog %skr (%s) från %s", + ["amount_invalid"] = "Ogiltig mängd", + ["players_nearby"] = "Inga spelare nära", + ["ex_inv_lim"] = "Kan inte utföra, överskrider maxvikten på %s", + ["imp_invalid_quantity"] = "Kan inte utföra, mängden är ogiltig", + ["imp_invalid_amount"] = "Kan inte utföra, antalet är ogiltig", + ["threw_standard"] = "Kastar %sx %s", + ["threw_account"] = "Kastar %skr %s", + ["threw_weapon"] = "Kastar %s", + ["threw_weapon_ammo"] = "Kastar %s med ~o~%sx %s", + ["threw_weapon_already"] = "Du har redan detta vapen", + ["threw_cannot_pickup"] = "Inventoryt är fullt, kan inte plocka upp!", + ["threw_pickup_prompt"] = "Tryck E för att plocka upp", + ["keymap_showinventory"] = "Öppna inventory", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/tr.lua b/resources/[core]/esx_inventory/locales/tr.lua new file mode 100644 index 0000000..35df1f3 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/tr.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "Envanter ( Ağırlık %s / %s )", + ["use"] = "Kullan", + ["give"] = "Ver", + ["remove"] = "At", + ["return"] = "Geri Ver", + ["give_to"] = "Şuna Ver", + ["amount"] = "Miktar", + ["giveammo"] = "Mermi Ver", + ["amountammo"] = "Mermi Miktarı", + ["noammo"] = "Yeterli Değil!", + ["gave_item"] = "Verilen %sx %s %s'ye", + ["received_item"] = "Alınan %sx %s %s'den", + ["gave_weapon"] = "Verilen %s %s'ye", + ["gave_weapon_ammo"] = "Verilen ~o~%sx %s %s için %s'ye", + ["gave_weapon_withammo"] = "Verilen %s ile ~o~%sx %s %s'ye", + ["gave_weapon_hasalready"] = "%s Zaten Bir %s Sahip", + ["gave_weapon_noweapon"] = "%s O Silahı Sahip Değil", + ["received_weapon"] = "%s'den %s Alındı", + ["received_weapon_ammo"] = "%s'den %s için ~o~%sx %s Alındı", + ["received_weapon_withammo"] = "%s'den %s ile ~o~%sx %s Alındı", + ["received_weapon_hasalready"] = "%s Size Bir %s Vermeye Çalıştı, Ama Zaten Bu Silahınız Var", + ["received_weapon_noweapon"] = "%s Size Bir %s İçin Mermi Vermeye Çalıştı, Ama Bu Silaha Sahip Değilsiniz", + ["gave_account_money"] = "Verilen $%s (%s) %s'ye", + ["received_account_money"] = "Alınan $%s (%s) %s'den", + ["amount_invalid"] = "Geçersiz Miktar", + ["players_nearby"] = "Yakınlarda Hiçbir Oyuncu Yok", + ["ex_inv_lim"] = "İşlem Yapılamaz, %s Ağırlık Sınırı Aşıldı", + ["imp_invalid_quantity"] = "İşlem Yapılamaz, Miktar Geçersiz", + ["imp_invalid_amount"] = "İşlem Yapılamaz, Miktar Geçersiz", + ["threw_standard"] = "Atılan %sx %s", + ["threw_account"] = "Atılan $%s %s", + ["threw_weapon"] = "Atılan %s", + ["threw_weapon_ammo"] = "Atılan %s ile ~o~%sx %s", + ["threw_weapon_already"] = "Bu Silaha Zaten Sahipsiniz", + ["threw_cannot_pickup"] = "Envanter Dolu, Alınamaz!", + ["threw_pickup_prompt"] = "Almak İçin E'ye Basın", + ["keymap_showinventory"] = "Envanteri Göster", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_inventory/locales/zh-cn.lua b/resources/[core]/esx_inventory/locales/zh-cn.lua new file mode 100644 index 0000000..be7d200 --- /dev/null +++ b/resources/[core]/esx_inventory/locales/zh-cn.lua @@ -0,0 +1,41 @@ +return { + ["inventory"] = "物品栏 (负重 %s / %s)", + ["use"] = "使用", + ["give"] = "赠予", + ["remove"] = "丢弃", + ["return"] = "返回", + ["give_to"] = "赠予目标", + ["amount"] = "数量", + ["giveammo"] = "赠予弹药", + ["amountammo"] = "弹药数量", + ["noammo"] = "弹药不足!", + ["gave_item"] = "您将 %s 个 %s 赠予给 %s", + ["received_item"] = "您收到 %s 个 %s, 由 %s 的赠予", + ["gave_weapon"] = "您将 %s 赠予给 %s", + ["gave_weapon_ammo"] = "您将 ~o~%s 发 %s %s 赠予 %s", + ["gave_weapon_withammo"] = "您把 %s 及 ~o~%s 发 %s 赠予 %s", + ["gave_weapon_hasalready"] = "%s 已拥有 %s", + ["gave_weapon_noweapon"] = "%s 未拥有该武器", + ["received_weapon"] = "您收到 %s, 由 %s 赠", + ["received_weapon_ammo"] = "您收到 ~o~%s 发 %s 的%s, 由 %s 赠予", + ["received_weapon_withammo"] = "您收到 %s 及 ~o~%s 发 %s, 由 %s 赠予", + ["received_weapon_hasalready"] = "%s 试图赠予您 %s, 但您已拥有", + ["received_weapon_noweapon"] = "%s 试图赠予您 %s 发弹药, 但您未装备该武器", + ["gave_account_money"] = "您将 ¥%s (%s) 转账至 %s", + ["received_account_money"] = "您收到 ¥%s (%s), 由 %s 转账", + ["amount_invalid"] = "无效数量", + ["players_nearby"] = "附近暂无其他人员", + ["ex_inv_lim"] = "操作失败: 超过最大负重限制 (%s)", + ["imp_invalid_quantity"] = "操作失败: 无效数量输入", + ["imp_invalid_amount"] = "操作失败: 无效金额输入", + ["threw_standard"] = "您已丢弃 %s 个 %s", + ["threw_account"] = "您已丢弃 ¥%s 笔 %s", + ["threw_weapon"] = "您已丢弃武器 %s", + ["threw_weapon_ammo"] = "您已丢弃 %s 及其 ~o~%s 发 %s", + ["threw_weapon_already"] = "您已持有相同武器!", + ["threw_cannot_pickup"] = "物品栏已满, 无法拾取!", + ["threw_pickup_prompt"] = "键下 [E] 拾取", + ["keymap_showinventory"] = "显示物品栏", + ["locale_currency"] = "$%s", + ["ammo_rounds"] = "Rounds" +} diff --git a/resources/[core]/esx_loadingscreen/LICENSE b/resources/[core]/esx_loadingscreen/LICENSE new file mode 100644 index 0000000..79832f2 --- /dev/null +++ b/resources/[core]/esx_loadingscreen/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + esx_loadingscreen + Copyright (C) 2020-2024 ESX Framework + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + esx_loadingscreen Copyright (C) 2020-2024 ESX Framework + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[core]/esx_loadingscreen/README.md b/resources/[core]/esx_loadingscreen/README.md new file mode 100644 index 0000000..8cf8d7c --- /dev/null +++ b/resources/[core]/esx_loadingscreen/README.md @@ -0,0 +1,15 @@ +

[ESX] Loading Screen

Discord - Website - Documentation + +A simple but beautiful Loading Screen for your server! + +## Legal + +esx_loadingscreen - Loading in style! + +Copyright (C) 2020-2024 ESX Framework + +This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version. + +This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details. + +You should have received a copy Of the GNU General Public License along with this program. If Not, see . diff --git a/resources/[core]/esx_loadingscreen/client/client.lua b/resources/[core]/esx_loadingscreen/client/client.lua new file mode 100644 index 0000000..383454c --- /dev/null +++ b/resources/[core]/esx_loadingscreen/client/client.lua @@ -0,0 +1,13 @@ +local ClientLoadESX = false + +AddEventHandler("playerSpawned", function() + if not ClientLoadESX then + ShutdownLoadingScreenNui() + ClientLoadESX = true + if Config.Fade then + DoScreenFadeOut(0) + Wait(3000) + DoScreenFadeIn(2500) + end + end +end) diff --git a/resources/[core]/esx_loadingscreen/config.lua b/resources/[core]/esx_loadingscreen/config.lua new file mode 100644 index 0000000..302c9a5 --- /dev/null +++ b/resources/[core]/esx_loadingscreen/config.lua @@ -0,0 +1,3 @@ +Config = {} + +Config.Fade = true diff --git a/resources/[core]/esx_loadingscreen/css/index.css b/resources/[core]/esx_loadingscreen/css/index.css new file mode 100644 index 0000000..474a89b --- /dev/null +++ b/resources/[core]/esx_loadingscreen/css/index.css @@ -0,0 +1,117 @@ +/** + * Copyright (c) Jérémie N'gadi + * + * All rights reserved. + * + * Even if 'All rights reserved' is very clear : + * + * You shall not use any piece of this software in a commercial product / service + * You shall not resell this software + * You shall not provide any facility to install this particular software in a commercial product / service + * If you redistribute this software, you must link to ORIGINAL repository at https://github.com/esx-framework/esx-reborn + * This copyright should appear in every part of the project code + */ + +html, +body { + margin: 0; + padding: 0; + font-family: "Quicksand", sans-serif; + overflow: hidden; +} + +#esx_intro { + z-index: 2; +} + +#esx_loop { + z-index: 1; +} + +#loading_txt { + bottom: 5%; + left: 50%; + margin-left: -80px; + position: absolute; + z-index: 999; + + -webkit-animation: fadein 5s; + -moz-animation: fadein 5s; + -ms-animation: fadein 5s; + -o-animation: fadein 5s; + animation: fadein 5s; +} + +p { + color: white; + font-size: 32px; +} + +.text_thing:after { + content: " ."; + animation: dots 2s steps(5, end) infinite; +} + +@keyframes dots { + 0%, + 20% { + color: rgba(0, 0, 0, 0); + text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0); + } + 40% { + color: white; + text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0); + } + 60% { + text-shadow: 0.25em 0 0 white, 0.5em 0 0 rgba(0, 0, 0, 0); + } + 80%, + 100% { + text-shadow: 0.25em 0 0 white, 0.5em 0 0 white; + } +} + +@keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@-moz-keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@-webkit-keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@-ms-keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@-o-keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } +} diff --git a/resources/[core]/esx_loadingscreen/fxmanifest.lua b/resources/[core]/esx_loadingscreen/fxmanifest.lua new file mode 100644 index 0000000..db6f664 --- /dev/null +++ b/resources/[core]/esx_loadingscreen/fxmanifest.lua @@ -0,0 +1,17 @@ +game 'common' + +fx_version 'cerulean' +author 'ESX-Framework' +description 'Allows resources to Run tasks at specific intervals.' +version '1.13.5' +lua54 'yes' + +loadscreen 'index.html' + +shared_script 'config.lua' + +loadscreen_manual_shutdown "yes" + +client_script 'client/client.lua' + +files { 'index.html', './vid/*.mp4', './vid/*.webm', './js/index.js', './css/index.css' } diff --git a/resources/[core]/esx_loadingscreen/index.html b/resources/[core]/esx_loadingscreen/index.html new file mode 100644 index 0000000..590de52 --- /dev/null +++ b/resources/[core]/esx_loadingscreen/index.html @@ -0,0 +1,22 @@ + + + + + + + + +

+
+

Loading

+
+ + + +
+ + diff --git a/resources/[core]/esx_loadingscreen/js/index.js b/resources/[core]/esx_loadingscreen/js/index.js new file mode 100644 index 0000000..c77c76c --- /dev/null +++ b/resources/[core]/esx_loadingscreen/js/index.js @@ -0,0 +1,22 @@ +// Copyright (c) Jérémie N'gadi +// +// All rights reserved. +// +// Even if 'All rights reserved' is very clear : +// +// You shall not use any piece of this software in a commercial product / service +// You shall not resell this software +// You shall not provide any facility to install this particular software in a commercial product / service +// If you redistribute this software, you must link to ORIGINAL repository at https://github.com/esx-framework/esx-reborn +// This copyright should appear in every part of the project code + +document.addEventListener("DOMContentLoaded", () => { + const introTag = document.getElementById("esx_intro"); + const loopTag = document.getElementById("esx_loop"); + + introTag.onended = () => { + introTag.style.display = "none"; + loopTag.loop = true; // true + loopTag.play(); + }; +}); diff --git a/resources/[core]/esx_loadingscreen/vid/esx_intro.mp4 b/resources/[core]/esx_loadingscreen/vid/esx_intro.mp4 new file mode 100644 index 0000000..57d0d72 Binary files /dev/null and b/resources/[core]/esx_loadingscreen/vid/esx_intro.mp4 differ diff --git a/resources/[core]/esx_loadingscreen/vid/esx_loop.mp4 b/resources/[core]/esx_loadingscreen/vid/esx_loop.mp4 new file mode 100644 index 0000000..23fd976 Binary files /dev/null and b/resources/[core]/esx_loadingscreen/vid/esx_loop.mp4 differ diff --git a/resources/[core]/esx_menu_default/LICENSE b/resources/[core]/esx_menu_default/LICENSE new file mode 100644 index 0000000..8eef124 --- /dev/null +++ b/resources/[core]/esx_menu_default/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + esx_menu_default + Copyright (C) 2015-2024 Jérémie N'gadi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + esx_menu_default Copyright (C) 2015-2024 Jérémie N'gadi + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[core]/esx_menu_default/README.md b/resources/[core]/esx_menu_default/README.md new file mode 100644 index 0000000..5f434b8 --- /dev/null +++ b/resources/[core]/esx_menu_default/README.md @@ -0,0 +1,17 @@ +

[ESX] Menu Default

Discord - Website - Documentation + +A default List type menu for ESX. + +![Preview_1](https://media.discordapp.net/attachments/1370464258382368918/1409904516555477063/image.png?ex=68af1367&is=68adc1e7&hm=35debf1b09e71a4c418c23d751e21602ccb50c86c267548e58ca90c3e98a54b1&=&format=webp&quality=lossless) + +## Legal + +esx_menu_default - Default Menu! + +Copyright (C) 2015-2024 Jérémie N'gadi + +This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version. + +This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details. + +You should have received a copy Of the GNU General Public License along with this program. If Not, see . diff --git a/resources/[core]/esx_menu_default/client/main.lua b/resources/[core]/esx_menu_default/client/main.lua new file mode 100644 index 0000000..a48193b --- /dev/null +++ b/resources/[core]/esx_menu_default/client/main.lua @@ -0,0 +1,152 @@ +local GUI, MenuType, OpenedMenus, CurrentNameSpace = {}, "default", 0, nil +GUI.Time = 0 + +local function openMenu(namespace, name, data) + CurrentNameSpace = namespace + OpenedMenus = OpenedMenus + 1 + + data.namespace = namespace + data.name = name + + SendNUIMessage({ + action = "openMenu", + data = data + }) +end + +local function closeMenu(namespace, name) + CurrentNameSpace = namespace + OpenedMenus = OpenedMenus - 1 + if OpenedMenus < 0 then + OpenedMenus = 0 + end + + SendNUIMessage({ + action = "closeMenu", + data = { + namespace = namespace, + name = name, + } + }) +end + +AddEventHandler("onResourceStop", function(resource) + if GetCurrentResourceName() == resource and OpenedMenus > 0 then + ESX.UI.Menu.CloseAll() + elseif CurrentNameSpace ~= nil and CurrentNameSpace == resource and OpenedMenus > 0 then + ESX.UI.Menu.CloseAll() + end +end) + +ESX.UI.Menu.RegisterType(MenuType, openMenu, closeMenu) + +RegisterNUICallback("menu_submit", function(data, cb) + local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name) + + if not menu then + return + end + + if menu.submit ~= nil then + menu.submit(data, menu) + end + + cb("OK") +end) + +RegisterNUICallback("menu_cancel", function(data, cb) + local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name) + + if not menu then + return + end + + if menu.cancel ~= nil then + menu.cancel(data, menu) + end + + cb("OK") +end) + +RegisterNUICallback("menu_change", function(data, cb) + local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name) + + if not menu then + return + end + + for i = 1, #data.elements, 1 do + menu.setElement(i, "value", data.elements[i].value) + + if data.elements[i].selected then + menu.setElement(i, "selected", true) + else + menu.setElement(i, "selected", false) + end + end + + if menu.change ~= nil then + menu.change(data, menu) + end + cb("OK") +end) + +ESX.RegisterInput("menu_default_enter", "Submit menu item", "KEYBOARD", "RETURN", function() + if OpenedMenus > 0 and (GetGameTimer() - GUI.Time) > 200 then + SendNUIMessage({ + action = "controlPressed", + control = "ENTER", + }) + GUI.Time = GetGameTimer() + end +end) + +ESX.RegisterInput("menu_default_backspace", "Close menu", "KEYBOARD", "BACK", function() + if OpenedMenus > 0 then + SendNUIMessage({ + action = "controlPressed", + control = "BACKSPACE", + }) + GUI.Time = GetGameTimer() + end +end) + +ESX.RegisterInput("menu_default_top", "Change menu focus to top item", "KEYBOARD", "UP", function() + if OpenedMenus > 0 then + SendNUIMessage({ + action = "controlPressed", + control = "TOP", + }) + GUI.Time = GetGameTimer() + end +end) + +ESX.RegisterInput("menu_default_down", "Change menu focus to down item", "KEYBOARD", "DOWN", function() + if OpenedMenus > 0 then + SendNUIMessage({ + action = "controlPressed", + control = "DOWN", + }) + GUI.Time = GetGameTimer() + end +end) + +ESX.RegisterInput("menu_default_left", "Change menu slider to left", "KEYBOARD", "LEFT", function() + if OpenedMenus > 0 then + SendNUIMessage({ + action = "controlPressed", + control = "LEFT", + }) + GUI.Time = GetGameTimer() + end +end) + +ESX.RegisterInput("menu_default_right", "Change menu slider to right", "KEYBOARD", "RIGHT", function() + if OpenedMenus > 0 then + SendNUIMessage({ + action = "controlPressed", + control = "RIGHT", + }) + GUI.Time = GetGameTimer() + end +end) diff --git a/resources/[core]/esx_menu_default/fxmanifest.lua b/resources/[core]/esx_menu_default/fxmanifest.lua new file mode 100644 index 0000000..6545098 --- /dev/null +++ b/resources/[core]/esx_menu_default/fxmanifest.lua @@ -0,0 +1,14 @@ +fx_version 'cerulean' + +game 'gta5' +description 'A basic menu system for ESX Legacy.' +lua54 'yes' +version '1.13.5' + +client_scripts { '@es_extended/imports.lua', 'client/main.lua' } + +ui_page 'web/build/index.html' + +files { 'web/build/index.html', 'web/build/**/*' } + +dependencies { 'es_extended' } diff --git a/resources/[core]/esx_menu_default/web/.eslintrc.cjs b/resources/[core]/esx_menu_default/web/.eslintrc.cjs new file mode 100644 index 0000000..6e8698b --- /dev/null +++ b/resources/[core]/esx_menu_default/web/.eslintrc.cjs @@ -0,0 +1,18 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", + ], + ignorePatterns: ["dist", ".eslintrc.cjs"], + parser: "@typescript-eslint/parser", + plugins: ["react-refresh"], + rules: { + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + }, +}; diff --git a/resources/[core]/esx_menu_default/web/.gitignore b/resources/[core]/esx_menu_default/web/.gitignore new file mode 100644 index 0000000..a1f14af --- /dev/null +++ b/resources/[core]/esx_menu_default/web/.gitignore @@ -0,0 +1,36 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# Dependencies +node_modules +.pnpm-store +.npm + +# Build outputs +*.local + +# Environment files +.env +.env.* +!.env.example + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# OS generated files +Thumbs.db +.DS_Store \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/index.html b/resources/[core]/esx_menu_default/web/index.html new file mode 100644 index 0000000..e9082d6 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/index.html @@ -0,0 +1,18 @@ + + + + + + + + + ESX Menu Default + + + +

+ + + + + \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/package.json b/resources/[core]/esx_menu_default/web/package.json new file mode 100644 index 0000000..3ecd199 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/package.json @@ -0,0 +1,56 @@ +{ + "name": "web", + "version": "1.0.0", + "description": "", + "main": "index.js", + "private": true, + "scripts": { + "start": "vite", + "dev": "vite", + "start:game": "vite build --watch", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "keywords": [], + "author": "Err", + "license": "ISC", + "packageManager": "pnpm@10.13.1", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-brands-svg-icons": "^6.7.2", + "@fortawesome/free-regular-svg-icons": "^6.7.2", + "@fortawesome/free-solid-svg-icons": "^6.7.2", + "@fortawesome/react-fontawesome": "^0.2.2", + "@tailwindcss/vite": "^4.0.15", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "framer-motion": "^12.5.0", + "lucide-react": "^0.525.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-icons": "^5.5.0", + "tailwind-merge": "^3.0.2", + "tailwindcss-animate": "^1.0.7" + }, + "devDependencies": { + "@types/node": "^22.13.13", + "@types/react": "^19.0.12", + "@types/react-dom": "^19.0.4", + "@typescript-eslint/eslint-plugin": "^8.28.0", + "@typescript-eslint/parser": "^8.28.0", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.21", + "eslint": "^9.23.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.19", + "postcss": "^8.5.3", + "tailwindcss": "^3.4.17", + "typescript": "^5.8.2", + "vite": "^6.2.3" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "esbuild" + ] + } +} diff --git a/resources/[core]/esx_menu_default/web/src/app/App.tsx b/resources/[core]/esx_menu_default/web/src/app/App.tsx new file mode 100644 index 0000000..a9e010a --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/app/App.tsx @@ -0,0 +1,94 @@ +import React, { useEffect, useState } from "react"; +import { useNuiEvent } from "@/hooks/useNuiEvent"; +import { AnimatePresence, HTMLMotionProps, motion } from "framer-motion"; +import Menu from "@/components/menu"; +import { IconProp } from "@fortawesome/fontawesome-svg-core"; + +export interface Element { + label: string; + name: string; + description?: string; + icon?: IconProp; + value?: number; + type?: "slider"; + min: number; + max: number; + options?: string[]; + usable?: boolean; + unselectable?: boolean; + disableRightArrow?: boolean; +} + +export interface MenuData { + title: string; + namespace: string; + name: string; + align: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center" | "left-center" | "right-center"; + elements: Element[]; +} + +export interface CloseData { + namespace: string; + name: string; +} + +const visibility_animation: HTMLMotionProps<"div"> = { + initial: { opacity: 0 }, + animate: { + opacity: 1, + transition: { duration: 0.3, ease: [0, 0, 0.2, 1] }, + }, + exit: { + opacity: 0, + transition: { duration: 0.3, ease: [0.4, 0, 1, 1] }, + }, +}; + +const App: React.FC = () => { + const [_, setCreatedMenus] = useState>({}); + + const [currentMenu, setCurrentMenu] = useState(null); + + useNuiEvent("openMenu", (data) => { + setCreatedMenus((prev) => { + const list = prev[data.namespace] ?? []; + return { + ...prev, + [data.namespace]: [...list, data], + }; + }); + + setCurrentMenu(data); + }); + + useNuiEvent("closeMenu", ({ namespace, name }) => { + setCreatedMenus((prev) => { + const list = prev[namespace] ?? []; + const nextList = list.filter((m) => m.name !== name); + + const next = { ...prev }; + if (nextList.length > 0) { + next[namespace] = nextList; + } else { + delete next[namespace]; + } + + const all = Object.values(next).flat(); + setCurrentMenu(all.length > 0 ? all[all.length - 1] : null); + + return next; + }); + }); + + return ( + + {currentMenu && ( + + + + )} + + ); +}; + +export default App; diff --git a/resources/[core]/esx_menu_default/web/src/components/menu-button.tsx b/resources/[core]/esx_menu_default/web/src/components/menu-button.tsx new file mode 100644 index 0000000..3063c30 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/components/menu-button.tsx @@ -0,0 +1,67 @@ +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { ArrowRight } from "lucide-react"; +import { Element } from "@/app/App"; + +interface Props { + element: Element; + isSelected?: boolean; +} + +const MenuButton: React.FC = ({ element, isSelected }) => { + const { label, description, icon, usable, disableRightArrow, unselectable } = + element; + const base = "rounded-[4px] flex items-center p-4 gap-4 justify-between"; + const sel = isSelected + ? "bg-[#FB9B041A] border border-[#FB9B04]" + : "bg-[#252525] border border-transparent"; + + const unSelectable = unselectable ? "opacity-80" : ""; + + return ( +
+
+ {icon && ( + + )} + +
+ {description ? ( + <> +

+

+ + ) : ( +

+ )} +

+
+ + {usable !== false && + disableRightArrow !== true && + unselectable !== true && ( + + )} +
+ ); +}; + +export default MenuButton; diff --git a/resources/[core]/esx_menu_default/web/src/components/menu-slider.tsx b/resources/[core]/esx_menu_default/web/src/components/menu-slider.tsx new file mode 100644 index 0000000..9df8dbc --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/components/menu-slider.tsx @@ -0,0 +1,78 @@ +import { ChevronLeft, ChevronRight } from "lucide-react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { Element } from "@/app/App"; + +interface Props { + element: Element; + isSelected?: boolean; +} + +const MenuSlider: React.FC = ({ element, isSelected }) => { + const { label, description, icon, unselectable } = element; + + const options = (element as Element).options as string[] | undefined; + + const min = options ? 0 : element.min ?? 0; + const max = options ? Math.max(0, options.length - 1) : element.max ?? 0; + + const rawValue = element.value ?? min; + const value = Math.min(max, Math.max(min, rawValue)); + + const base = "rounded-[4px] flex items-center p-4 gap-4 justify-between"; + const sel = isSelected + ? "bg-[#FB9B041A] border border-[#FB9B04]" + : "bg-[#252525] border border-transparent"; + const text = isSelected ? "text-[#FB9B04]" : "text-neutral-100"; + + const unSelectable = unselectable ? "opacity-50" : "" + + return ( +
+
+ {icon && ( + + )} +
+ {description ? ( + <> +

+

+ + ) : ( +

+ )} +

+
+ +
+ + {options ? ( + + ) : ( + {value} + )} + +
+
+ ); +}; + +export default MenuSlider; diff --git a/resources/[core]/esx_menu_default/web/src/components/menu.tsx b/resources/[core]/esx_menu_default/web/src/components/menu.tsx new file mode 100644 index 0000000..c517a9b --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/components/menu.tsx @@ -0,0 +1,140 @@ +import { useReducer, useState, useRef, useEffect } from "react"; +import { fetchNui } from "@/utils/fetchNui"; +import { useControls } from "@/hooks/useControls"; +import { MenuData } from "@/app/App"; +import MenuButton from "./menu-button"; +import MenuSlider from "./menu-slider"; +import { GetPosition } from "@/utils/getPosition"; + +interface Props { + data: MenuData; +} + +const Menu: React.FC = ({ data }) => { + const [position, setPosition] = useState(0); + const [, forceRender] = useReducer((v) => v + 1, 0); + const itemRefs = useRef<(HTMLDivElement | null)[]>([]); + + const elements = data.elements; + + const payload = () => ({ + _namespace: data.namespace, + _name: data.name, + current: elements[position], + elements, + }); + + const submit = () => { + const el = elements[position]; + if (el?.usable === false) return; + + fetchNui("menu_submit", payload()); + }; + + const cancel = () => + fetchNui("menu_cancel", { _namespace: data.namespace, _name: data.name }); + + const change = () => { + const el = elements[position]; + if (el?.usable === false) return; + + fetchNui("menu_change", payload()); + }; + + const stepSelectedSlider = (delta: number) => { + const el = elements[position]; + + if (el?.usable === false) return; + if (el?.type !== "slider") return; + + const options = (el as any).options as string[] | undefined; + + const min = options ? 0 : el.min ?? 0; + const max = options ? Math.max(0, options.length - 1) : el.max ?? 0; + + const cur = (el.value ?? min) + delta; + + if (cur > max) { + el.value = min; + } else if (cur < min) { + el.value = max; + } else { + el.value = cur; + } + + forceRender(); + change(); + }; + + useControls({ + elements, + position, + setPosition: (updater) => { + setPosition(updater); + change(); + }, + submit, + cancel, + changeLeft: () => stepSelectedSlider(-1), + changeRight: () => stepSelectedSlider(1), + }); + + useEffect(() => { + const el = itemRefs.current[position]; + if (el) { + el.scrollIntoView({ + behavior: "smooth", + block: "center", + inline: "nearest", + }); + } + }, [position]); + + useEffect(() => { + if (elements[position]?.unselectable) { + const firstSelectable = elements.findIndex((el) => !el.unselectable); + if (firstSelectable !== -1) setPosition(firstSelectable); + } + }, []); + + return ( +
+
+
+

+ +

+ +
+ {elements.map((element, index) => { + const isSelected = index === position; + + return ( +
{ + itemRefs.current[index] = el; + }} + > + {element.type === "slider" ? ( + + ) : ( + + )} +
+ ); + })} +
+
+
+ ); +}; + +export default Menu; diff --git a/resources/[core]/esx_menu_default/web/src/hooks/useControls.ts b/resources/[core]/esx_menu_default/web/src/hooks/useControls.ts new file mode 100644 index 0000000..b45548c --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/hooks/useControls.ts @@ -0,0 +1,79 @@ +import { useEffect } from "react"; + +export type Control = "TOP" | "DOWN" | "ENTER" | "BACKSPACE" | "LEFT" | "RIGHT"; + +interface Props { + elements: any[]; + position: number; + setPosition: (p: number | ((prev: number) => number)) => void; + submit: () => void; + cancel: () => void; + changeLeft: () => void; + changeRight: () => void; +} + +export const useControls = ({ + elements, + position, + setPosition, + submit, + cancel, + changeLeft, + changeRight, +}: Props) => { + useEffect(() => { + const onMessage = ( + ev: MessageEvent<{ action: string; control: Control }> + ) => { + if (ev.data.action !== "controlPressed") return; + + const skipUp = (p: number) => { + let next = p === 0 ? elements.length - 1 : p - 1; + while (elements[next]?.unselectable) { + next = next === 0 ? elements.length - 1 : next - 1; + } + return next; + }; + + const skipDown = (p: number) => { + let next = p === elements.length - 1 ? 0 : p + 1; + while (elements[next]?.unselectable) { + next = next === elements.length - 1 ? 0 : next + 1; + } + return next; + }; + + switch (ev.data.control) { + case "TOP": + setPosition((p) => skipUp(typeof p === "number" ? p : position)); + break; + case "DOWN": + setPosition((p) => skipDown(typeof p === "number" ? p : position)); + break; + case "ENTER": + if (!elements[position]?.unselectable) submit(); + break; + case "BACKSPACE": + cancel(); + break; + case "LEFT": + changeLeft(); + break; + case "RIGHT": + changeRight(); + break; + } + }; + + window.addEventListener("message", onMessage); + return () => window.removeEventListener("message", onMessage); + }, [ + elements, + position, + setPosition, + submit, + cancel, + changeLeft, + changeRight, + ]); +}; diff --git a/resources/[core]/esx_menu_default/web/src/hooks/useNuiEvent.ts b/resources/[core]/esx_menu_default/web/src/hooks/useNuiEvent.ts new file mode 100644 index 0000000..72b1f16 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/hooks/useNuiEvent.ts @@ -0,0 +1,47 @@ +// yoinked from https://github.com/overextended/ox_lib/blob/master/web/src/hooks/useNuiEvent.ts +import { MutableRefObject, useEffect, useRef } from 'react'; +import { noop } from '../utils/misc'; + +interface NuiMessageData { + action: string; + data: T; +} + +type NuiHandlerSignature = (data: T) => void; + +/** + * A hook that manage events listeners for receiving data from the client scripts + * @param action The specific `action` that should be listened for. + * @param handler The callback function that will handle data relayed by this hook + * + * @example + * useNuiEvent<{visibility: true, wasVisible: 'something'}>('setVisible', (data) => { + * // whatever logic you want + * }) + * + **/ + +export const useNuiEvent = (action: string, handler: (data: T) => void) => { + const savedHandler: MutableRefObject> = useRef(noop); + + // Make sure we handle for a reactive handler + useEffect(() => { + savedHandler.current = handler; + }, [handler]); + + useEffect(() => { + const eventListener = (event: MessageEvent>) => { + const { action: eventAction, data } = event.data; + + if (savedHandler.current) { + if (eventAction === action) { + savedHandler.current(data); + } + } + }; + + window.addEventListener('message', eventListener); + // Remove Event Listener on component cleanup + return () => window.removeEventListener('message', eventListener); + }, [action]); +}; \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/src/index.css b/resources/[core]/esx_menu_default/web/src/index.css new file mode 100644 index 0000000..1ede7fe --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/index.css @@ -0,0 +1,120 @@ +@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"); + +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 0 0% 3.9%; + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary: 0 0% 9%; + --primary-foreground: 0 0% 98%; + --secondary: 0 0% 96.1%; + --secondary-foreground: 0 0% 9%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 89.8%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem; + --sidebar-background: 0 0% 98%; + --sidebar-foreground: 240 5.3% 26.1%; + --sidebar-primary: 240 5.9% 10%; + --sidebar-primary-foreground: 0 0% 98%; + --sidebar-accent: 240 4.8% 95.9%; + --sidebar-accent-foreground: 240 5.9% 10%; + --sidebar-border: 220 13% 91%; + --sidebar-ring: 217.2 91.2% 59.8%; + } + + .dark { + --background: 0 0% 3.9%; + --foreground: 0 0% 98%; + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-fonoreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + --sidebar-background: 0 0% 9%; + --sidebar-foreground: 0 0% 98%; + --sidebar-primary: 225 84% 49%; + --sidebar-primary-foreground: 0 0% 98%; + --sidebar-accent: 0 0% 15%; + --sidebar-accent-foreground: 0 0% 98%; + --sidebar-border: 0 0% 100% / 10%; + --sidebar-ring: 0 0% 45%; + } +} + +@layer base { + * { + @apply border-border; + } + + body { + @apply bg-transparent w-[100vw] h-[100vh] text-foreground; + } +} + +::-webkit-scrollbar { + background: none !important; + width: 0 !important; + height: 0 !important; + margin: 0 !important; + padding: 0 !important; +} + +:root { + font-family: "Poppins", sans-serif !important; + text-rendering: optimizeLegibility !important; + -webkit-font-smoothing: antialiased !important; + -moz-osx-font-smoothing: grayscale !important; + color-scheme: normal !important; + background-color: none !important; + overflow: hidden !important; + height: 100vh !important; + width: 100vw !important; + margin: 0 !important; + padding: 0 !important; + font-size: 1.2vh !important; +} + +#root { + height: 100vh !important; + width: 100vw !important; +} + +body { + user-select: none; +} diff --git a/resources/[core]/esx_menu_default/web/src/lib/utils.ts b/resources/[core]/esx_menu_default/web/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/resources/[core]/esx_menu_default/web/src/main.tsx b/resources/[core]/esx_menu_default/web/src/main.tsx new file mode 100644 index 0000000..34d3bc4 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/main.tsx @@ -0,0 +1,38 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import "./index.css"; +import App from "./app/App"; +import { fas } from "@fortawesome/free-solid-svg-icons"; +import { far } from "@fortawesome/free-regular-svg-icons"; +import { fab } from "@fortawesome/free-brands-svg-icons"; +import { library } from "@fortawesome/fontawesome-svg-core"; +import { isEnvBrowser } from "./utils/misc"; +import ErrorBoundary from "./providers/errorBoundary"; +import { ThemeProvider } from "./providers/themeProvider"; + +library.add(fas, far, fab); + +if (isEnvBrowser()) { + const root = document.getElementById("root"); + // https://i.imgur.com/iPTAdYV.png - Night time img + // https://i.imgur.com/3pzRj9n.png - Day time img + // + // root!.style.backgroundImage = 'url("/images/carShader.png")'; + root!.style.backgroundSize = "cover"; + root!.style.backgroundRepeat = "no-repeat"; + root!.style.backgroundPosition = "center"; +} + +const root = document.getElementById("root"); + +createRoot(root!).render( + + + {" "} + {/* Catches JS errors without hiding UI and keeps the app running */} + + + + + +); diff --git a/resources/[core]/esx_menu_default/web/src/providers/errorBoundary.tsx b/resources/[core]/esx_menu_default/web/src/providers/errorBoundary.tsx new file mode 100644 index 0000000..4b7f03d --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/providers/errorBoundary.tsx @@ -0,0 +1,25 @@ +// yoinked from https://github.com/overextended/ox_lib/blob/master/web/src/providers/errorBoundary.tsx +import { fetchNui } from '@/utils/fetchNui'; +import { Component, ReactNode, ErrorInfo } from 'react'; + +class ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean }> { + constructor(props: { children: ReactNode }) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(err: Error) { + return { hasError: true }; + } + + componentDidCatch(error: Error, info: ErrorInfo) { + console.error(error, info) + this.setState({ hasError: false }); + } + + render() { + return this.state.hasError ? null : this.props.children; + } +} + +export default ErrorBoundary; \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/src/providers/themeProvider.tsx b/resources/[core]/esx_menu_default/web/src/providers/themeProvider.tsx new file mode 100644 index 0000000..473f79e --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/providers/themeProvider.tsx @@ -0,0 +1,73 @@ +import { createContext, useContext, useEffect, useState } from "react" + +type Theme = "dark" | "light" | "system" + +type ThemeProviderProps = { + children: React.ReactNode + defaultTheme?: Theme + storageKey?: string +} + +type ThemeProviderState = { + theme: Theme + setTheme: (theme: Theme) => void +} + +const initialState: ThemeProviderState = { + theme: "system", + setTheme: () => null, +} + +const ThemeProviderContext = createContext(initialState) + +export function ThemeProvider({ + children, + defaultTheme = "system", + storageKey = "vite-ui-theme", + ...props +}: ThemeProviderProps) { + const [theme, setTheme] = useState( + () => (localStorage.getItem(storageKey) as Theme) || defaultTheme + ) + + useEffect(() => { + const root = window.document.documentElement + + root.classList.remove("light", "dark") + + if (theme === "system") { + const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") + .matches + ? "dark" + : "light" + + root.classList.add(systemTheme) + return + } + + root.classList.add(theme) + }, [theme]) + + const value = { + theme, + setTheme: (theme: Theme) => { + localStorage.setItem(storageKey, theme) + setTheme(theme) + }, + } + + return ( + + {children} + + ) +} + +export const useTheme = () => { + const context = useContext(ThemeProviderContext) + + if (context === undefined) + throw new Error("useTheme must be used within a ThemeProvider") + + return context +} \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/src/utils/debugData.ts b/resources/[core]/esx_menu_default/web/src/utils/debugData.ts new file mode 100644 index 0000000..06aa664 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/utils/debugData.ts @@ -0,0 +1,31 @@ +// yoinked from https://github.com/overextended/ox_lib/blob/master/web/src/utils/debugData.ts +import { isEnvBrowser } from './misc'; + +interface DebugEvent { + action: string; + data: T; +} + +/** + * Emulates dispatching an event using SendNuiMessage in the lua scripts. + * This is used when developing in browser + * + * @param events - The event you want to cover + * @param timer - How long until it should trigger (ms) + */ +export const debugData =

(events: DebugEvent

[], timer = 1000): void => { + if (process.env.NODE_ENV === 'development' && isEnvBrowser()) { + for (const event of events) { + setTimeout(() => { + window.dispatchEvent( + new MessageEvent('message', { + data: { + action: event.action, + data: event.data, + }, + }) + ); + }, timer); + } + } +}; \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/src/utils/fetchNui.ts b/resources/[core]/esx_menu_default/web/src/utils/fetchNui.ts new file mode 100644 index 0000000..aecca11 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/utils/fetchNui.ts @@ -0,0 +1,36 @@ +// yoinked from https://github.com/overextended/ox_lib/blob/master/web/src/utils/fetchNui.ts +/** + * Simple wrapper around fetch API tailored for CEF/NUI use. This abstraction + * can be extended to include AbortController if needed or if the response isn't + * JSON. Tailor it to your needs. + * + * @param eventName - The endpoint eventname to target + * @param data - Data you wish to send in the NUI Callback + * + * @return returnData - A promise for the data sent back by the NuiCallbacks CB argument + */ + +const fetch = window.fetch; +// @ts-expect-error +window.fetch = () => {}; +// @ts-expect-error +window.XMLHttpRequest = window.fetch; + +export async function fetchNui(eventName: string, data?: any): Promise { + const options = { + method: 'post', + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + }, + body: JSON.stringify(data), + }; + + const resourceName = (window as any).GetParentResourceName + ? (window as any).GetParentResourceName() + : 'err_boilerplate'; + + const resp = await fetch(`https://${resourceName}/${eventName}`, options); + const respFormatted = await resp.json(); + + return respFormatted; +} \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/src/utils/getPosition.ts b/resources/[core]/esx_menu_default/web/src/utils/getPosition.ts new file mode 100644 index 0000000..3c4f52c --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/utils/getPosition.ts @@ -0,0 +1,27 @@ +export const GetPosition = (pos: string) => { + + pos = pos ? pos : "right-center" + + if (pos == "center") { + return "top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" + } + + const classes: string[] = []; + + + if (pos.includes("top")) { + classes.push("top-4"); + } else if (pos.includes("center")) { + classes.push("top-1/2", "-translate-y-1/2"); + } else { + classes.push("bottom-4"); + } + + if (pos.includes("left")) { + classes.push("left-4"); + } else { + classes.push("right-4"); + } + + return classes.join(" "); +} \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/src/utils/misc.ts b/resources/[core]/esx_menu_default/web/src/utils/misc.ts new file mode 100644 index 0000000..9f4a193 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/utils/misc.ts @@ -0,0 +1,41 @@ +// Will return whether the current environment is in a regular browser + +import { useEffect, useState } from "react"; + +// and not CEF +export const isEnvBrowser = (): boolean => !(window as any).invokeNative; + +// Basic no operation function +export const noop = () => { }; + +export const IsInputFocused = () => { + const [isFocused, setIsFocused] = useState(false); + + useEffect(() => { + const checkFocused = () => { + const element = document.activeElement as HTMLElement | null; + + if (element) { + setIsFocused( + element.tagName == "INPUT" || + element.tagName == "TEXTAREA" || + element.tagName == "SELECT" + ); + } else { + setIsFocused(false); + } + }; + + document.addEventListener("focusin", checkFocused); + document.addEventListener("focusout", checkFocused); + + checkFocused(); + + return () => { + document.removeEventListener("focusin", checkFocused); + document.removeEventListener("focusout", checkFocused); + }; + }, []); + + return isFocused; +}; \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/src/vite-env.d.ts b/resources/[core]/esx_menu_default/web/src/vite-env.d.ts new file mode 100644 index 0000000..151aa68 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/src/vite-env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/tailwind.config.js b/resources/[core]/esx_menu_default/web/tailwind.config.js new file mode 100644 index 0000000..34a1ce8 --- /dev/null +++ b/resources/[core]/esx_menu_default/web/tailwind.config.js @@ -0,0 +1,67 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: ["selector", "class"], + content: ["./src/**/*.{js,jsx,ts,tsx}"], + theme: { + extend: { + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + colors: { + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + chart: { + 1: "hsl(var(--chart-1))", + 2: "hsl(var(--chart-2))", + 3: "hsl(var(--chart-3))", + 4: "hsl(var(--chart-4))", + 5: "hsl(var(--chart-5))", + }, + sidebar: { + DEFAULT: "hsl(var(--sidebar-background))", + foreground: "hsl(var(--sidebar-foreground))", + primary: "hsl(var(--sidebar-primary))", + "primary-foreground": "hsl(var(--sidebar-primary-foreground))", + accent: "hsl(var(--sidebar-accent))", + "accent-foreground": "hsl(var(--sidebar-accent-foreground))", + border: "hsl(var(--sidebar-border))", + ring: "hsl(var(--sidebar-ring))", + }, + }, + }, + }, + plugins: [require("tailwindcss-animate")], +}; diff --git a/resources/[core]/esx_menu_default/web/tsconfig.json b/resources/[core]/esx_menu_default/web/tsconfig.json new file mode 100644 index 0000000..8d05dda --- /dev/null +++ b/resources/[core]/esx_menu_default/web/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} \ No newline at end of file diff --git a/resources/[core]/esx_menu_default/web/tsconfig.node.json b/resources/[core]/esx_menu_default/web/tsconfig.node.json new file mode 100644 index 0000000..cc2671e --- /dev/null +++ b/resources/[core]/esx_menu_default/web/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + }, + "include": ["vite.config.ts"] +} diff --git a/resources/[core]/esx_menu_default/web/vite.config.ts b/resources/[core]/esx_menu_default/web/vite.config.ts new file mode 100644 index 0000000..529474b --- /dev/null +++ b/resources/[core]/esx_menu_default/web/vite.config.ts @@ -0,0 +1,34 @@ +import * as path from "path"; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import tailwindcss from 'tailwindcss'; +import autoprefixer from 'autoprefixer'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + css: { + postcss: { + plugins: [ + tailwindcss, + autoprefixer, + ], + }, + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + server: { + port: 3000, + }, + base: './', + build: { + outDir: 'build', + target: 'esnext', + }, + esbuild: { + logOverride: { 'this-is-undefined-in-esm': 'silent' }, + }, +}); diff --git a/resources/[core]/esx_menu_dialog/LICENSE b/resources/[core]/esx_menu_dialog/LICENSE new file mode 100644 index 0000000..7b3fd1a --- /dev/null +++ b/resources/[core]/esx_menu_dialog/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + esx_menu_dialog + Copyright (C) 2015-2024 Jérémie N'gadi + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + esx_menu_dialog Copyright (C) 2015-2024 Jérémie N'gadi + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/resources/[core]/esx_menu_dialog/README.md b/resources/[core]/esx_menu_dialog/README.md new file mode 100644 index 0000000..038f95f --- /dev/null +++ b/resources/[core]/esx_menu_dialog/README.md @@ -0,0 +1,21 @@ +# esx_menu_dialog +Simple script used for inputs. + +## Installation +- Add this to your `server.cfg`: + +``` +start esx_menu_dialog +``` + +# Legal +### License +esx_menu_dialog - input dialog for ESX + +Copyright (C) 2015-2024 Jérémie N'gadi + +This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version. + +This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details. + +You should have received a copy Of the GNU General Public License along with this program. If Not, see http://www.gnu.org/licenses/. \ No newline at end of file diff --git a/resources/[core]/esx_menu_dialog/client/main.lua b/resources/[core]/esx_menu_dialog/client/main.lua new file mode 100644 index 0000000..8258818 --- /dev/null +++ b/resources/[core]/esx_menu_dialog/client/main.lua @@ -0,0 +1,93 @@ +local Timeouts, OpenedMenus, MenuType = {}, {}, "dialog" + +local function openMenu(namespace, name, data) + for i = 1, #Timeouts, 1 do + ESX.ClearTimeout(Timeouts[i]) + end + + OpenedMenus[namespace .. "_" .. name] = true + + SendNUIMessage({ + action = "openMenu", + namespace = namespace, + name = name, + data = data, + }) + + local timeoutId = ESX.SetTimeout(200, function() + SetNuiFocus(true, true) + end) + + table.insert(Timeouts, timeoutId) +end + +local function closeMenu(namespace, name) + OpenedMenus[namespace .. "_" .. name] = nil + + SendNUIMessage({ + action = "closeMenu", + namespace = namespace, + name = name, + }) + + if not next(OpenedMenus) then + SetNuiFocus(false, false) + end +end + +ESX.UI.Menu.RegisterType(MenuType, openMenu, closeMenu) + +AddEventHandler("esx_menu_dialog:message:menu_submit", function(data) + local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name) + local cancel = false + + if not menu then + return + end + + if menu.submit then + -- is the submitted data a number? + local value = tonumber(data.value) + if value then + data.value = ESX.Math.Round(value) + + -- check for negative value + if tonumber(data.value) <= 0 then + cancel = true + end + end + + data.value = ESX.Math.Trim(data.value) + + -- don't submit if the value is negative or if it's 0 + if cancel then + ESX.ShowNotification("That input is not allowed!") + else + menu.submit(data, menu) + end + end +end) + +AddEventHandler("esx_menu_dialog:message:menu_cancel", function(data) + local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name) + + if not menu then + return + end + + if menu.cancel ~= nil then + menu.cancel(data, menu) + end +end) + +AddEventHandler("esx_menu_dialog:message:menu_change", function(data) + local menu = ESX.UI.Menu.GetOpened(MenuType, data._namespace, data._name) + + if not menu then + return + end + + if menu.change ~= nil then + menu.change(data, menu) + end +end) diff --git a/resources/[core]/esx_menu_dialog/fxmanifest.lua b/resources/[core]/esx_menu_dialog/fxmanifest.lua new file mode 100644 index 0000000..f561dc3 --- /dev/null +++ b/resources/[core]/esx_menu_dialog/fxmanifest.lua @@ -0,0 +1,28 @@ +fx_version 'adamant' + +game 'gta5' +description 'A basic input dialog for ESX Legacy.' +lua54 'yes' +version '1.13.5' + +client_scripts { + '@es_extended/imports.lua', + '@es_extended/client/modules/wrapper.lua', + 'client/main.lua' +} + +ui_page 'html/ui.html' + +files { + 'html/ui.html', + + 'html/css/app.css', + + 'html/js/mustache.min.js', + 'html/js/app.js', + + 'html/fonts/pdown.ttf', + 'html/fonts/bankgothic.ttf' +} + +dependency 'es_extended' diff --git a/resources/[core]/esx_menu_dialog/html/css/app.css b/resources/[core]/esx_menu_dialog/html/css/app.css new file mode 100644 index 0000000..211a71e --- /dev/null +++ b/resources/[core]/esx_menu_dialog/html/css/app.css @@ -0,0 +1,132 @@ +@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"); + +#controls { + font-family: "Poppins", sans-serif; + font-size: 2.77vh; + color: #fff; + position: absolute; + bottom: 3.7vh; + right: 3.7vh; +} + +.controls { + display: none; +} + +.dialog { + font-family: "Poppins", sans-serif; + background: #212121; + color: #fff; + position: absolute; + border-radius: 0.46vh; + overflow: hidden; + top: 50%; + left: 50%; + width: 55.6vh; + height: 14.1vh; + padding-bottom: 1vh; + transform: translate(-50%, -50%); +} + +.head { + display: flex; + flex-basis: 100%; + align-items: center; + justify-content: center; + color: #fff; + font-size: 1.6vh; + font-weight: 500; + text-transform: uppercase; +} + +.dialog.big { + height: 18.5vh; +} + +.dialog .head { + background: #161616; + text-align: center; + height: 3.7vh; +} + +.dialog .head span::before { + content: ""; + display: inline-block; + height: 100%; + vertical-align: middle; +} + +.dialog input[type="text"] { + width: 60%; + height: 2.96vh; + outline: 0; + background: none; + text-align: center; + margin-top: 2.4vh; + margin-left: 11.6vh; + font-size: 1.48vh; + transition: all 0.2s ease-in-out; + color: white; + border: 0.05vh solid #ffffff3b; + border-radius: 0.3vh; +} + +.dialog input[type="text"]:active, +.dialog input[type="text"]:hover { + color: white; +} + +.dialog textarea { + width: 100%; + height: 11.85vh; +} + +.dialog button[name="submit"] { + width: 17.6%; + height: 2.96vh; + margin-left: 14.8vh; + font-weight: 500; + + color: #fb9b04; + border-radius: 0.5vh; + font-size: 1.2vh; + background: #fb9c0433; + outline: 0; + border: none; + transition: all 0.2s ease-in-out; +} + +.dialog button { + z-index: 9999; + transform: translate(-0%, 50%); +} + +.dialog button[name="cancel"] { + width: 17.6%; + height: 2.96vh; + margin-left: 5.6vh; + + font-weight: 500; + + color: #fefefe; + border-radius: 0.5vh; + font-size: 1.2vh; + background: #94949433; + outline: 0; + border: none; + transition: all 0.2s ease-in-out; +} + +.dialog button[name="cancel"]:hover { + letter-spacing: 0.09vh; + transform: scale(1.05) translate(-0%, 50%); +} + +.dialog button[name="submit"]:hover { + letter-spacing: 0.09vh; + transform: scale(1.05) translate(-0%, 50%); +} + +* { + font-family: Poppins !important; +} diff --git a/resources/[core]/esx_menu_dialog/html/fonts/bankgothic.ttf b/resources/[core]/esx_menu_dialog/html/fonts/bankgothic.ttf new file mode 100644 index 0000000..f3d8049 Binary files /dev/null and b/resources/[core]/esx_menu_dialog/html/fonts/bankgothic.ttf differ diff --git a/resources/[core]/esx_menu_dialog/html/fonts/pdown.ttf b/resources/[core]/esx_menu_dialog/html/fonts/pdown.ttf new file mode 100644 index 0000000..69c76cf Binary files /dev/null and b/resources/[core]/esx_menu_dialog/html/fonts/pdown.ttf differ diff --git a/resources/[core]/esx_menu_dialog/html/js/app.js b/resources/[core]/esx_menu_dialog/html/js/app.js new file mode 100644 index 0000000..9cbdf2b --- /dev/null +++ b/resources/[core]/esx_menu_dialog/html/js/app.js @@ -0,0 +1,181 @@ +(function () { + let MenuTpl = + '

+ +
+ + +
+ +
+ + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/index.js b/resources/[creators]/jobs_creator/html/index.js new file mode 100644 index 0000000..57c28d5 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/index.js @@ -0,0 +1,4453 @@ +/* +██╗░░░██╗████████╗██╗██╗░░░░░░██████╗ +██║░░░██║╚══██╔══╝██║██║░░░░░██╔════╝ +██║░░░██║░░░██║░░░██║██║░░░░░╚█████╗░ +██║░░░██║░░░██║░░░██║██║░░░░░░╚═══██╗ +╚██████╔╝░░░██║░░░██║███████╗██████╔╝ +░╚═════╝░░░░╚═╝░░░╚═╝╚══════╝╚═════╝░ +*/ +const resName = GetParentResourceName(); + +const allJobsStatisticsDiv = document.getElementById('all-jobs-statistics').getContext('2d'); +const jobStatisticsDiv = document.getElementById('job-statistics-chart').getContext('2d'); + +let TRANSLATIONS = {}; +let ENGLISH_TRANSLATIONS = {}; +let MARKERS_INFOS = {}; +let ACTIONS_LABELS = {}; + +function translateEverything() { + $("body").find("[data-translation-id], [data-bs-toggle='tooltip']").each(function() { + let translationId = $(this).data("translationId") + + if( $(this).data("bsToggle") == "tooltip" ) { + if ($(this).tooltip) { + $(this).tooltip('dispose'); + } + + $(this).attr("data-bs-title", getLocalizedText(translationId)); + $(this).tooltip(); + } else if( $(this).hasClass("form-control") ) { + $(this).attr("placeholder", getLocalizedText(translationId)); + } else { + $(this).prop("innerHTML", getLocalizedText(translationId)); + } + }) + + MARKERS_INFOS = { + ["stash"]: { + label: getLocalizedText("menu:dynamic:marker_info:stash"), + settingsName: getLocalizedText("menu:dynamic:marker_info:stash_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: false + }, + ["armory"]: { + label: getLocalizedText("menu:dynamic:marker_info:armory"), + settingsName: getLocalizedText("menu:dynamic:marker_info:armory_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true, + framework: "ESX" + }, + ["safe"]: { + label: getLocalizedText("menu:dynamic:marker_info:safe"), + settingsName: null, + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: false, + framework: "ESX" + }, + ["garage"]: { + label: getLocalizedText("menu:dynamic:marker_info:temporary_garage"), + settingsName: getLocalizedText("menu:dynamic:marker_info:temporary_garage_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["garage_buyable"]: { + label: getLocalizedText("menu:dynamic:marker_info:garage_buyable"), + settingsName: getLocalizedText("menu:dynamic:marker_info:garage_buyable_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["garage_owned"]: { + label: getLocalizedText("menu:dynamic:marker_info:garage_owned"), + settingsName: getLocalizedText("menu:dynamic:marker_info:garage_owned_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["boss"]: { + label: getLocalizedText("menu:dynamic:marker_info:boss"), + settingsName: getLocalizedText("menu:dynamic:marker_info:boss_settings"), + isJobMarker: true, + isPublicMarker: false, + requiresDataUpdate: true + }, + ["wardrobe"]: { + label: getLocalizedText("menu:dynamic:marker_info:wardrobe"), + settingsName: null, + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["job_outfit"]: { + label: getLocalizedText("menu:dynamic:marker_info:job_outfit"), + settingsName: getLocalizedText("menu:dynamic:marker_info:job_outfit_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["shop"]: { + label: getLocalizedText("menu:dynamic:marker_info:shop"), + settingsName: getLocalizedText("menu:dynamic:marker_info:shop_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["market"]: { + label: getLocalizedText("menu:dynamic:marker_info:market"), + settingsName: getLocalizedText("menu:dynamic:marker_info:market_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["harvest"]: { + label: getLocalizedText("menu:dynamic:marker_info:harvest"), + settingsName: getLocalizedText("menu:dynamic:marker_info:harvest_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["process"]: { + label: getLocalizedText("menu:dynamic:marker_info:process"), + settingsName: getLocalizedText("menu:dynamic:marker_info:process_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["crafting_table"]: { + label: getLocalizedText("menu:dynamic:marker_info:crafting_table"), + settingsName: getLocalizedText("menu:dynamic:marker_info:crafting_table_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["teleport"]: { + label: getLocalizedText("menu:dynamic:marker_info:teleport"), + settingsName: getLocalizedText("menu:dynamic:marker_info:teleport_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["weapon_upgrader"]: { + label: getLocalizedText("menu:dynamic:marker_info:weapon_upgrader"), + settingsName: getLocalizedText("menu:dynamic:marker_info:weapon_upgrader_settings"), + isJobMarker: true, + isPublicMarker: true, + requiresDataUpdate: true + }, + ["duty"]: { + label: getLocalizedText("menu:dynamic:marker_info:duty"), + settingsName: null, + isJobMarker: true, + isPublicMarker: false, + requiresDataUpdate: true + }, + ["job_shop"]: { + label: getLocalizedText("menu:dynamic:marker_info:job_shop"), + settingsName: getLocalizedText("menu:dynamic:marker_info:job_shop_settings"), + isJobMarker: false, + isPublicMarker: true, + requiresDataUpdate: true + }, + } + + ACTIONS_LABELS = [ + {action: "actionsMenuEnabled", label: getLocalizedText("menu:job_settings:can_open_actions_menu")}, + {action: "canRepairVehicles", label: getLocalizedText("menu:job_settings:enable_repair_vehicles")}, + {action: "canCheckDrivingLicense", label: getLocalizedText("menu:job_settings:enable_check_driving_license")}, + {action: "canCheckWeaponLicense", label: getLocalizedText("menu:job_settings:enable_check_weapon_license")}, + {action: "enableBilling", label: getLocalizedText("menu:job_settings:enable_billing")}, + {action: "canHandcuff", label: getLocalizedText("menu:job_settings:enable_handcuff_players")}, + {action: "placeableObjects", label: getLocalizedText("menu:job_settings:placeable_objects")}, + {action: "canLockpickCars", label: getLocalizedText("menu:job_settings:enable_lockpick_players")}, + {action: "whitelisted", label: getLocalizedText("menu:job_settings:whitelisted")}, + {action: "canRevive", label: getLocalizedText("menu:job_settings:enable_revive")}, + {action: "canWashVehicles", label: getLocalizedText("menu:job_settings:enable_wash_vehicles")}, + {action: "canRob", label: getLocalizedText("menu:job_settings:enable_search_players")}, + {action: "canCheckIdentity", label: getLocalizedText("menu:job_settings:enable_check_identities")}, + {action: "canImpoundVehicles", label: getLocalizedText("menu:job_settings:enable_impound_vehicles")}, + {action: "canCheckVehicleOwner", label: getLocalizedText("menu:job_settings:enable_check_vehicle_owner")}, + {action: "canHeal", label: getLocalizedText("menu:job_settings:enable_heal")}, + ] +} + +async function refreshTranslations(locale) { + let rawEnglishTranslations = await $.get("menu_translations/en.json"); + ENGLISH_TRANSLATIONS = typeof rawEnglishTranslations == "object" ? rawEnglishTranslations : JSON.parse(rawEnglishTranslations); + + let rawTranslations = await $.get(`menu_translations/${locale}.json`); + TRANSLATIONS = typeof rawTranslations == "object" ? rawTranslations : JSON.parse(rawTranslations); + + translateEverything(); +} + +async function loadTranslations() { + const locale = await $.post(`https://${resName}/getLocale`); + + refreshTranslations(locale); +} loadTranslations(); + +function getLocalizedText(text) { + return TRANSLATIONS[text] || ENGLISH_TRANSLATIONS[text] || text; +} + +async function getFramework() { + const framework = await $.post(`https://${resName}/getFramework`); + return framework; +} + +const allJobsStatisticsChart = new Chart(allJobsStatisticsDiv, { + type: 'bar', + + data: { + labels: "Jobs", + datasets: [] + }, + + options: { + scales: { + y: { + beginAtZero: true + } + }, + } +}); + +const jobStatisticsChart = new Chart(jobStatisticsDiv, { + type: 'bar', + + data: { + labels: "Ranks", + datasets: [] + }, + + options: { + scales: { + y: { + beginAtZero: true + } + }, + } +}); + +// Fetch all the forms we want to apply custom Bootstrap validation styles to +var forms = document.querySelectorAll('.needs-validation') + +// Loop over them and prevent submission +Array.prototype.slice.call(forms) +.forEach(function (form) { + form.addEventListener('submit', function (event) { + + event.preventDefault(); + + form.classList.add('was-validated') + }, false) +}) + +$(".max-two-decimals").change(function() { + if(isNaN(this.value)) { + return + } + + let number = parseFloat(this.value); + + if(number) { + this.value = number.toFixed(2); + } +}) + +function getValidId(text) { + text = text.toLowerCase(); + text = text.replace(/[^a-zA-Z0-9]/g,'_'); + + return text +} + +$(".id").on("input", function() { + let text = $(this).val(); + + + $(this).val( getValidId(text) ); +}) + +function componentToHex(c) { + var hex = c.toString(16); + + return hex.length == 1 ? "0" + hex : hex; + } + +function rgbToHex(r, g, b) { + return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); +} + +function hexToRgb(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +} + +function getVehicleLabel(vehicleModel, cb) { + $.post(`https://${resName}/get-vehicle-label`, JSON.stringify({vehicleModel: vehicleModel}), cb) +} + +// Disables enter +$(document).on("keypress", 'form', function (e) { + var code = e.keyCode || e.which; + if (code == 13) { + e.preventDefault(); + return false; + } +}); + +/* Dialogs */ +function inputDialog(title, data, yesCallback) { + $("#input-text-dialog-title").text(title); + + var inputModal = $("#input-text-dialog-modal"); + + // Removes old data + inputModal.find(".modal-body form").empty(); + + data.forEach(currentData => { + var id = currentData.id; + var label = currentData.label; + var defaultValue = currentData.default !== undefined ? currentData.default : ""; + + var type = currentData.type || "text"; + + if (type === "button") { + var button = $(``); + + button.click(function () { + currentData.buttonCallback(inputModal); + }); + + inputModal.find(".modal-body form").append(button); + } else if (type === "select") { + + var select = $(``) + var options = currentData.options + + options.forEach(option => { + var optionElement = $(``) + select.append(optionElement); + }) + + inputModal.find(".modal-body form").append(select); + } else if (type === "switch") { + + var switchInput = $(` +
+ + +
`); + + inputModal.find(".modal-body form").append(switchInput); + + $(`#modal-${id}`).prop("checked", defaultValue) + } else { + let isAnId = currentData.isId || false + var formGroup = $( + `
+ + +
Can't be empty
+
` + ) + + inputModal.find(".modal-body form").append(formGroup) + + let inputDiv = $(`#modal-${id}`); + + inputDiv.unbind('input'); + + if(isAnId) { + inputDiv.on('input', function() { + let text = inputDiv.val(); + text = text.toLowerCase(); + text = text.replace(/[^a-zA-Z0-9]/g,'_'); + + inputDiv.val(text); + }); + } + } + }) + + inputModal.modal("show"); + + $("#input-text-dialog-confirm").off('click'); + $("#input-text-dialog-confirm").click(function () { + var areInputsValid = true; + + var inputs = inputModal.find(".form-control, .form-select, :checkbox"); + var length = inputs.length; + + var data = {}; + + inputs.each(function (index, element) { + var text = $(element).val(); + if (text || $(element).is(":checkbox")) { + $(element).removeClass("is-invalid"); + var id = $(element).data("id"); + + if ($(element).is(":checkbox")) { + data[id] = $(element).is(':checked'); + } else { + data[id] = text; + } + } else { + $(element).addClass("is-invalid"); + areInputsValid = false; + } + }); + + inputModal.modal("hide"); + yesCallback(data); + }) +} + +function showError(msg){ + $("#notification-message").text(msg); + $("#notification-modal").modal("show"); +} + +function accountsDialog(cb) { + let accountsModal = $("#input-accounts-dialog-modal"); + let accountsList = $("#accounts-list"); + + $.post(`https://${resName}/getAllAccounts`, {}, function (accounts) { + accountsList.empty(); + + for(const[accountName, accountLabel] of Object.entries(accounts)) { + let accountDiv = $(` +
  • ${accountLabel}
  • + `); + + accountDiv.click(function() { + accountsModal.modal("hide"); + cb(accountName); + }); + + accountsList.append(accountDiv); + } + + accountsModal.modal("show"); + }) +} + +async function getCurrentCoordsAndHeading() { + return new Promise((resolve, reject) => { + $.post(`https://${resName}/get-current-coords`, {}, function (coords) { + resolve(coords); + }); + }); +} + +/* +██████╗░░█████╗░███╗░░██╗██╗░░██╗░██████╗ +██╔══██╗██╔══██╗████╗░██║██║░██╔╝██╔════╝ +██████╔╝███████║██╔██╗██║█████═╝░╚█████╗░ +██╔══██╗██╔══██║██║╚████║██╔═██╗░░╚═══██╗ +██║░░██║██║░░██║██║░╚███║██║░╚██╗██████╔╝ +╚═╝░░╚═╝╚═╝░░╚═╝╚═╝░░╚══╝╚═╝░░╚═╝╚═════╝░ +*/ +let ranksDataTable = $("#ranks-container").DataTable( { + "lengthMenu": [5, 10, 15, 20], + "pageLength": 10, + "createdRow": function ( row, data, index ) { + $(row).addClass("clickable"); + + $(row).click(function() { + let editRankModal = $("#edit-rank"); + + let rankId = data[0]; + let rankLabel = data[1]; + let rankName = data[2]; + let rankGrade = data[3]; + let rankSalary = data[4]; + + $("#edit-rank-label").val(rankLabel); + $("#edit-rank-name").val(rankName); + $("#edit-rank-grade").val(rankGrade); + $("#edit-rank-salary").val(rankSalary); + + editRankModal.data("rankId", rankId); + + editRankModal.modal("show"); + }) + }, + "columnDefs": [{"defaultContent": "???", "targets": "_all"}] +} ); + +async function deleteRank(jobName, rankId) { + if(! await confirmDeletion(getLocalizedText("menu:do_you_want_to_delete_the_rank"))) return; + + const data = await $.post(`https://${resName}/delete-rank`, JSON.stringify({ rankId: rankId })); + + // Removes deleted row + if (data.isSuccessful) { + refreshJobRanks(jobName) + } else { + showError(data.message) + } +} + +function fillJobRanks(ranks) { + ranksDataTable.clear(); + + for(const[_, gradeData] of Object.entries(ranks)) { + ranksDataTable.row.add( [gradeData.id, gradeData.label, gradeData.name, gradeData.grade, gradeData.salary] ); + } + + ranksDataTable.draw(); +} + +$("#edit-rank-form").submit(function(event) { + if (!this.checkValidity()) { + event.preventDefault(); + event.stopPropagation(); + + return; + } else { + $(this).removeClass("was-validated"); + $("#create-rank").modal("hide"); + } + + let data = { + rankLabel: $("#edit-rank-label").val(), + rankName: $("#edit-rank-name").val(), + rankGrade: parseInt( $("#edit-rank-grade").val() ), + rankSalary: parseInt( $("#edit-rank-salary").val() ), + rankId: $("#edit-rank").data("rankId") + } + + $.post(`https://${resName}/updateRank`, JSON.stringify(data), function (resultData) { + // Updates old row field with new values + if (resultData.isSuccessful) { + refreshJobRanks( $("#edit-job").data("jobName") ); + } else { + showError(resultData.message) + } + }); + + $("#edit-rank").modal("hide"); +}) + +$("#edit-rank-delete-btn").click(function() { + let jobName = $("#edit-job").data("jobName"); + let rankId = $("#edit-rank").data("rankId"); + + deleteRank(jobName, rankId); +}) + +$("#create-rank-btn").click(function() { + // Reset previous inputs + $("#create-rank-label").val(""); + $("#create-rank-name").val(""); + $("#create-rank-grade").val(""); + $("#create-rank-salary").val(""); + + $("#create-rank").modal("show"); +}); + +// Automatically fills the id from the label +$("#create-rank-label").on("input", function(){ + let label = $(this).val(); + + let id = getValidId(label); + + $("#create-rank-name").val(id); +}) + +// Automatically fills the id from the label +$("#edit-rank-label").on("input", function(){ + let label = $(this).val(); + + let id = getValidId(label); + + $("#edit-rank-name").val(id); +}) + +$("#create-rank-form").submit(function(event) { + if(isThereAnyErrorInForm(event)) return; + + let jobName = $("#edit-job").data("jobName"); + + let data = { + rankLabel: $("#create-rank-label").val(), + rankName: $("#create-rank-name").val(), + rankGrade: parseInt( $("#create-rank-grade").val() ), + rankSalary: parseInt( $("#create-rank-salary").val() ), + jobName: jobName + } + + $.post(`https://${resName}/create-new-rank`, JSON.stringify(data), function (data) { + if (data.isSuccessful) { + refreshJobRanks(jobName) + } else { + showError(data.message) + } + }); + + $("#create-rank").modal("hide"); +}) + +function refreshJobRanks(jobName) { + $.post(`https://${resName}/retrieveJobRanks`, JSON.stringify({ jobName: jobName }), function (ranks) { + if (ranks) { + fillJobRanks(ranks) + } + }); +} +/* +░░░░░██╗░█████╗░██████╗░░██████╗ +░░░░░██║██╔══██╗██╔══██╗██╔════╝ +░░░░░██║██║░░██║██████╦╝╚█████╗░ +██╗░░██║██║░░██║██╔══██╗░╚═══██╗ +╚█████╔╝╚█████╔╝██████╦╝██████╔╝ +░╚════╝░░╚════╝░╚═════╝░╚═════╝░ +*/ +var allJobs = {}; + +async function refresh() { + fillPublicMarkers(); + + const jobs = await $.post(`https://${resName}/getJobsData`, {}); + + allJobs = jobs; + + fillJobs(jobs); +} + +$("#create-job-btn").click(function () { + inputDialog(getLocalizedText("menu:create_new_job"), [ + { id: "jobLabel", label: getLocalizedText("menu:dynamic:new_job_label") }, + { id: "jobName", label: getLocalizedText("menu:dynamic:new_job_name"), isId: true }, + ], function (data) { + $.post(`https://${resName}/create-new-job`, JSON.stringify({ jobLabel: data.jobLabel, jobName: data.jobName }), function (data) { + if (data.isSuccessful) { + refresh() + } else { + showError(data.message) + } + }); + }); +}) + +function exitFromEditJob(){ + // Resets current active tab (ranks is the default one) + $("#edit-job").find(".nav-link, .tab-pane").each(function() { + if($(this).data("isDefault") == "1") { + $(this).addClass(["active", "show"]) + } else { + $(this).removeClass(["active", "show"]) + } + }) + + refresh(); + + $("#edit-job").hide(); + $("#job-creator").show(); +} + +async function deleteJob(jobName) { + if(! await confirmDeletion(getLocalizedText("menu:dynamic:delete_job_confirm"))) return; + + const data = await $.post(`https://${resName}/delete-job`, JSON.stringify({ jobName: jobName })); + + data.isSuccessful ? exitFromEditJob() : showError(data.message); +} + +$("#delete-job-btn").click(function() { + let jobName = $("#edit-job").data("jobName"); + deleteJob(jobName); +}) + +$("#edit-job-label").on("input", function(){ + let label = $(this).val(); + + let id = getValidId(label); + + $("#edit-job-name").val(id); +}) + +function editJob(jobData) { + let editJobDiv = $("#edit-job"); + + editJobDiv.data("jobName", jobData.name); + + // Chart with ranks + loadRanksDistrubutions(); + + // Job settings + $("#edit-job-label").val(jobData.label); + $("#edit-job-name").val(jobData.name); + + // Fills actions in settings + if(jobData.actions) { + for(const[actionName, isEnabled] of Object.entries(jobData.actions)) { + $("#job-settings-actions").find(`[data-action-name=${actionName}]`).prop("checked", isEnabled) + } + } + + // Fill placeable objects + $("#job-placeable-objects-list").empty(); + $("#job-placeable-objects-no-objects-text").show(); // It will be hidden if there are objects + + for(const [model, objectData] of Object.entries(jobData.actions?.placeableObjects || {})) { + addPlaceableObject(model, objectData.label, objectData.limit); + } + + $("#edit-job-text").text(jobData.label); + + fillJobRanks(jobData.ranks); + fillJobMarkers(); + + $("#job-creator").hide(); + editJobDiv.show(); + + jobTour(); +} + +$("#edit-job-close-btn").click(exitFromEditJob); + +function addPlaceableObject(model, label, limit) { + const div = $(` +
    + + +
    + + +
    + +
    + + +
    + +
    + + +
    +
    + `); + + div.find(".delete-object-btn").click(function() { + div.remove(); + + if($("#job-placeable-objects-list").children().length == 0) { + $("#job-placeable-objects-no-objects-text").show(); + } + }); + + div.find(".object-model").val(model || ""); + div.find(".object-label").val(label || ""); + div.find(".object-limit").val(limit || 1); + + $("#job-placeable-objects-no-objects-text").hide(); + + $("#job-placeable-objects-list").append(div); +} + +$("#job-placeable-objects-add-btn").click(function() { + addPlaceableObject(); +}); + +$("#job-settings").submit(function(event) { + if (!this.checkValidity()) { + event.stopPropagation(); + event.preventDefault(); + return; + } else { + $(this).removeClass("was-validated"); + } + + let actions = {}; + + $("#job-settings-actions").find(".job-action").each(function() { + let actionName = $(this).data("actionName"); + + actions[actionName] = $(this).prop("checked"); + }) + + let placeableObjects = {}; + + $("#job-placeable-objects-list").find(".placeable-object").each(function() { + let model = $(this).find(".object-model").val(); + + placeableObjects[model] = { + label: $(this).find(".object-label").val(), + limit: parseInt( $(this).find(".object-limit").val() ) + } + }); + + actions["placeableObjects"] = placeableObjects; + + let oldJobName = $("#edit-job").data("jobName"); + let jobName = $("#edit-job-name").val(); + let jobLabel = $("#edit-job-label").val(); + + let data = { + oldJobName, + jobName, + jobLabel, + actions + } + + $.post(`https://${resName}/update-job`, JSON.stringify(data), function (resultData) { + // Updates old job with new values + if (resultData.isSuccessful) { + exitFromEditJob(); + } else { + showError(resultData.message) + } + }); +}) + +let jobsDataTable = $("#jobs-container").DataTable( { + "lengthMenu": [5, 10, 15, 20], + "pageLength": 10, + "createdRow": function ( row, data, index ) { + $(row).addClass("clickable"); + + $(row).click(function() { + let jobName = data[1]; + + editJob(allJobs[jobName]) + }) + }, + "columnDefs": [{"defaultContent": "???", "targets": "_all"}] +} ); + +function fillJobs(jobs) { + jobsDataTable.clear(); + + for (const [_, job] of Object.entries(jobs)) { + jobsDataTable.row.add( [job.label, job.name, Object.entries(job.ranks).length] ); + } + + jobsDataTable.draw(); +} + +/* +███╗░░░███╗░█████╗░██████╗░██╗░░██╗███████╗██████╗░░██████╗ +████╗░████║██╔══██╗██╔══██╗██║░██╔╝██╔════╝██╔══██╗██╔════╝ +██╔████╔██║███████║██████╔╝█████═╝░█████╗░░██████╔╝╚█████╗░ +██║╚██╔╝██║██╔══██║██╔══██╗██╔═██╗░██╔══╝░░██╔══██╗░╚═══██╗ +██║░╚═╝░██║██║░░██║██║░░██║██║░╚██╗███████╗██║░░██║██████╔╝ +╚═╝░░░░░╚═╝╚═╝░░╚═╝╚═╝░░╚═╝╚═╝░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░ +*/ +let allMarkers = {}; + +let jobMarkersDataTable = $("#job-markers-container").DataTable( { + "lengthMenu": [5, 10, 15, 20], + "pageLength": 10, + "createdRow": function ( row, data, index ) { + $(row).find(".teleport-to-marker-btn").click(function(e) { + e.stopPropagation(); + // Close tooltip of this button + $(this).tooltip("hide"); + + $.post(`https://${resName}/teleportToMarker`, JSON.stringify({ markerId: parseInt(data[0]) })); + }).tooltip(); + + $(row).addClass("clickable"); + + $(row).click(function() { + let markerId = data[0]; + + editMarker(markerId); + }) + }, + "columnDefs": [ + { + "targets": -1, + "data": null, + "className": "col-1", + "defaultContent": ` +
    + +
    + ` + }, + {"defaultContent": "???", "targets": "_all"} + ], +} ); + +let publicMarkersDataTable = $("#public-markers-container").DataTable( { + "lengthMenu": [5, 10, 15, 20], + "pageLength": 10, + "createdRow": function ( row, data, index ) { + $(row).find(".teleport-to-marker-btn").click(function(e) { + e.stopPropagation(); + // Close tooltip of this button + $(this).tooltip("hide"); + + $.post(`https://${resName}/teleportToMarker`, JSON.stringify({ markerId: parseInt(data[0]) })); + }).tooltip(); + + $(row).addClass("clickable"); + + $(row).click(function() { + let markerId = data[0]; + + editMarker(markerId); + }) + }, + "columnDefs": [ + { + "targets": -1, + "data": null, + "className": "col-1", + "defaultContent": ` +
    + +
    + ` + }, + {"defaultContent": "???", "targets": "_all"} + ], +}); + +function fillJobMarkers(markerToEdit) { + let jobName = $("#edit-job").data("jobName"); + + $.post(`https://${resName}/retrieveJobMarkers`, JSON.stringify({ jobName: jobName }), function (markers) { + allMarkers = {}; + + // Manually insert each marker to avoid wrong conversion between lua table first index (1) and javascript object first index (0) + for(const[k, markerData] of Object.entries(markers)) { + allMarkers[markerData.id] = markerData; + } + + jobMarkersDataTable.clear(); + + for(const[_, markerData] of Object.entries(markers)) { + let typeLabel = MARKERS_INFOS[markerData.type]?.label; + + jobMarkersDataTable.row.add( [markerData.id || "Unknown", markerData.label || "No name", typeLabel, markerData.coords.x, markerData.coords.y, markerData.coords.z] ); + } + + jobMarkersDataTable.draw(); + + if(markerToEdit) { + editMarker(markerToEdit); + } + }) +} + +function fillPublicMarkers(markerToEdit) { + $.post(`https://${resName}/retrieveJobMarkers`, JSON.stringify({ jobName: "public_marker" }), function (markers) { + allMarkers = {}; + + // Manually insert each marker to avoid wrong conversion between lua table first index (1) and javascript object first index (0) + for(const[k, markerData] of Object.entries(markers)) { + allMarkers[markerData.id] = markerData; + } + + publicMarkersDataTable.clear(); + + for(const[_, markerData] of Object.entries(markers)) { + let typeLabel = MARKERS_INFOS[markerData.type]?.label; + + publicMarkersDataTable.row.add( [markerData.id, markerData.label || "No name", typeLabel, markerData.coords.x, markerData.coords.y, markerData.coords.z] ); + } + + publicMarkersDataTable.draw(); + + if(markerToEdit) { + editMarker(markerToEdit); + } + }) +} + +function getOffDutyName(name) { + return "off_" + name; +} + +function getOnDutyName(name) { + return name.replace("off_", ""); +} + +function isOffDutyName(name) { + return name.includes("off_"); +} + +async function createJobMarker(jobName) { + let allowedMarkers = []; + + for(const[markerType, markerInfo] of Object.entries(MARKERS_INFOS)) { + if(markerInfo.framework != undefined && markerInfo.framework != await getFramework()) continue; + if(!markerInfo.isJobMarker) continue; + + allowedMarkers.push({ + value: markerType, + label: markerInfo.label + }) + } + + inputDialog(getLocalizedText("menu:dynamic:job_markers:create_marker"), [ + { id: "markerType", label: "Marker Type:", type: "select", options: allowedMarkers }, + { id: "label", label: getLocalizedText("menu:dynamic:job_markers:label"), type: "text", default: getLocalizedText("menu:dynamic:default") }, + { id: "markerCoordsX", label: getLocalizedText("menu:dynamic:job_markers:coord_x"), type: "number" }, + { id: "markerCoordsY", label: getLocalizedText("menu:dynamic:job_markers:coord_y"), type: "number" }, + { id: "markerCoordsZ", label: getLocalizedText("menu:dynamic:job_markers:coord_z"), type: "number" }, + { + id: "currentCoordsBtn", label: getLocalizedText("menu:dynamic:job_markers:current_coords"), type: "button", buttonType: "btn-success", + buttonCallback: async function (modal) { + const coords = await placeEntity(); + if(!coords) return; + + modal.find("#modal-markerCoordsX").val(coords.x) + modal.find("#modal-markerCoordsY").val(coords.y) + modal.find("#modal-markerCoordsZ").val(coords.z) + } + }, + { id: "markerMinGrade", label: getLocalizedText("menu:dynamic:job_markers:min_grade"), type: "number", default: 0 }, + ], async function (data) { + data.jobName = jobName + + const resultData = await $.post(`https://${resName}/create-marker`, JSON.stringify(data)); + + if (resultData.isSuccessful) { + fillJobMarkers(resultData.markerId); + + if(!isOffDutyName(jobName) && await getFramework() == "ESX" && data.markerType == "duty") { + const duplicateForOffDuty = await swal({ + title: getLocalizedText("menu:note"), + text: getLocalizedText("menu:do_you_want_to_create_it_also_for_off_duty_job"), + icon: "info", + buttons: true, + dangerMode: false, + }); + + if(!duplicateForOffDuty) return; + + data.jobName = getOffDutyName(jobName); + + const resultData = await $.post(`https://${resName}/create-marker`, JSON.stringify(data)); + + if (resultData.isSuccessful) { + fillJobMarkers(resultData.markerId); + } else { + showError(resultData.message) + } + } + } else { + showError(resultData.message) + } + }) +} +$("#create-job-marker-btn").click(function() { + let jobName = $("#edit-job").data("jobName"); + + createJobMarker(jobName); +}) + +async function createPublicMarker() { + let allowedMarkers = []; + + for(const[markerType, markerInfo] of Object.entries(MARKERS_INFOS)) { + if(markerInfo.framework == undefined || markerInfo.framework == await getFramework()) { + if(markerInfo.isPublicMarker) { + allowedMarkers.push({ + value: markerType, + label: markerInfo.label + }) + } + } + } + + inputDialog(getLocalizedText("menu:dynamic:public_markers:create_public_marker"), [ + { id: "markerType", label: "Marker Type:", type: "select", options: allowedMarkers }, + { id: "label", label: getLocalizedText("menu:dynamic:public_markers:label"), type: "text", default: getLocalizedText("menu:dynamic:default") }, + { id: "markerCoordsX", label: getLocalizedText("menu:dynamic:public_markers:coord_x"), type: "number" }, + { id: "markerCoordsY", label: getLocalizedText("menu:dynamic:public_markers:coord_y"), type: "number" }, + { id: "markerCoordsZ", label: getLocalizedText("menu:dynamic:public_markers:coord_z"), type: "number" }, + { + id: "currentCoordsBtn", label: getLocalizedText("menu:dynamic:public_markers:current_coords"), type: "button", buttonType: "btn-success", + buttonCallback: async function (modal) { + const coords = await placeEntity(); + if(!coords) return; + + modal.find("#modal-markerCoordsX").val(coords.x) + modal.find("#modal-markerCoordsY").val(coords.y) + modal.find("#modal-markerCoordsZ").val(coords.z) + } + }, + ], function (data) { + $.post(`https://${resName}/create-public-marker`, JSON.stringify(data), function (data) { + if (data.isSuccessful) { + fillPublicMarkers(data.markerId); + } else { + showError(data.message) + } + }); + }) +} +$("#create-public-marker-btn").click(createPublicMarker); + +function hideAllMarkerSettings() { + $("#edit-marker-form").find(".edit-marker-settings").each(function() { + $(this).find(".form-control").each(function(index, element) { + if($(element).prop("required")) { + $(element).prop("required", false); + $(element).data("isActuallyRequired", true); + } + }); + + $(this).hide(); + }) +} + +function showMarkerSettings(markerType) { + hideAllMarkerSettings(); + + $("#edit-marker-form").find(`.edit-marker-settings`).each(function() { + if( $(this).data("markerType") != markerType ) return; + + $(this).find(".form-control").each(function(index, element) { + if( $(element).data("isActuallyRequired") ) { + $(element).prop("required", true); + } + }); + + $(this).show(); + + return; + }) +} + +function editMarker(markerId) { + $("#edit-marker-form").removeClass("was-validated"); + + let markerData = allMarkers[markerId]; + + if(!markerData) { + console.log("Couldn't find marker " + markerId); + + console.log(`Existing markers for job '${ $("#edit-job").data("jobName") }': `) + + for(const[key, value] of Object.entries(allMarkers)) { + console.log(` Marker ID '${key}'`); + } + + + return + } + + let isMarkerPublic = markerData.jobName == "public_marker"; + + $("#edit-marker-form").data("isPublic", isMarkerPublic); + + $("#edit-marker-label").val(markerData.label); + $("#edit-marker-type").val(markerData.markerType); + + changeMarkerGradeType(markerData.gradesType); + + if(markerData.gradesType === "specificGrades") { + setSpecificGrades(markerData.specificGrades); + } else if(markerData.gradesType === "minimumGrade") { + $("#edit-marker-min-grade").val(markerData.minGrade); + } + + $("#edit-marker-scale-x").val(markerData.scale.x); + $("#edit-marker-scale-y").val(markerData.scale.y); + $("#edit-marker-scale-z").val(markerData.scale.z); + + $("#edit-marker-coord-x").val(markerData.coords.x); + $("#edit-marker-coord-y").val(markerData.coords.y); + $("#edit-marker-coord-z").val(markerData.coords.z); + + $("#edit-marker-color").val(rgbToHex(markerData.color.r, markerData.color.g, markerData.color.b)); + $("#edit-marker-alpha").val(markerData.color.alpha); + + // Map blip + $("#edit-marker-sprite-id").val(markerData.blip?.spriteId); + $("#edit-marker-blip-color").val(markerData.blip?.color); + $("#edit-marker-blip-scale").val(markerData.blip?.scale); + toggleBlipInputs(markerData.blip?.spriteId ? true : false); + + // NPC + $("#edit-marker-npc-model").val(markerData.ped?.model); + $("#edit-marker-npc-heading").val(markerData.ped?.heading); + toggleNpcInputs(markerData.ped?.model ? true : false); + + // Object + $("#edit-marker-object-model").val(markerData.object?.model); + $("#edit-marker-object-heading").val(markerData.object?.heading); + toggleObjectInputs(markerData.object?.model ? true : false); + + // Minimum grade / specific grade inputs + $("#edit-marker-min-grade").prop("disabled", isMarkerPublic); + $("input[name=markerGradeType]").prop("disabled", isMarkerPublic); + $("#edit-marker-min-grade").val(markerData.minGrade || 0); + + let settingsLabel = MARKERS_INFOS[markerData.type].settingsName; + + if(settingsLabel) { + $("#specific-marker-settings").show(); + $("#specific-marker-settings-label").text(settingsLabel); + + showMarkerSettings(markerData.type); + } else { + $("#specific-marker-settings").hide(); + hideAllMarkerSettings(); + } + + setCurrentMarkerData(markerData.type, markerData.data); + + let editMarkerModal = $("#edit-marker-dialog-modal"); + + editMarkerModal.modal("show"); + editMarkerModal.data("markerId", markerId); +} + +function changeMarkerGradeType(type) { + $(`input[type=radio][name="markerGradeType"][value="${type}"]`).prop("checked", true); + + switch(type) { + case "minimumGrade": { + $("#edit-marker-min-grade").prop("required", true); + + $("#edit-marker-min-grade-form").show(); + $("#edit-marker-specific-grades-form").hide(); + break; + } + + case "specificGrades": { + $("#edit-marker-min-grade").prop("required", false); + + $("#edit-marker-min-grade-form").hide(); + $("#edit-marker-specific-grades-form").show(); + break; + } + } +} + +$("input[type=radio][name=markerGradeType").change(function() { + let gradesType = $(this).val(); + + changeMarkerGradeType(gradesType); +}) + +function addVehicleToTemporaryGarage(vehicleModel, vehicleData) { + vehicleData = vehicleData || {} + + let vehiclesTable = $("#garage-data-model-tbody") + + let vehiclePrimaryColor = vehicleData.primaryColor || "#111111" + let vehicleSecondaryColor = vehicleData.secondaryColor || "#111111" + let livery = vehicleData.livery; + + let customPlate = vehicleData.plate || ""; + + let deleteVehicleBtn = $(``) + + let vehicleTableRow = $(` + + +

    ${vehicleModel}

    + + +

    ${vehicleModel}

    + + + + + + + + + + + + + + + + `) + + getVehicleLabel(vehicleModel, (vehicleLabel) => { + vehicleTableRow.find(".vehicle-label").text(vehicleLabel) + }) + + vehiclesTable.append(vehicleTableRow); + + vehicleTableRow.find(".delete-vehicle-btn").append(deleteVehicleBtn) + + $(deleteVehicleBtn).click(function () { + $(this).parents(".vehicle").remove(); + }); +} + +$("#garage-owned-current-coords").click(function() { + $.post(`https://${resName}/get-current-coords`, {}, function (data) { + var coords = data.coords; + var heading = data.heading; + + if (coords) { + $("#garage-owned-spawnpoint-x").val(coords.x) + $("#garage-owned-spawnpoint-y").val(coords.y) + $("#garage-owned-spawnpoint-z").val(coords.z) + } + + if (heading) { + $("#garage-owned-heading").val(heading) + } + }) +}); + +function toggleBlipInputs(isEnabled) { + $("#edit-marker-map-blip").prop("checked", isEnabled); + + $("#edit-marker-map-blip-inputs").find(".form-control").each(function() { + $(this).prop("disabled", !isEnabled); + $(this).prop("required", isEnabled); + }) +} + +function toggleNpcInputs(isEnabled) { + $("#edit-marker-npc").prop("checked", isEnabled); + + $("#edit-marker-npc-inputs").find(".form-control").each(function() { + $(this).prop("disabled", !isEnabled); + $(this).prop("required", isEnabled); + }) +} + +function toggleObjectInputs(isEnabled) { + $("#edit-marker-object").prop("checked", isEnabled); + + $("#edit-marker-object-inputs").find(".form-control").each(function() { + $(this).prop("disabled", !isEnabled); + $(this).prop("required", isEnabled); + }) +} + +// Boss marker settings +function toggleBossWashMoneyOptions(isEnabled) { + $("#boss-data-washmoney-percentage").prop("required", isEnabled); + $("#boss-data-washmoney-percentage").prop("disabled", !isEnabled); + $("#boss-data-washmoney-to-society-account").prop("disabled", !isEnabled); +} + +$("#boss-data-washmoney").change(function() { + toggleBossWashMoneyOptions( $(this).prop("checked") ); +}) + + +// Harvestable items settings +$("#harvest-item-requires-tool").change(function() { + const isEnabled = $(this).prop("checked"); + $("#harvest-item-tool-div").find("input, button").prop("required", isEnabled).prop("disabled", !isEnabled); + + $("#harvest-item-tool-lose-on-use").prop("disabled", !isEnabled); + + if(!isEnabled) { + $("#harvest-item-tool-lose-on-use").prop("checked", false).change(); + } +}) + +$("#harvest-item-tool-lose-on-use").change(function() { + const isEnabled = $(this).prop("checked"); + + $("#harvest-item-tool-lose-quantity") + .prop("required", isEnabled) + .prop("disabled", !isEnabled); + + $("#harvest-item-tool-lose-probability") + .prop("required", isEnabled) + .prop("disabled", !isEnabled); +}) + +$("#harvest-disappear-after-use").change(function() { + toggleDisappearsAfterUse( $(this).prop("checked") ); + $("#harvest-disappear-seconds") + .prop("required", isEnabled) + .prop("disabled", !isEnabled); +}) + +function toggleDisappearsAfterUse(isEnabled) { + $("#harvest-disappear-after-use").prop("checked", isEnabled); + + $("#harvest-disappear-seconds").prop("required", isEnabled); + $("#harvest-disappear-seconds").prop("disabled", !isEnabled); +} + +$("#harvest-requires-minimum-account-money").change(function() { + let isEnabled = $(this).prop("checked"); + + $("#harvest-minimum-account-name-div").find("input, button").prop("disabled", !isEnabled); + $("#harvest-minimum-account-name-div").find("input, button").prop("required", isEnabled); +}); + +// Marker generic settings +$("#edit-marker-map-blip").change(function(){ + let isEnabled = $(this).prop("checked"); + + toggleBlipInputs(isEnabled); +}) + +$("#edit-marker-npc").change(function(){ + let isEnabled = $(this).prop("checked"); + + toggleNpcInputs(isEnabled); +}) + +$("#edit-marker-object").change(function(){ + let isEnabled = $(this).prop("checked"); + + toggleObjectInputs(isEnabled); +}) + +$("#edit-marker-current-coords-btn").click(async function(){ + const npcModel = $("#edit-marker-npc").prop("checked") ? $("#edit-marker-npc-model").val() : null; + const objectModel = $("#edit-marker-object") ? $("#edit-marker-object-model").val() : null; + + if(npcModel) { + var data = await placeEntity(npcModel, "ped"); + } else if(objectModel) { + var data = await placeEntity(objectModel, "object"); + } else { + var data = await placeEntity(); + } + + if(!data) return; + + if(npcModel || objectModel) { + $("#edit-marker-coord-x").val(data.coords.x) + $("#edit-marker-coord-y").val(data.coords.y) + $("#edit-marker-coord-z").val(data.coords.z) + + if(npcModel) + $("#edit-marker-npc-heading").val(data.heading); + + if(objectModel) + $("#edit-marker-object-heading").val(data.heading); + + } else { + $("#edit-marker-coord-x").val(data.x) + $("#edit-marker-coord-y").val(data.y) + $("#edit-marker-coord-z").val(data.z) + } +}) + +$("#delete-marker-btn").click(async function(){ + let editMarkerModal = $("#edit-marker-dialog-modal"); + let markerId = editMarkerModal.data("markerId"); + + editMarkerModal.modal("hide"); + if(!markerId) return; + + if(! await confirmDeletion(getLocalizedText("menu:do_you_want_to_delete_this_marker"))) return; + + const data = await $.post(`https://${resName}/delete-marker`, JSON.stringify({ markerId: markerId })) + + if (!data.isSuccessful) { + showError(data.message); + return + } + + if( $("#edit-marker-form").data("isPublic") ) { + fillPublicMarkers(); + } else { + fillJobMarkers(); + } +}) + +async function getOpenExternalClothingMenu() { + return await $.post(`https://${resName}/getOpenExternalClothingMenu`); +} + +async function getInventoryScriptUsed() { + return await $.post(`https://${resName}/getInventoryScriptUsed`); +} + +async function setCurrentMarkerData(markerType, markerData) { + // Resets animations from old opened marker + $("#edit-marker-dialog-modal").data("animations", []); + + markerData = markerData || {}; + + switch(markerType) { + case "garage": { + let spawnpointsDiv = $("#temporary-garage-spawnpoints-list"); + spawnpointsDiv.empty(); + if (markerData.spawnPoints) { + markerData.spawnPoints.forEach(spawnPointData => { + addGarageSpawnpoint(spawnpointsDiv, spawnPointData); + }) + } + + $("#garage-data-model-tbody").empty(); + + if (markerData.vehicles) { + for (const [vehicleModel, vehicleData] of Object.entries(markerData.vehicles)) { + addVehicleToTemporaryGarage(vehicleModel, vehicleData) + } + } + + break; + } + + case "garage_buyable": { + let spawnpointsDiv = $("#buyable-garage-spawnpoints-list"); + spawnpointsDiv.empty(); + if (markerData.spawnPoints) { + markerData.spawnPoints.forEach(spawnPointData => { + addGarageSpawnpoint(spawnpointsDiv, spawnPointData); + }) + } + + $("#garage-buyable-vehicles").empty(); + + if(markerData.vehicles) { + for (const [vehicleName, price] of Object.entries(markerData.vehicles)) { + var vehicleInputGroup = $(`
    `) + + var vehicleInput = $(``); + var moneySpan = $(`$`) + var vehiclePrice = $(``); + var deleteVehicle = $(``); + + vehicleInputGroup.append(vehicleInput, moneySpan, vehiclePrice, deleteVehicle); + + $(deleteVehicle).click(function () { + $(this).parent().remove(); + }) + + $("#garage-buyable-vehicles").append(vehicleInputGroup) + } + } + + $("#garage-buyable-vehicle-model").val(""); + $("#garage-buyable-vehicle-price").val(""); + + break; + } + + case "garage_owned": { + let spawnpointsDiv = $("#owned-garage-spawnpoints-list"); + spawnpointsDiv.empty(); + if (markerData.spawnPoints) { + markerData.spawnPoints.forEach(spawnPointData => { + addGarageSpawnpoint(spawnpointsDiv, spawnPointData); + }) + } + + break; + } + + case "boss": { + let canWashMoney = markerData.canWashMoney; + let canWithdraw = markerData.canWithdraw; + let canDeposit = markerData.canDeposit; + let canEmployees = markerData.canEmployees; + let canGrades = markerData.canGrades; + + toggleBossWashMoneyOptions(canWashMoney); + + if(canWashMoney) { + $("#boss-data-washmoney-percentage").val(markerData.washMoneyReturnPercentage); + $("#boss-data-washmoney-to-society-account").prop("checked", markerData.washMoneyGoesToSocietyAccount); + } + + $("#boss-data-washmoney").prop('checked', canWashMoney); + $("#boss-data-withdraw").prop('checked', canWithdraw); + $("#boss-data-deposit").prop('checked', canDeposit); + $("#boss-data-employees").prop('checked', canEmployees); + $("#boss-data-grades").prop('checked', canGrades); + + $("#boss-data-max-salary").val(markerData.maxSalary); + + break; + } + + case "shop": { + setChoosenObject( $("#shop-new-item-name-div"), null ); + + $("#shop-data-item-price").val("") + $('#shop-data-items-container').empty(); + + if (markerData.itemsOnSale) { + markerData.itemsOnSale.forEach(itemData => { + addItemToShop(itemData.object, itemData) + }) + } + + break; + } + + case "market": { + $("#market-modal-items-tbody").empty(); + + markerData?.items?.forEach(item => { + addItemToMarket(item.object, item.minPrice, item.maxPrice, item.blackMoney, item.sellTime); + }) + + $("#market-modal-society-percentage").val(markerData.percentageForSociety); + + break; + } + + case "crafting_table": { + let craftablesDiv = $("#craftables"); + + craftablesDiv.empty(); + + if(markerData.craftablesItems) { + markerData.craftablesItems.forEach(craftableItem => { + addNewCraftableToCraftables(craftableItem.resultObject, craftableItem) + }) + } + + break; + } + + case "armory": { + $("#armory-is-shared").prop("checked", markerData.isShared); + $("#armory-refill-on-take").prop("checked", markerData.refillOnTake); + + break; + } + + case "job_outfit": { + $("#job-outfit-outfits").empty(); + + if(!markerData.outfits) return; + + const openExternalClothingMenu = await getOpenExternalClothingMenu(); + + if(openExternalClothingMenu) { + hideAllMarkerSettings(); + $("#specific-marker-settings").hide(); + + swal(getLocalizedText("menu:note"), getLocalizedText("menu:job_outfit_warning"), "info"); + return; + } + + markerData.outfits.forEach(outfit => { + createNewOutfit(outfit) + }) + + break; + } + + case "teleport": { + if(markerData.teleportCoords) { + $("#teleport-x").val(markerData.teleportCoords.x); + $("#teleport-y").val(markerData.teleportCoords.y); + $("#teleport-z").val(markerData.teleportCoords.z); + } + + break; + } + + case "harvest": { + $("#harvest-modal-items").empty(); + + if(markerData.harvestableItems) { + markerData.harvestableItems.forEach(item => { + addItemToHarvestable(item.object, item.minQuantity, item.maxQuantity, item.time, item.chances); + }); + } + + if(markerData.animations) { + $("#edit-marker-dialog-modal").data("animations", markerData.animations) + } + + $("#harvest-item-requires-tool").prop("checked", markerData.itemTool != undefined).change(); + setChoosenObject( $("#harvest-item-tool-div"), markerData.itemTool ) + + $("#harvest-item-tool-lose-on-use").prop("checked", markerData.itemToolLoseQuantity).change(); + $("#harvest-item-tool-lose-quantity").val(markerData.itemToolLoseQuantity); + $("#harvest-item-tool-lose-probability").val(markerData.itemToolLoseProbability); + + toggleDisappearsAfterUse(markerData.disappearAfterUse); + $("#harvest-disappear-seconds").val(markerData.disappearSeconds); + + $("#harvest-requires-minimum-account-money").prop("checked", markerData.requiresMinimumAccountMoney || false).change(); + $("#harvest-minimum-account-name").val(markerData.minimumAccountName); + $("#harvest-minimum-account-amount").val(markerData.minimumAccountAmount); + + break; + } + + case "process": { + setChoosenObject( $("#process-modal-remove-item-div"), markerData.itemToRemove); + $("#item-to-remove-quantity").val(markerData?.itemToRemoveQuantity || 1); + + setChoosenObject( $("#process-modal-give-item-div"), markerData.itemToAdd); + $("#item-to-add-quantity").val(markerData?.itemToAddQuantity || 1); + + $("#process-time").val(markerData?.timeToProcess || 5); + $("#edit-marker-dialog-modal").data("animations", markerData?.animations) + $("#process-requires-minimum-account-money").prop("checked", markerData.requiresMinimumAccountMoney || false).change(); + $("#process-minimum-account-name").val(markerData.minimumAccountName); + $("#process-minimum-account-amount").val(markerData.minimumAccountAmount); + + break; + } + + case "weapon_upgrader": { + if(markerData.componentsPrices) { + // set empty all, so disabled components will remain disabled + $("#weapon-upgrader-components").find(".form-control").each(function() { + $(this).val(""); + }) + + for(const [componentName, componentPrice] of Object.entries(markerData.componentsPrices)) { + $("#weapon-upgrader-components").find(`[data-componentname=${componentName}]`).val(componentPrice); + } + } + + if(markerData.tintsPrices) { + // set empty all, so disabled tints will remain disabled + $("#weapon-upgrader-tints").find(".form-control").each(function() { + $(this).val(""); + }) + + for(const [tintId, tintPrice] of Object.entries(markerData.tintsPrices)) { + $("#weapon-upgrader-tints").find(`[data-tintid=${tintId}]`).val(tintPrice); + } + } + + break; + } + + case "job_shop": { + let allJobsSelect = $("#job-shop-all-jobs"); + + allJobsSelect.find(".job-shop-job").remove(); + + const jobs = await $.post(`https://${resName}/getJobsData`); + let jobsRanks = {} + + for(const [_, jobData] of Object.entries(jobs)) { + if(jobData.name) { + let jobDiv = $(``); + + jobsRanks[jobData.name] = jobData.ranks + allJobsSelect.append(jobDiv); + } + } + + allJobsSelect.data("ranks", jobsRanks); + + $("#job-shop-all-jobs").val(markerData.allowedJob).change(); + $("#job-shop-all-ranks").val(markerData.minimumRank); + + break; + } + } +} + +function getCurrentMarkerData(markerType) { + let markerData = {}; + + switch(markerType) { + case "garage": { + let vehicles = {}; + + let vehiclesObject = $("#garage-data-model-tbody").children(".vehicle"); + + vehiclesObject.each(function (index, element) { + let vehicleModel = $(element).find(".vehicle-model").text(); + let vehiclePrimaryColor = $(element).find(".vehicle-primary-color").val(); + let vehicleSecondaryColor = $(element).find(".vehicle-secondary-color").val(); + let vehicleLivery = parseInt( $(element).find(".vehicle-livery").val() ); + let vehiclePlate = $(element).find(".vehicle-custom-plate").val(); + + vehicles[vehicleModel] = { + primaryColor: vehiclePrimaryColor, + secondaryColor: vehicleSecondaryColor, + livery: vehicleLivery || null, + plate: vehiclePlate || null + } + }) + + markerData = { + vehicles: vehicles, + spawnPoints: getGarageSpawnpoints( $("#temporary-garage-spawnpoints-list") ), + } + + break; + } + + case "garage_buyable": { + let vehicles = {}; + let vehiclesObject = $("#garage-buyable-vehicles").find(".vehicle"); + + vehiclesObject.each(function (index, element) { + let model = $(element).find(".vehicle-model").val(); + let price = parseInt( $(element).find(".vehicle-price").val() ); + + vehicles[model] = price; + }); + + markerData = { + spawnPoints: getGarageSpawnpoints( $("#buyable-garage-spawnpoints-list") ), + vehicles: vehicles + } + + break; + } + + case "garage_owned": { + markerData = { + spawnPoints: getGarageSpawnpoints( $("#owned-garage-spawnpoints-list") ), + } + + break; + } + + case "boss": { + let canWashMoney = $("#boss-data-washmoney").prop('checked') + let canWithdraw = $("#boss-data-withdraw").prop('checked') + let canDeposit = $("#boss-data-deposit").prop('checked') + let canEmployees = $("#boss-data-employees").prop('checked') + let canGrades = $("#boss-data-grades").prop('checked') + + if(canWashMoney) { + var washMoneyReturnPercentage = parseInt($("#boss-data-washmoney-percentage").val()); + var washMoneyGoesToSocietyAccount = $("#boss-data-washmoney-to-society-account").prop("checked"); + } + + markerData = { + canWashMoney: canWashMoney, + washMoneyReturnPercentage: washMoneyReturnPercentage, + washMoneyGoesToSocietyAccount: washMoneyGoesToSocietyAccount, + canWithdraw: canWithdraw, + canDeposit: canDeposit, + canEmployees: canEmployees, + canGrades: canGrades, + maxSalary: parseInt( $("#boss-data-max-salary").val() ), + } + + break; + } + + case "shop": { + let itemsOnSale = []; + + let itemsContainer = $("#shop-data-items-container") + + itemsContainer.children().each(function (index, element) { + let object = $(element).data("object"); + let itemPrice = $(element).data("item-price"); + let blackMoney = $(element).find(".item-blackmoney").prop("checked"); + + if (!object || itemPrice === undefined) return; + + itemsOnSale.push({ + object, + price: itemPrice, + blackMoney + }) + }) + + markerData = { + itemsOnSale: itemsOnSale + } + + break; + } + + case "market": { + let items = []; + + let marketBodyDiv = $("#market-modal-items-tbody") + + let itemsDivs = marketBodyDiv.children(".item") + + itemsDivs.each(function(index, element) { + let itemDiv = $(element) + + let object = itemDiv.data("object"); + let itemMinPrice = parseInt(itemDiv.find(".item-min-price").text()); + let itemMaxPrice = parseInt(itemDiv.find(".item-max-price").text()); + let blackMoney = itemDiv.find(".item-blackmoney").prop("checked") + let sellTime = parseInt(itemDiv.find(".item-selltime").val()); + + items.push({ + object, + minPrice: itemMinPrice, + maxPrice: itemMaxPrice, + blackMoney: blackMoney, + sellTime: sellTime + }); + }); + + markerData = { + items: items, + percentageForSociety: parseInt( $("#market-modal-society-percentage").val() ) + } + + break; + } + + case "crafting_table": { + let craftablesItems = []; + + $("#craftables").children().each(function(craftableIndex, craftableElement) { + let craftable = $(craftableElement); + + let resultObject = getChoosenObject( craftable.find('.craftable-object-div') ); + let resultItemQuantity = parseInt( craftable.find('.result-item-quantity').val() ); + let resultItemCraftingTime = parseInt( craftable.find('.result-item-crafting-time').val() ); + + let recipes = []; + + craftable.find('.craft-ingredients').children().each(function(ingredientIndex, ingredientElement){ + var ingredientDiv = $(ingredientElement) + + var ingredientObject = ingredientDiv.data("object"); + var ingredientQuantity = ingredientDiv.data("item-quantity"); + var loseOnUse = ingredientDiv.find(".lose-on-use-checkbox").prop("checked") + + recipes.push({ + object: ingredientObject, + quantity: ingredientQuantity, + loseOnUse + }); + }) + + craftablesItems.push({ + resultObject, + recipes, + animations: craftable.data("animations"), + quantity: resultItemQuantity || 1, + craftingTime: resultItemCraftingTime || 8 + }); + }) + + markerData = { craftablesItems } + + break; + } + + case "armory": { + markerData = { + isShared: $("#armory-is-shared").prop("checked"), + refillOnTake: $("#armory-refill-on-take").prop("checked") + } + + break; + } + + case "job_outfit": { + let jobOutfitsDiv = $("#job-outfit-outfits"); + let outfitsDiv = jobOutfitsDiv.children(); + + let outfits = []; + + outfitsDiv.each(function(index, outfitDivRaw){ + let outfitDiv = $(outfitDivRaw); + + let outfit = getOutfitFromOutfitDiv(outfitDiv); + + outfits.push(outfit); + }) + + markerData = { + outfits: outfits + } + + break; + } + + case "teleport": { + markerData = { + teleportCoords: { + x: parseFloat( $(`#teleport-x`).val() ), + y: parseFloat( $(`#teleport-y`).val() ), + z: parseFloat( $(`#teleport-z`).val() ), + } + } + + break; + } + + case "harvest": { + let harvestableItems = []; + + $("#harvest-modal-items").find(".harvestable-item").each(function(index, element) { + let harvestableItem = { + object: getChoosenObject( $(this).find(".harvest-object-div") ), + minQuantity: parseInt( $(this).find(".harvest-item-min-quantity").val() ), + maxQuantity: parseInt( $(this).find(".harvest-item-max-quantity").val() ), + time: parseInt( $(this).find(".harvest-item-time").val() ), + chances: parseInt( $(this).find(".harvest-item-chance").val()), + }; + + harvestableItems.push(harvestableItem); + }) + + if($("#harvest-item-requires-tool").prop("checked")) { + var itemTool = getChoosenObject( $("#harvest-item-tool-div") ); + } + + if($("#harvest-item-tool-lose-on-use").prop("checked")) { + var itemToolLoseQuantity = parseInt($("#harvest-item-tool-lose-quantity").val()); + var itemToolLoseProbability = parseInt( $("#harvest-item-tool-lose-probability").val() ); + } + + markerData = { + harvestableItems, + animations: $("#edit-marker-dialog-modal").data("animations"), + + itemTool, + itemToolLoseQuantity, + itemToolLoseProbability, + + disappearAfterUse: $("#harvest-disappear-after-use").prop("checked"), + disappearSeconds: parseInt( $("#harvest-disappear-seconds").val() ), + + requiresMinimumAccountMoney: $("#harvest-requires-minimum-account-money").prop("checked"), + minimumAccountName: $("#harvest-minimum-account-name").val(), + minimumAccountAmount: parseInt( $("#harvest-minimum-account-amount").val() ), + } + + break; + } + + case "process": { + markerData = { + itemToRemove: getChoosenObject( $("#process-modal-remove-item-div") ), + itemToRemoveQuantity: parseInt($("#item-to-remove-quantity").val()), + itemToAdd: getChoosenObject( $("#process-modal-give-item-div") ), + itemToAddQuantity: parseInt($("#item-to-add-quantity").val()), + timeToProcess: parseInt($("#process-time").val()), + animations: $("#edit-marker-dialog-modal").data("animations"), + + requiresMinimumAccountMoney: $("#process-requires-minimum-account-money").prop("checked"), + minimumAccountName: $("#process-minimum-account-name").val(), + minimumAccountAmount: parseInt( $("#process-minimum-account-amount").val() ) + } + + break; + } + + case "weapon_upgrader": { + let weaponsComponentsDiv = $("#weapon-upgrader-components"); + let weaponsTintsDiv = $("#weapon-upgrader-tints"); + + let componentsPrices = {}; + let tintsPrices = {}; + + weaponsComponentsDiv.find(".form-control").each(function(index, element) { + let componentDiv = $(element) + + let componentName = componentDiv.data("componentname") + let componentPrice = componentDiv.val() + + if(componentPrice) { + componentsPrices[componentName] = componentPrice + } + }) + + weaponsTintsDiv.find(".form-control").each(function(index, element) { + let tintDiv = $(element) + + let tintId = parseInt(tintDiv.data("tintid")) + let tintPrice = parseInt(tintDiv.val()) + + if(tintPrice) { + tintsPrices[tintId] = tintPrice + } + }) + + markerData = { + componentsPrices: componentsPrices, + tintsPrices: tintsPrices + } + + break; + } + + case "job_shop": { + let jobName = $("#job-shop-all-jobs").val(); + if(!jobName) return; + + let rankGrade = parseInt($("#job-shop-all-ranks").val()); + + if(jobName && !isNaN(rankGrade)) { + markerData = { + allowedJob: jobName, + minimumRank: rankGrade + } + } + + break; + } + } + + return markerData; +} + +$("#edit-marker-form").submit(function(event){ + if (!this.checkValidity()) { + event.stopPropagation(); + event.preventDefault(); + return; + } + + let editMarkerModal = $("#edit-marker-dialog-modal"); + let markerId = editMarkerModal.data("markerId"); + + let isPublicMarker = $("#edit-marker-form").data("isPublic"); + + let enableMarkerBlip = $("#edit-marker-map-blip").prop("checked"); + + if(enableMarkerBlip) { + var blipSpriteId = parseInt( $("#edit-marker-sprite-id").val() ); + var blipColor = parseInt( $("#edit-marker-blip-color").val() ); + var blipScale = parseFloat( $("#edit-marker-blip-scale").val() ); + } + + let color = hexToRgb( $("#edit-marker-color").val() ); + + let enableNPC = $("#edit-marker-npc").prop("checked"); + + if(enableNPC) { + var npcModel = $("#edit-marker-npc-model").val(); + var npcHeading = parseFloat( $("#edit-marker-npc-heading").val() ); + } + + let enableObject = $("#edit-marker-object").prop("checked"); + + if(enableObject) { + var objectModel = $("#edit-marker-object-model").val(); + } + + let gradesType = $("input[type=radio][name=markerGradeType]:checked").val(); + + if(gradesType === "minimumGrade") { + var minGrade = parseInt( $("#edit-marker-min-grade").val() ); + } else if(gradesType === "specificGrades") { + var specificGrades = $("#edit-marker-specific-grades").data("grades") || {}; + } + + let data = { + markerId: markerId, + + label: $("#edit-marker-label").val(), + + gradesType: gradesType, + + minGrade: minGrade, + specificGrades: specificGrades, + + coords: { + x: parseFloat( $("#edit-marker-coord-x").val() ), + y: parseFloat( $("#edit-marker-coord-y").val() ), + z: parseFloat( $("#edit-marker-coord-z").val() ), + }, + + blip: { + spriteId: blipSpriteId, + color: blipColor, + scale: blipScale, + }, + + markerType: parseInt( $("#edit-marker-type").val() ), + + scale: { + x: parseFloat( $("#edit-marker-scale-x").val() ), + y: parseFloat( $("#edit-marker-scale-y").val() ), + z: parseFloat( $("#edit-marker-scale-z").val() ) + }, + + color: { + r: color.r, + g: color.g, + b: color.b, + alpha: parseInt( $("#edit-marker-alpha").val() ) + }, + + ped: { + model: npcModel, + heading: npcHeading + }, + + object: { + model: objectModel, + heading: parseFloat( $("#edit-marker-object-heading").val() ) + } + } + + let markerData = getCurrentMarkerData(allMarkers[markerId].type); + + $.post(`https://${resName}/update-marker`, JSON.stringify(data), function (data) { + if (data.isSuccessful) { + + let markerType = allMarkers[markerId].type + + if(MARKERS_INFOS[markerType].requiresDataUpdate) { + $.post(`https://${resName}/update-marker-data`, JSON.stringify({ markerId: markerId, markerData: markerData }), function (data) { + if (data.isSuccessful) { + editMarkerModal.modal("hide"); + } else { + showError(data.message) + } + + if(isPublicMarker) { + fillPublicMarkers(); + } else { + fillJobMarkers(); + } + }); + } else { + editMarkerModal.modal("hide"); + + if(isPublicMarker) { + fillPublicMarkers(); + } else { + fillJobMarkers(); + } + } + } else { + showError(data.message) + } + }) +}) + +function gradesDialog(enabledGrades) { + return new Promise(resolve => { + let gradesModal = $("#input-grades-dialog-modal") + let gradesList = $("#grades-list"); + gradesList.empty(); + + let jobName = $("#edit-job").data("jobName"); + + $.post(`https://${resName}/getJobGrades`, JSON.stringify({jobName: jobName}), function(jobGrades) { + for( const[_, gradeData] of Object.entries(jobGrades) ) { + let gradeDiv = $(` +
    + + +
    + `); + + gradesList.append(gradeDiv); + } + + gradesModal.modal("show"); + }) + + + + let confirmButton = $("#input-grades-dialog-confirm"); + + confirmButton.unbind("click"); + confirmButton.click(function() { + let grades = {}; + $(".grade:checked").each(function() { + grades[ parseInt($(this).val()) ] = true; + }) + + gradesModal.modal("hide"); + + resolve(grades); + }) + }); +} + +function setSpecificGrades(grades) { + let specificGradesDiv = $("#edit-marker-specific-grades"); + + specificGradesDiv.data("grades", grades); + specificGradesDiv.val( Object.keys(grades).join(",")); +} + +$("#edit-marker-specific-grades-choose-btn").click(async function() { + let enabledGrades = $("#edit-marker-specific-grades").data("grades") || {}; + + let grades = await gradesDialog(enabledGrades); + + setSpecificGrades(grades); +}) + +$("#marker-data-add-vehicle").click(function () { + var modelDiv = $("#marker-data-vehicle-model"); + var model = modelDiv.val(); + + // Clears input + modelDiv.val(""); + + if (model) { + modelDiv.removeClass("is-invalid"); + + addVehicleToTemporaryGarage(model) + } else { + modelDiv.addClass("is-invalid"); + } +}) + +function getGarageSpawnpoints(listDiv) { + let spawnpoints = []; + + listDiv.find(".spawnpoint-div").each(function() { + let spawnpointData = { + coords: { + x: parseFloat( $(this).find(".spawnpoint-coords-x").val() ), + y: parseFloat( $(this).find(".spawnpoint-coords-y").val() ), + z: parseFloat( $(this).find(".spawnpoint-coords-z").val() ), + }, + + heading: parseFloat( $(this).find(".spawnpoint-heading").val() ), + radius: parseInt( $(this).find(".spawnpoint-radius").val() ) + } + + spawnpoints.push(spawnpointData); + }) + + return spawnpoints; +} + +function addGarageSpawnpoint(listDiv, spawnpointData) { + let div = $(` +
    + + Coords + + + + Heading + + + Radius + +
    + `); + + div.find(".delete-spawnpoint-btn").click(function() { + div.remove(); + }); + + div.find(".current-coords-btn").click(async function() { + const data = await getCurrentCoordsAndHeading(); + + div.find(".spawnpoint-coords-x").val(data.coords.x); + div.find(".spawnpoint-coords-y").val(data.coords.y); + div.find(".spawnpoint-coords-z").val(data.coords.z); + div.find(".spawnpoint-heading").val(data.heading); + }); + + + if(spawnpointData) { + div.find(".spawnpoint-coords-x").val(spawnpointData.coords.x); + div.find(".spawnpoint-coords-y").val(spawnpointData.coords.y); + div.find(".spawnpoint-coords-z").val(spawnpointData.coords.z); + div.find(".spawnpoint-heading").val(spawnpointData.heading); + div.find(".spawnpoint-radius").val(spawnpointData.radius); + } + + listDiv.append(div); +} + +$("#temporary-garage-add-spawnpoint").click(function() { + addGarageSpawnpoint( $("#temporary-garage-spawnpoints-list") ); +}) + +$("#buyable-garage-add-spawnpoint").click(function() { + addGarageSpawnpoint( $("#buyable-garage-spawnpoints-list") ); +}) + +$("#owned-garage-add-spawnpoint").click(function() { + addGarageSpawnpoint( $("#owned-garage-spawnpoints-list") ); +}) + +function addItemToShop(object, itemData) { + var newItem = $(` + + +

    ${object.name}

    + + + +

    $${itemData.price}

    + + + +
    + +
    + + + + + + + `) + + newItem.data("item-price", parseInt(itemData.price)); + + newItem.find(".item-blackmoney").prop("checked", itemData.blackMoney); + + newItem.find(".btn").click(function () { newItem.remove(); }) + + newItem.data("object", object); + + $('#shop-data-items-container').append(newItem) +} + +$("#shop-data-add-btn").click(function () { + var isEverythingValid = true + + let choosenObject = getChoosenObject( $("#shop-new-item-name-div") ); + var itemPriceDiv = $("#shop-data-item-price") + var itemName = choosenObject.name; + var itemPrice = itemPriceDiv.val(); + + let itemData = { + price: itemPrice + } + + if (!itemName) return; + + if (!itemPrice) { + itemPriceDiv.addClass("is-invalid") + isEverythingValid = false + } else { + itemPriceDiv.removeClass("is-invalid") + } + + if (!isEverythingValid) return; + + addItemToShop(choosenObject, itemData); +}) + +$("#garage-buyable-add-vehicle").click(function () { + var isEverythingValid = true; + + var modelDiv = $("#garage-buyable-vehicle-model"); + var model = modelDiv.val(); + var priceDiv = $("#garage-buyable-vehicle-price"); + var price = parseInt(priceDiv.val()); + + // Clears input + modelDiv.val(""); + priceDiv.val(""); + + if (model) { + modelDiv.removeClass("is-invalid"); + } else { + modelDiv.addClass("is-invalid"); + isEverythingValid = false + } + + if(price) { + priceDiv.removeClass("is-invalid") + } else { + priceDiv.addClass("is-invalid") + isEverythingValid = false + } + + if(isEverythingValid) { + var vehicleInputGroup = $(`
    `) + + var vehicleInput = $(``); + var moneySpan = $(`$`) + var vehiclePrice = $(``); + var deleteVehicle = $(``); + + vehicleInputGroup.append(vehicleInput, moneySpan, vehiclePrice, deleteVehicle); + + $(deleteVehicle).click(function () { + $(this).parent().remove(); + }) + + $("#garage-buyable-vehicles").append(vehicleInputGroup) + } +}) + +$("#garage-buyable-current-coords").click(function() { + $.post(`https://${resName}/get-current-coords`, {}, function (data) { + var coords = data.coords; + var heading = data.heading; + + if (coords) { + $("#garage-buyable-spawnpoint-x").val(coords.x) + $("#garage-buyable-spawnpoint-y").val(coords.y) + $("#garage-buyable-spawnpoint-z").val(coords.z) + } + + if (heading) { + $("#garage-buyable-heading").val(heading) + } + }) +}) + +function addNewCraftableToCraftables(object, craftingData) { + var craftablesDiv = $("#craftables"); + + var newCraftable = $(` +
    +
    +
    + + +
    + +
    + ${getLocalizedText("menu:dynamic:marker:crafting_table:quantity")} + + + ${getLocalizedText("menu:dynamic:marker:crafting_table:time_to_craft")} + +
    +
    + + + + + + + + + + + + + +
    ${getLocalizedText("menu:dynamic:marker:crafting_table:item_id")}${getLocalizedText("menu:dynamic:marker:crafting_table:item_quantity")}${getLocalizedText("menu:dynamic:marker:crafting_table:lose_on_use")}${getLocalizedText("menu:dynamic:marker:crafting_table:remove")}
    + +
    +
    + + +
    + +
    + ${getLocalizedText("menu:dynamic:marker:crafting_table:item_quantity")} + + +
    +
    + +
    + + +
    + +
    +
    + `) + + loadChooseObjectDivs( newCraftable.find(".craftable-object-div"), object) + loadChooseObjectDivs( newCraftable.find(".ingredient-object-div")) + + newCraftable.find(".remove-craft-btn").click(function() { + newCraftable.remove(); + }) + + newCraftable.find(".animations-craft-btn").click(function() { + inputAnimations(newCraftable.data("animations"), function(animations) { + newCraftable.data("animations", animations) + }); + }) + + var addToCraftBtn = newCraftable.find(".add-to-craft-btn") + addToCraftBtn.click(function() { + var itemQuantityDiv = newCraftable.find(".crafting-table-item-quantity"); + + const object = getChoosenObject( newCraftable.find(".ingredient-object-div") ); + var itemQuantity = parseInt( itemQuantityDiv.val() ); + + if(!object) return; + + if(!itemQuantity || itemQuantity <= 0) { + itemQuantityDiv.addClass("is-invalid"); + return; + } else { + itemQuantityDiv.removeClass("is-invalid"); + } + + var craftIngredientsDiv = newCraftable.find(".craft-ingredients"); + + let newCraftItem = $(` + + ${object.name} + ${itemQuantity} + +
    + +
    + + + + `) + + newCraftItem.data("object", object); + + newCraftItem.find('.remove-ingredient-btn').click(function() { + newCraftItem.remove() + }) + + craftIngredientsDiv.append(newCraftItem) + + setChoosenObject( newCraftable.find(".ingredient-object-div"), null ) + itemQuantityDiv.val(""); + }) + + if(craftingData?.recipes) { + let craftIngredientsDiv = newCraftable.find('.craft-ingredients'); + + craftingData.recipes.forEach(ingredientData => { + let newCraftItem = $(` + + ${ingredientData.object.name} + ${ingredientData.quantity} + +
    + +
    + + + + `) + + newCraftItem.data("object", ingredientData.object); + + let loseOnUse = ingredientData.loseOnUse + newCraftItem.find(".lose-on-use-checkbox").prop("checked", loseOnUse) + + newCraftItem.find('.remove-ingredient-btn').click(function() { + newCraftItem.remove() + }) + + craftIngredientsDiv.append(newCraftItem); + }) + } + + newCraftable.data("animations", craftingData?.animations || undefined) + + craftablesDiv.append(newCraftable); +} + +$("#crafting-table-new-craft-btn").click(function() { + addNewCraftableToCraftables() +}) + +$("#delete-armory-content").click(async function(){ + let armoryModal = $("#armory-data-modal"); + + let markerId = armoryModal.data("markerId") + + armoryModal.modal("hide"); + + if(! await confirmDeletion(getLocalizedText("menu:do_you_want_to_delete_armory_content"))) return; + + const data = $.post(`https://${resName}/delete-armory-inventory`, JSON.stringify({ markerId: markerId })); + + if(!data.isSuccessful) { + showError(data.message) + } +}) + +$("#delete-stash-inventory").click(async function() { + let editMarkerModal = $("#edit-marker-dialog-modal"); + let markerId = editMarkerModal.data("markerId"); + + if(! await confirmDeletion(getLocalizedText("menu:do_you_want_to_delete_stash_content"))) return; + + const data = await $.post(`https://${resName}/delete-stash-inventory`, JSON.stringify({ markerId: markerId })); + + if(!data.isSuccessful) { + showError(data.message) + } +}) + +function createNewOutfit(outfit){ + outfit = outfit || {}; + + outfit.tshirt_1 = outfit.tshirt_1 || 0; + outfit.tshirt_2 = outfit.tshirt_2 || 0; + + outfit.torso_1 = outfit.torso_1 || 0; + outfit.torso_2 = outfit.torso_2 || 0; + + outfit.decals_1 = outfit.decals_1 || 0; + outfit.decals_2 = outfit.decals_2 || 0; + + outfit.arms = outfit.arms || 0; + outfit.arms_2 = outfit.arms_2 || 0; + + outfit.pants_1 = outfit.pants_1 || 0; + outfit.pants_2 = outfit.pants_2 || 0; + + outfit.shoes_1 = outfit.shoes_1 || 0; + outfit.shoes_2 = outfit.shoes_2 || 0; + + outfit.mask_1 = outfit.mask_1 || 0; + outfit.mask_2 = outfit.mask_2 || 0; + + outfit.bproof_1 = outfit.bproof_1 || 0; + outfit.bproof_2 = outfit.bproof_2 || 0; + + outfit.chain_1 = outfit.chain_1 || 0; + outfit.chain_2 = outfit.chain_2 || 0; + + outfit.helmet_1 = outfit.helmet_1 || -1; + outfit.helmet_2 = outfit.helmet_2 || 0; + + outfit.glasses_1 = outfit.glasses_1 || 0; + outfit.glasses_2 = outfit.glasses_2 || 0; + + outfit.bags_1 = outfit.bags_1 || 0; + outfit.bags_2 = outfit.bags_2 || 0; + + let outfitsDiv = $("#job-outfit-outfits") + let outfitId = $("#job-outfit-outfits").children().length + 1; + + let outfitDiv = $(` +
    +
    +

    + +

    +
    +
    +
    +
    + T-Shirt + + Color + +
    +
    + Torso + + Color + +
    +
    + Decals + + Color + +
    +
    + Arms + + Color + +
    +
    + Pants + + Color + +
    +
    + Shoes + + Color + +
    +
    + Mask + + Color + +
    +
    + Bulletproof + + Color + +
    +
    + Chain + + Color + +
    +
    + Helmet/Hat + + Color + +
    +
    + Glasses + + Color + +
    +
    + Bag + + Color + +
    +
    + + + + +
    +
    +
    +
    + `) + + outfitDiv.find(".current-outfit-btn").click(function(){ + $.post(`https://${resName}/get-current-outfit`, JSON.stringify({}), function (data) { + outfitDiv.find(".outfit-tshirt").val(data.tshirt_1) + outfitDiv.find(".outfit-tshirt-color").val(data.tshirt_2) + + outfitDiv.find(".outfit-torso").val(data.torso_1) + outfitDiv.find(".outfit-torso-color").val(data.torso_2) + + outfitDiv.find(".outfit-decals").val(data.decals_1) + outfitDiv.find(".outfit-decals-color").val(data.decals_2) + + outfitDiv.find(".outfit-arms").val(data.arms) + outfitDiv.find(".outfit-arms-color").val(data.arms_2) + + outfitDiv.find(".outfit-pants").val(data.pants_1) + outfitDiv.find(".outfit-pants-color").val(data.pants_2) + + outfitDiv.find(".outfit-shoes").val(data.shoes_1) + outfitDiv.find(".outfit-shoes-color").val(data.shoes_2) + + outfitDiv.find(".outfit-mask").val(data.mask_1) + outfitDiv.find(".outfit-mask-color").val(data.mask_2) + + outfitDiv.find(".outfit-bulletproof").val(data.bproof_1) + outfitDiv.find(".outfit-bulletproof-color").val(data.bproof_2) + + outfitDiv.find(".outfit-chain").val(data.chain_1) + outfitDiv.find(".outfit-chain-color").val(data.chain_2) + + outfitDiv.find(".outfit-helmet").val(data.helmet_1) + outfitDiv.find(".outfit-helmet-color").val(data.helmet_2) + + outfitDiv.find(".outfit-glasses").val(data.glasses_1) + outfitDiv.find(".outfit-glasses-color").val(data.glasses_2) + + outfitDiv.find(".outfit-bag").val(data.bags_1) + outfitDiv.find(".outfit-bag-color").val(data.bags_2) + }); + }) + + outfitDiv.find(".delete-outfit-btn").click(async function(){ + if(! await confirmDeletion(getLocalizedText("menu:do_you_want_to_delete_outfit"))) return; + + outfitDiv.remove(); + }) + + $(outfitsDiv).append(outfitDiv) +} + +function getOutfitFromOutfitDiv(outfitDiv) { + let outfit = {} + + outfit.label = outfitDiv.data("label") + + outfit.tshirt_1 = parseInt(outfitDiv.find(".outfit-tshirt").val()) || 0; + outfit.tshirt_2 = parseInt(outfitDiv.find(".outfit-tshirt-color").val()) || 0; + + outfit.torso_1 = parseInt(outfitDiv.find(".outfit-torso").val()) || 0; + outfit.torso_2 = parseInt(outfitDiv.find(".outfit-torso-color").val()) || 0; + + outfit.decals_1 = parseInt(outfitDiv.find(".outfit-decals").val()) || 0; + outfit.decals_2 = parseInt(outfitDiv.find(".outfit-decals-color").val()) || 0; + + outfit.arms = parseInt(outfitDiv.find(".outfit-arms").val()) || 0; + outfit.arms_2 = parseInt(outfitDiv.find(".outfit-arms-color").val()) || 0; + + outfit.pants_1 = parseInt(outfitDiv.find(".outfit-pants").val()) || 0; + outfit.pants_2 = parseInt(outfitDiv.find(".outfit-pants-color").val()) || 0; + + outfit.shoes_1 = parseInt(outfitDiv.find(".outfit-shoes").val()) || 0; + outfit.shoes_2 = parseInt(outfitDiv.find(".outfit-shoes-color").val()) || 0; + + outfit.mask_1 = parseInt(outfitDiv.find(".outfit-mask").val()) || 0; + outfit.mask_2 = parseInt(outfitDiv.find(".outfit-mask-color").val()) || 0; + + outfit.bproof_1 = parseInt(outfitDiv.find(".outfit-bulletproof").val()) || 0; + outfit.bproof_2 = parseInt(outfitDiv.find(".outfit-bulletproof-color").val()) || 0; + + outfit.chain_1 = parseInt(outfitDiv.find(".outfit-chain").val()) || 0; + outfit.chain_2 = parseInt(outfitDiv.find(".outfit-chain-color").val()) || 0; + + outfit.helmet_1 = parseInt(outfitDiv.find(".outfit-helmet").val()) || -1; + outfit.helmet_2 = parseInt(outfitDiv.find(".outfit-helmet-color").val()) || 0 + + outfit.glasses_1 = parseInt(outfitDiv.find(".outfit-glasses").val()) || 0; + outfit.glasses_2 = parseInt(outfitDiv.find(".outfit-glasses-color").val()) || 0; + + outfit.bags_1 = parseInt(outfitDiv.find(".outfit-bag").val()) || 0; + outfit.bags_2 = parseInt(outfitDiv.find(".outfit-bag-color").val()) || 0; + + return outfit; +} + +$("#job-outfit-new-outfit-btn").click(function(){ + inputDialog("Create new outfit", [ + { id: "outfitLabel", label: "New outfit label:" }, + ], function (data) { + let outfit = {label: data.outfitLabel} + createNewOutfit(outfit); + }); +}) + +$("#teleport-current-coords-btn").click(function(){ + $.post(`https://${resName}/get-current-coords`, {}, function (data) { + var coords = data.coords; + + if (coords) { + $(`#teleport-x`).val(coords.x) + $(`#teleport-y`).val(coords.y) + $(`#teleport-z`).val(coords.z) + } + }) +}); + +function addItemToMarket(object, itemMinPrice, itemMaxPrice, blackMoney = false, sellTime = 0) { + let itemsTableDiv = $("#market-modal-items-tbody"); + + let itemDiv = $(` + + ${object.name} + + ${itemMinPrice} + ${itemMaxPrice} + + + + + + + + + + + + `) + + let deleteBtn = $(``); + + deleteBtn.click(function(){ itemDiv.remove(); }) + + itemDiv.find(".delete-btn").append(deleteBtn); + + itemDiv.find(".item-blackmoney").prop("checked", blackMoney); + + itemDiv.data("object", object); + + itemsTableDiv.append(itemDiv); +} + +$("#market-modal-new-item-btn").click(function(){ + let itemIdDiv = $("#market-modal-new-item-name-input"); + const chooseObjectDiv = $("#market-new-item-name-div"); + let object = getChoosenObject(chooseObjectDiv); + + let itemMinPriceDiv = $("#market-modal-new-item-min-price-input"); + let itemMaxPriceDiv = $("#market-modal-new-item-max-price-input"); + + let itemMinPrice = itemMinPriceDiv.val(); + let itemMaxPrice = itemMaxPriceDiv.val(); + + if(object) { + itemIdDiv.removeClass("is-invalid"); + } else { + itemIdDiv.addClass("is-invalid"); + } + + if(itemMinPrice) { + itemMinPriceDiv.removeClass("is-invalid"); + } else { + itemMinPriceDiv.addClass("is-invalid"); + } + + if(itemMaxPrice) { + itemMaxPriceDiv.removeClass("is-invalid"); + } else { + itemMaxPriceDiv.addClass("is-invalid"); + } + + if(object && itemMinPrice && itemMaxPrice) { + setChoosenObject(chooseObjectDiv, null); + itemMinPriceDiv.val(""); + itemMaxPriceDiv.val(""); + + addItemToMarket(object, itemMinPrice, itemMaxPrice); + } +}) + +function inputAnimations(animations, cb) { + let animationsModal = $("#animations-modal"); + let animationsForm = $("#animations-modal-form"); + + $("#animations").empty(); + + if(animations && animations.length > 0) { + animations.forEach(animation => { + addAnimation(animation) + }) + } else { + addAnimation(); + } + + animationsForm.unbind(); + animationsForm.submit(function(event) { + if (!this.checkValidity()) { + event.stopPropagation(); + event.preventDefault(); + return; + } else { + $(animationsForm).removeClass("was-validated"); + } + + let animations = []; + + $("#animations").find(".animation-container").each(function() { + let currentAnimDiv = $(this); + + let animType = currentAnimDiv.find(".animation-type").prop("checked"); + + // If it's a scenario + if(animType) { + animations.push({ + type: "scenario", + scenarioName: currentAnimDiv.find(".scenario-name").val(), + scenarioDuration: parseInt(currentAnimDiv.find(".scenario-duration").val()) + }) + } else { // If it's an animation + animations.push({ + type: "animation", + animDict: currentAnimDiv.find(".animation-dictionary").val(), + animName: currentAnimDiv.find(".animation-name").val(), + animDuration: parseInt(currentAnimDiv.find(".animation-duration").val()) + }) + } + }) + + animationsModal.modal("hide"); + + cb(animations) + }) + + animationsModal.modal("show"); +} + +function addAnimation(animation) { + if(!animation) { + animation = {}; + } + + let fullAnimContainer = $(` +
    +
    + + +
    + +
    +
    + ${getLocalizedText("menu:dynamic:animations:animation_dictionary")} + +
    +
    + ${getLocalizedText("menu:dynamic:animations:animation_name")} + +
    +
    + ${getLocalizedText("menu:dynamic:animations:animation_duration")} + +
    +
    + + + + +
    + `); + + let scenarioContainer = fullAnimContainer.find(".scenario"); + let animationContainer = fullAnimContainer.find(".animation"); + let switchLabel = fullAnimContainer.find(".animation-type-label"); + let switchInput = fullAnimContainer.find(".animation-type"); + + let removeAnimBtn = fullAnimContainer.find(".remove-anim-btn"); + + fullAnimContainer.find(".animation-type").change(function() { + let isChecked = $(this).prop("checked"); + + if(isChecked) { + scenarioContainer.show(); + scenarioContainer.find(".form-control").prop("required", true); + + animationContainer.hide(); + animationContainer.find(".form-control").prop("required", false); + + switchLabel.text("Scenario"); + } else { + scenarioContainer.hide(); + scenarioContainer.find(".form-control").prop("required", false); + + animationContainer.show(); + animationContainer.find(".form-control").prop("required", true); + + switchLabel.text("Animation"); + } + }) + + removeAnimBtn.click(function() { + $(this).parent().remove(); + }) + + if(animation && animation.type == "scenario") { + switchInput.prop("checked", true).trigger("change"); + } + + $("#animations").append(fullAnimContainer); +} + +$("#add-animation-btn").click(function(){ + addAnimation(); +}) + +$("#harvest-add-item-btn").click(function() { + addItemToHarvestable(); +}); + +$("#harvest-animations-btn").click(function() { + let editMarkerModal = $("#edit-marker-dialog-modal"); + inputAnimations(editMarkerModal.data("animations"), function(animations) { + editMarkerModal.data("animations", animations) + }); +}); + +$("#harvest-disappear-after-use").change(function(){ + toggleDisappearsAfterUse( $(this).prop("checked") ); +}); + +$("#harvest-choose-account-btn").click(function() { + accountsDialog(accountName => { + $("#harvest-minimum-account-name").val(accountName); + }) +}) + +function addItemToHarvestable(object, minQuantity = "", maxQuantity = "", secondsToHarvest = "", chances = "") { + var itemDiv = $(` +
    +
    +
    + + +
    +
    + ${getLocalizedText("menu:dynamic:harvest:min_quantity")} + +
    +
    + ${getLocalizedText("menu:dynamic:harvest:max_quantity")} + +
    +
    + +
    +
    + ${getLocalizedText("menu:dynamic:harvest:time_to_harvest")} + +
    +
    + ${getLocalizedText("menu:dynamic:harvest:probabilty")} + +
    + + +
    + +
    +
    + `); + + $(itemDiv).find(".remove-harvestable-item-btn").click(function() { + $(this).parents(".harvestable-item").remove(); + }) + + loadChooseObjectDivs( $(itemDiv).find(".choose-object-div"), object); + + $("#harvest-modal-items").append(itemDiv); +} + +$("#process-animations-btn").click(function() { + let editMarkerModal = $("#edit-marker-dialog-modal"); + + inputAnimations(editMarkerModal.data("animations"), function(animations) { + editMarkerModal.data("animations", animations) + }); +}) + +$("#process-requires-minimum-account-money").change(function() { + let isEnabled = $(this).prop("checked"); + + $("#process-minimum-account-name-div").find("input, button").prop("disabled", !isEnabled); + $("#process-minimum-account-name-div").find("input, button").prop("required", isEnabled); +}); + +$("#process-choose-account-btn").click(function() { + accountsDialog(accountName => { + $("#process-minimum-account-name").val(accountName); + }) +}) + +$("#job-shop-all-jobs").change(function() { + let jobRanks = $(this).data("ranks"); + let jobName = $(this).val(); + + let allRanksSelect = $("#job-shop-all-ranks"); + + allRanksSelect.find(".job-shop-rank").remove(); + + let ranksArray = Array.isArray(jobRanks[jobName]) ? jobRanks[jobName] : Object.values(jobRanks[jobName]); + + ranksArray.forEach(rank => { + let rankDiv = $(``); + + allRanksSelect.append(rankDiv); + }) +}) + +function loadAllJobsOnlinePlayers() { + $.post(`https://${resName}/getAllJobsOnlinePlayers`, {}, function(jobsOnlinePlayers) { + allJobsStatisticsChart.data.labels = []; + + allJobsStatisticsChart.data.datasets[0] = {}; + allJobsStatisticsChart.data.datasets[0].data = []; + + allJobsStatisticsChart.data.datasets[0].label = getLocalizedText("menu:online_players"); + allJobsStatisticsChart.data.datasets[0].backgroundColor = "rgba(26, 188, 156, 0.5)"; + allJobsStatisticsChart.data.datasets[0].borderColor = "rgba(26, 188, 156, 0.8)"; + allJobsStatisticsChart.data.datasets[0].borderWidth = 1; + allJobsStatisticsChart.options.scales.y.ticks.callback = function(value, index, values) { + if (Number.isInteger(value)) { return value; } + } + + let maximumValue = 0; + + jobsOnlinePlayers.forEach(jobData => { + allJobsStatisticsChart.data.labels.push(jobData.label); + + allJobsStatisticsChart.data.datasets[0].data.push(jobData.playersCount); + + if (jobData.playersCount > maximumValue) { + maximumValue = jobData.playersCount; + } + }); + + allJobsStatisticsChart.options.scales.y.suggestedMax = maximumValue + 1; + + allJobsStatisticsChart.update(); + }); +} + +function loadAllJobsTotalPlayers() { + $.post(`https://${resName}/getAllJobsTotalPlayers`, {}, function(jobsTotalPlayers) { + allJobsStatisticsChart.data.labels = []; + + allJobsStatisticsChart.data.datasets[0] = {}; + allJobsStatisticsChart.data.datasets[0].data = []; + + allJobsStatisticsChart.data.datasets[0].label = getLocalizedText("menu:total_players"); + allJobsStatisticsChart.data.datasets[0].backgroundColor = "rgba(26, 188, 156, 0.5)"; + allJobsStatisticsChart.data.datasets[0].borderColor = "rgba(26, 188, 156, 0.8)"; + allJobsStatisticsChart.data.datasets[0].borderWidth = 1; + allJobsStatisticsChart.options.scales.y.ticks.callback = function(value, index, values) { + if (Number.isInteger(value)) { return value; } + } + + let maximumValue = 0; + + jobsTotalPlayers.forEach(jobData => { + allJobsStatisticsChart.data.labels.push(jobData.label); + + allJobsStatisticsChart.data.datasets[0].data.push(jobData.playersCount); + + if (jobData.playersCount > maximumValue) { + maximumValue = jobData.playersCount; + } + }); + allJobsStatisticsChart.options.scales.y.suggestedMax = maximumValue + 1; + + allJobsStatisticsChart.update(); + }); +} + +function loadAllJobsSocietyMoney() { + $.post(`https://${resName}/getJobsSocietyMoney`, {}, function(jobsSocietyMoney) { + allJobsStatisticsChart.data.labels = []; + + allJobsStatisticsChart.data.datasets[0] = {}; + allJobsStatisticsChart.data.datasets[0].data = []; + + allJobsStatisticsChart.data.datasets[0].label = getLocalizedText("menu:society_money"); + allJobsStatisticsChart.data.datasets[0].backgroundColor = "rgba(241, 196, 15, 0.4)"; + allJobsStatisticsChart.data.datasets[0].borderColor = "rgba(241, 196, 15, 0.8)"; + + allJobsStatisticsChart.data.datasets[0].borderWidth = 1; + allJobsStatisticsChart.options.scales.y.ticks.callback = function(value, index, values) { + return "$" + value; + } + + let maximumValue = 0; + + jobsSocietyMoney.forEach(jobData => { + allJobsStatisticsChart.data.labels.push(jobData.label); + + allJobsStatisticsChart.data.datasets[0].data.push(jobData.money); + + if (jobData.money > maximumValue) { + maximumValue = jobData.money; + } + }); + + allJobsStatisticsChart.options.scales.y.suggestedMax = maximumValue + maximumValue * 0.10; + + allJobsStatisticsChart.update(); + }); +} + +$('input[type=radio][name=all-jobs-statistics-type]').change(function() { + let action = $(this).val(); + + switch(action) { + case "online-players": { + loadAllJobsOnlinePlayers(); + break; + } + + case "total-players": { + loadAllJobsTotalPlayers(); + break; + } + + case "society-money": { + loadAllJobsSocietyMoney(); + break; + } + } +}); + +function loadRanksDistrubutions(){ + let jobName = $("#edit-job").data("jobName"); + + $.post(`https://${resName}/getRanksDistribution`, JSON.stringify({jobName: jobName }), function(rankDistribution) { + jobStatisticsChart.data.labels = []; + + jobStatisticsChart.data.datasets[0] = {}; + jobStatisticsChart.data.datasets[0].data = []; + + jobStatisticsChart.data.datasets[0].label = getLocalizedText("menu:chart:players_in_rank"); + + jobStatisticsChart.data.datasets[0].backgroundColor = "rgba(26, 188, 156, 0.5)"; + jobStatisticsChart.data.datasets[0].borderColor = "rgba(26, 188, 156, 0.8)"; + jobStatisticsChart.data.datasets[0].borderWidth = 1; + + jobStatisticsChart.options.scales.y.ticks.callback = function(value, index, values) { + if (Number.isInteger(value)) { return value; } + } + + let maximumValue = 0; + + rankDistribution.forEach(rankData => { + jobStatisticsChart.data.labels.push(rankData.label); + + jobStatisticsChart.data.datasets[0].data.push(rankData.playersCount); + + if (rankData.playersCount > maximumValue) { + maximumValue = rankData.playersCount; + } + }); + + jobStatisticsChart.options.scales.y.suggestedMax = maximumValue + 1; + + jobStatisticsChart.update(); + }) +} + +async function settingsTour() { + const introName = "settingsTour"; + if(await hasIntroBeenViewed(introName)) return; + + const tour = new Shepherd.Tour({ + useModalOverlay: true, + defaultStepOptions: { + scrollTo: true + } + }); + + tour.addStep({ + text: getLocalizedText("menu:intro:settings"), + attachTo: { + element: '#settings', + on: 'right' + }, + buttons: [ + { + text: getLocalizedText("menu:intro:skip"), + action: tour.cancel, + secondary: true + }, + { + text: getLocalizedText("menu:intro:next"), + action: tour.next + } + ] + }); + + tour.addStep({ + text: getLocalizedText("menu:intro:settings_external_names"), + attachTo: { + element: '#settings-external-scripts-names', + on: 'right' + }, + buttons: [ + { + text: getLocalizedText("menu:intro:skip"), + action: tour.cancel, + secondary: true + }, + { + text: getLocalizedText("menu:intro:next"), + action: tour.next + } + ] + }); + + tour.addStep({ + text: getLocalizedText("menu:intro:settings_modules"), + attachTo: { + element: '#settings-modules', + on: 'right' + }, + buttons: [ + { + text: getLocalizedText("menu:intro:skip"), + action: tour.cancel, + secondary: true + }, + { + text: getLocalizedText("menu:intro:next"), + action: tour.next + } + ] + }); + + tour.start(); + + registerIntroView(introName); +} +$("#settings-tab").click(settingsTour); + +async function jobTour() { + const introName = "jobTour"; + if(await hasIntroBeenViewed(introName)) return; + + const tour = new Shepherd.Tour({ + useModalOverlay: true, + defaultStepOptions: { + scrollTo: true + } + }); + + tour.addStep({ + text: getLocalizedText("menu:intro:ranks"), + attachTo: { + element: '#create-rank-btn', + on: 'left' + }, + buttons: [ + { + text: getLocalizedText("menu:intro:skip"), + action: tour.cancel, + secondary: true + }, + { + text: getLocalizedText("menu:intro:next"), + action: tour.next + } + ] + }); + + tour.addStep({ + text: getLocalizedText("menu:intro:job_settings"), + attachTo: { + element: '#job-settings-tab', + on: 'right' + }, + buttons: [ + { + text: getLocalizedText("menu:intro:skip"), + action: tour.cancel, + secondary: true + }, + { + text: getLocalizedText("menu:intro:okay"), + action: tour.next + } + ] + }); + + tour.start(); + + registerIntroView(introName); +} + +async function mainMenuTour() { + const introName = "mainMenuTour"; + if(await hasIntroBeenViewed(introName)) return; + + const tour = new Shepherd.Tour({ + useModalOverlay: true, + defaultStepOptions: { + scrollTo: true + } + }); + + tour.addStep({ + text: getLocalizedText("menu:intro:welcome"), + buttons: [ + { + text: getLocalizedText("menu:intro:skip"), + action: tour.cancel, + secondary: true + }, + { + text: getLocalizedText("menu:intro:next"), + action: tour.next + } + ] + }); + + tour.addStep({ + text: getLocalizedText("menu:intro:jobs"), + attachTo: { + element: '#create-job-btn', + on: 'left' + }, + buttons: [ + { + text: getLocalizedText("menu:intro:skip"), + action: tour.cancel, + secondary: true + }, + { + text: getLocalizedText("menu:intro:next"), + action: tour.next + } + ] + }); + + tour.addStep({ + text: getLocalizedText("menu:intro:jobs_table"), + attachTo: { + element: '#jobs-container', + on: 'right' + }, + buttons: [ + { + text: getLocalizedText("menu:intro:skip"), + action: tour.cancel, + secondary: true + }, + { + text: getLocalizedText("menu:intro:next"), + action: tour.next + } + ] + }); + + tour.addStep({ + text: getLocalizedText("menu:intro:public_markers"), + attachTo: { + element: '#public-markers-tab', + on: 'right' + }, + buttons: [ + { + text: getLocalizedText("menu:intro:skip"), + action: tour.cancel, + secondary: true + }, + { + text: getLocalizedText("menu:intro:okay"), + action: tour.next + } + ] + }); + + tour.start(); + + registerIntroView(introName); +} + +// [[ NEXUS ]] +const voteJobRater = raterJs({ + starSize: 35, + element: document.querySelector("#vote-job-rater"), + rateCallback: async function rateCallback(rating, done) { + const jobId = $("#nexus-modal").data("jobInstance").id; + const success = await $.post(`https://${resName}/nexus/rateJob`, JSON.stringify({rating, jobId})); + if(success) voteJobRater.setRating(rating); + + done(); + } +}); + +const averageJobVotes = raterJs({ + starSize: 20, + readOnly: true, + element: document.querySelector("#nexus-modal-job-average-rating"), +}); + +$("#nexus-import-job-btn").click(async function() { + const jobId = $("#nexus-modal").data("jobInstance").id; + + const response = await $.post(`https://${resName}/nexus/importJob`, JSON.stringify({jobId})); + $("#nexus-modal").modal("hide"); + + if(response === true) refresh(); + + showServerResponse(response); +}); + +let nexusDataTable = $("#nexus-jobs-container").DataTable({ + "lengthMenu": [5, 10, 15, 20], + "pageLength": 10, + "order": [[3, 'desc'], [4, 'desc']], + "createdRow": function (row, data, index) { + $(row).addClass("clickable"); + $(row).click(function () { + const jobInstance = $(this).data("jobInstance"); + showJobInstance(jobInstance); + $("#nexus-modal").modal("show"); + }); + }, + "columnDefs": [{ "defaultContent": "???", "targets": "_all" }] +}); + +function showJobInstance(jobInstance) { + $("#nexus-modal").data("jobInstance", jobInstance); + + $("#nexus-modal-job-listing-label").text(jobInstance.label); + $("#nexus-modal-job-label").text(jobInstance.jobConfiguration.label); + $("#nexus-modal-job-name").text(jobInstance.jobConfiguration.name); + $("#nexus-modal-job-description").text(jobInstance.description || getLocalizedText("menu:nexus:no_description")); + $("#nexus-modal-job-author").text(jobInstance.author); + + // Votes + if(jobInstance?.votes?.total > 0) { + averageJobVotes.setRating(jobInstance?.votes.averageRating); + } else { + averageJobVotes.setRating(0); + } + + $("#nexus-modal-job-total-votes").text(jobInstance.votes?.total || 0); + + // This server vote + voteJobRater.setRating(0); + + // Actions + const actionsListDiv = $("#nexus-modal-job-actions-list"); + actionsListDiv.empty(); + + let currentRow = null; + + for(let i=0; i < ACTIONS_LABELS.length; i++) { + const {action, label} = ACTIONS_LABELS[i]; + const actionValue = jobInstance.jobConfiguration.actions[action]; + const isEnabled = action == "placeableObjects" ? actionValue.length > 0 : actionValue; + + if(i % 2 === 0) { + actionsListDiv.append(currentRow); + currentRow = null; + } + + const emoji = isEnabled ? "✅" : "❌"; + + if(currentRow == null) currentRow = $("

    "); + + currentRow.append( i % 2 !== 0 ? `${label} ${emoji}` : `${emoji} ${label}`); + } + + if (currentRow !== null) actionsListDiv.append(currentRow); + + // Ranks + const ranksListDiv = $("#nexus-modal-job-ranks-list"); + ranksListDiv.empty(); + + for(const [rank, rankInfo] of Object.entries(jobInstance.jobConfiguration.ranks)) { + const rankDiv = $(` +
  • + ${rankInfo.label} + ${rank} +
  • + `); + + ranksListDiv.append(rankDiv); + } + + // Markers count + const markersCount = jobInstance.jobMarkers ? Object.keys(jobInstance.jobMarkers).length : 0; + $("#nexus-modal-job-included-markers-count").text(markersCount); +} + +$("#upload-job-to-nexus-btn").click(async function() { + const jobName = await singleJobDialog(); + if(!jobName) return; + + $("#nexus-modal-upload").data("jobName", jobName); + + $("#nexus-upload-label").val(""); + $("#nexus-upload-description").val(""); + $("#nexus-upload-include-job-markers").prop("checked", true).change(); + + $("#nexus-upload-accept-tos").prop("checked", false) + $("#nexus-upload-accept-sharing-data").prop("checked", false) + + const allJobs = await $.post(`https://${resName}/getJobsData`); + const jobData = allJobs[jobName]; + + $("#nexus-upload-label-shared-job-label").val(jobData.label) + $("#nexus-upload-label-shared-job-id").val(jobData.name) + + const jobMarkers = await $.post(`https://${resName}/retrieveJobMarkers`, JSON.stringify({jobName})); + + $("#nexus-upload-included-markers-count").val(Object.keys(jobMarkers).length) + + $("#nexus-modal-upload").modal("show"); +}); + +$("#nexus-upload-include-job-markers").change(function() { + const isChecked = $(this).prop("checked"); + $("#nexus-upload-included-markers-count-div").toggle(isChecked); +}); + +$("#nexus-upload-form").submit(async function(event) { + if(isThereAnyErrorInForm(event)) return; + + const dataToUpload = { + jobName: $("#nexus-modal-upload").data("jobName"), + label: $("#nexus-upload-label").val(), + description: $("#nexus-upload-description").val(), + includeJobMarkers: $("#nexus-upload-include-job-markers").prop("checked"), + } + + const result = await $.post(`https://${resName}/nexus/uploadJob`, JSON.stringify(dataToUpload)); + + if(result == true) { + swal("Success", getLocalizedText("menu:nexus:upload_success"), "success"); + resetNexus(); + } else { + swal("Error", result, "error"); + } + + $("#nexus-modal-upload").modal("hide"); +}); + +$("#enter-in-nexus-btn").click(async function() { + $("#nexus-login").find(".spinner-border").show(); + $("#enter-in-nexus-label").text("..."); + + const jobs = await $.get(`https://${resName}/nexus/getJobs`); + if(!jobs) { + swal("Error", getLocalizedText("menu:nexus:not_available"), "error"); + resetNexus(); + return; + } + + nexusDataTable.clear(); + + for(const[_, jobInstance] of Object.entries(jobs)) { + const roundedAverageRating = jobInstance?.votes?.averageRating ? Math.round(jobInstance.votes.averageRating) : 0; + const ratingStars = jobInstance?.votes?.total ? "⭐".repeat(roundedAverageRating) : getLocalizedText("menu:nexus:not_rated"); + const limitedDescription = jobInstance.description?.length > 30 ? jobInstance.description.substring(0, 30) + "..." : jobInstance.description; + const jobMarkersCount = jobInstance.jobMarkers ? Object.keys(jobInstance.jobMarkers).length : 0; + + const rawRow = nexusDataTable.row.add( [jobInstance.label, limitedDescription, jobMarkersCount, ratingStars, jobInstance.votes?.total || 0, jobInstance.author] ); + + const rowDiv = $(rawRow.node()); + $(rowDiv).data("jobInstance", jobInstance); + } + + nexusDataTable.draw(); + + $("#nexus-login").hide(); + $("#nexus-container").show(); +}) + +function resetNexus() { + $("#nexus-login").show(); + $("#nexus-login").find(".spinner-border").hide(); + $("#enter-in-nexus-label").text("Enter in Nexus"); + + $("#nexus-container").hide(); +} + +async function init(version, fullConfig) { + $("#job-creator-version").text(version); + + loadSettings(fullConfig); + + resetNexus() + + $("#job-creator").show(); + + await refresh(); + + mainMenuTour(); + refreshAnnouncements(); +} + +function exit() { + // Resets current active tab (jobs is the default one) + $("#job-creator").find(".nav-link, .tab-pane").each(function() { + if($(this).data("isDefault") == "1") { + $(this).addClass(["active", "show"]) + } else { + $(this).removeClass(["active", "show"]) + } + }) + + $("#job-creator").hide(); + + $.post(`https://${resName}/exit`) +} + +window.addEventListener('message', (event) => { + let data = event.data; + let action = data.action; + + if (action == 'show') { + init(data.version, data.fullConfig); + } +}) + +$("#close-main-btn").click(function () { + exit() +}) + +/* + +░██████╗███████╗████████╗████████╗██╗███╗░░██╗░██████╗░░██████╗ +██╔════╝██╔════╝╚══██╔══╝╚══██╔══╝██║████╗░██║██╔════╝░██╔════╝ +╚█████╗░█████╗░░░░░██║░░░░░░██║░░░██║██╔██╗██║██║░░██╗░╚█████╗░ +░╚═══██╗██╔══╝░░░░░██║░░░░░░██║░░░██║██║╚████║██║░░╚██╗░╚═══██╗ +██████╔╝███████╗░░░██║░░░░░░██║░░░██║██║░╚███║╚██████╔╝██████╔╝ +╚═════╝░╚══════╝░░░╚═╝░░░░░░╚═╝░░░╚═╝╚═╝░░╚══╝░╚═════╝░╚═════╝░ +*/ + +function clearLicensesInList(type) { + if(type === "driver") { + var listDiv = $("#settings_drivingLicensesList"); + } else if(type === "weapon") { + var listDiv = $("#settings_weaponLicensesList"); + } + + if(listDiv) { + listDiv.empty(); + } +} + +function addNewLicenseInList(licenseName, type) { + if(type === "driver") { + var listDiv = $("#settings_drivingLicensesList"); + } else if(type === "weapon") { + var listDiv = $("#settings_weaponLicensesList"); + } + + if(listDiv) { + listDiv.append(` +
  • + ${licenseName} + +
  • + `); + + listDiv.find(".remove-license").click(function() { + $(this).parent().remove(); + }); + } +} + +$("#settings_addNewDrivingLicenseBtn").click(function() { + let drivingLicenseName = $("#settings_newDrivingLicense").val(); + + if(drivingLicenseName) { + $("#settings_newDrivingLicense").val(""); + addNewLicenseInList(drivingLicenseName, "driver"); + } +}) + +$("#settings_addNewWeaponLicenseBtn").click(function() { + let weaponLicenseName = $("#settings_newWeaponLicense").val(); + + if(weaponLicenseName) { + $("#settings_newWeaponLicense").val(""); + addNewLicenseInList(weaponLicenseName, "weapon"); + } +}) + +function getSettingsLicenses(type) { + if(type === "driver") { + var listDiv = $("#settings_drivingLicensesList"); + } else if(type === "weapon") { + var listDiv = $("#settings_weaponLicensesList"); + } + + let licenses = {}; + + listDiv.find(".license").each(function(index, element) { + licenses[ $(element).data("license") ] = true; + }) + + return licenses; +} + +function getSeparatedDiscordWebhooks() { + let webhooks = {}; + + $("#settings_specific_webhooks").find(".form-control").each(function(index, element) { + let markerType = $(element).data("markerType"); + let webhook = $(element).val(); + + if(webhook) { + webhooks[markerType] = webhook; + } + }); + + return webhooks; +} + +$("#settings").submit(async function(event) { + if(isThereAnyErrorInForm(event)) return; + + let clientSettings = { + markerDistance: parseFloat( $("#settings_markerDistance").val() ), + use3Dtext: $("#settings_use3Dtext").prop("checked"), + textSize: parseInt( $("#settings_textSize").val() ), + textFont: parseInt( $("#settings_textFont").val() ), + carLockpickTime: parseInt( $("#settings_carLockpickTime").val() ), + enableAlarmWhenLockpicking: $("#settings_enableAlarmWhenLockpicking").prop("checked"), + useJSFourIdCard: $("#settings_useJSFourIdCard").prop("checked"), + canUseActionsMenuWhileOffDuty: $("#settings_canUseActionsMenuWhileOffDuty").prop("checked"), + licenses: { + driver: getSettingsLicenses("driver"), + weapon: getSettingsLicenses("weapon"), + }, + marketSellOnePerTime: $("#settings_marketSellOnePerTime").prop("checked"), + menuPosition: $("#settings_menuPosition").val(), + actionsMenuKey: $("#settings_actionsMenuKey").val(), + freezeWhenSoftHandcuffed: $("#settings_freezeWhenSoftHandcuffed").prop("checked"), + freezeWhenHardHandcuffed: $("#settings_freezeWhenHardHandcuffed").prop("checked"), + searchRequiresHandcuffState: $("#settings_searchRequiresHandcuffState").prop("checked"), + targetingScript:$("#settings-targeting-script").val(), + whitelistedControlsWhileHandcuffed: getAllWhitelistedControlsWhileHandcuffed(), + toggleDrag: { + enabled: $("#toggle-drag-enabled").prop("checked"), + key: $("#toggle-drag-default-key").val() + } + } + + let sharedSettings = { + allowAfkFarming: $("#settings_allowAfkFarming").prop("checked"), + locale: $("#settings_locale").val(), + externalScriptsNames: getIntegrationSettings(), + modules: getModulesSettings(), + handcuffsEnableSelfRelease: $("#settings_handcuffsEnableSelfRelease").prop("checked"), + resetEmployeeWorkTimeEveryNDays: parseInt( $("#settings_resetEmployeeWorkTimeEveryNDays").val() ), + } + + let serverSettings = { + unemployedJob: $("#settings_unemployedJob").val(), + unemployedGrade: parseInt( $("#settings_unemployedGrade").val() ), + + acePermission: $("#settings_acePermission").val(), + + areDiscordLogsActive: $("#settings_isDiscordLogActive").prop("checked"), + mainDiscordWebhook: $("#settings_discordWebhook").val(), + specificWebhooks: getSeparatedDiscordWebhooks(), + + handcuffRequireItem: $("#settings_handcuffRequireItem").prop("checked"), + handcuffsItemName: $("#settings_handcuffsItemName").val(), + handcuffsRemoveOnUse: $("#settings_handcuffsRemoveOnUse").prop("checked"), + + lockpickCarRequireItem: $("#settings_lockpickCarRequireItem").prop("checked"), + lockpickItemName: $("#settings_lockpickItemName").val(), + lockpickRemoveOnUse: $("#settings_lockpickRemoveOnUse").prop("checked"), + + robbableAccounts: getRobbableAccounts(), + + canAlwaysCarryItem: $("#settings_canAlwaysCarryItem").prop("checked"), + + depositableInSafeAccounts: getDepositableInSafeAccounts(), + + repairVehicleRequireItem: $("#settings_repairVehicleRequireItem").prop("checked"), + repairVehicleItemName: $("#settings_repairVehicleItemName").val(), + repairVehicleRemoveOnUse: $("#settings_repairVehicleRemoveOnUse").prop("checked"), + + cleanVehicleRequireItem: $("#settings_cleanVehicleRequireItem").prop("checked"), + cleanVehicleItemName: $("#settings_cleanVehicleItemName").val(), + cleanVehicleRemoveOnUse: $("#settings_cleanVehicleRemoveOnUse").prop("checked"), + + healRequireItem: $("#settings_healRequireItem").prop("checked"), + healItemName: $("#settings_healItemName").val(), + healRemoveOnUse: $("#settings_healRemoveOnUse").prop("checked"), + + reviveRequireItem: $("#settings_reviveRequireItem").prop("checked"), + reviveItemName: $("#settings_reviveItemName").val(), + reviveRemoveOnuse: $("#settings_reviveRemoveOnUse").prop("checked"), + + enablePropertyOutfits: $("#settings_enablePropertyOutfits").prop("checked"), + + parkAllOwnedVehiclesOnRestart: $("#settings_parkAllOwnedVehiclesOnRestart").prop("checked"), + + blackMoney: getBlackMoneySettings(), + } + + const response = await $.post(`https://${resName}/saveSettings`, JSON.stringify({ + clientSettings: clientSettings, + serverSettings: serverSettings, + sharedSettings: sharedSettings + })); + showServerResponse(response); + + refreshTranslations(sharedSettings.locale); +}) + +async function toggleDiscordLogsInSettings(enable) { + $("#settings_discordWebhook").prop("disabled", !enable); + $("#settings_discordWebhook").prop("required", enable); + + $("#settings_specific_webhooks").find(`.form-control`).prop("disabled", !enable); + + if(await getInventoryScriptUsed() !== "default" || await getFramework() !== "ESX") { + $("#settings_specific_webhooks").find(`.form-control[data-marker-type="stash"]`).prop("disabled", true); + $("#settings_specific_webhooks").find(`.form-control[data-marker-type="armory"]`).prop("disabled", true); + $("#settings_specific_webhooks").find(`.form-control[data-marker-type="safe"]`).prop("disabled", true); + } +} + +$("#settings_isDiscordLogActive").change(function() { + let enabled = $(this).prop("checked"); + + toggleDiscordLogsInSettings(enabled); +}) + +$(`input[type=radio][name=black-money-worth-type]`).change(function() { + const worthType = $(this).val(); + const isMetadata = worthType === "metadata"; + + $("#settings-black-money-metadata-field-id-div").toggle(isMetadata); + $("#settings-black-money-metadata-field-id").prop("required", isMetadata); +}); + +function setBlackMoneySettings(blackMoney) { + $(`input[type=radio][name=black-money-worth-type][value=${blackMoney.worthType}]`).prop("checked", true).change(); + setChoosenObject( $("#settings-choose-black-money-div"), blackMoney.object); + $("#settings-black-money-metadata-field-id").val(blackMoney.metadataFieldId); +} + +function getBlackMoneySettings() { + return { + worthType: $(`input[type=radio][name=black-money-worth-type]:checked`).val(), + object: getChoosenObject( $("#settings-choose-black-money-div") ), + metadataFieldId: $("#settings-black-money-metadata-field-id").val() + } +} + +async function loadSettings(fullConfig) { + // CLIENT + $("#settings_markerDistance").val(fullConfig.markerDistance); + + // 3D Text + $("#settings_use3Dtext").prop("checked", fullConfig.use3Dtext); + $("#settings_textSize").val(fullConfig.textSize); + setTomSelectValue("#settings_textFont", fullConfig.textFont) + + // Targeting + setTomSelectValue("#settings-targeting-script", fullConfig.targetingScript) + + // Black money + setBlackMoneySettings(fullConfig.blackMoney); + + // Car lockpicking + $("#settings_carLockpickTime").val(fullConfig.carLockpickTime); + $("#settings_enableAlarmWhenLockpicking").prop("checked", fullConfig.enableAlarmWhenLockpicking); + + $("#settings_useJSFourIdCard").prop("checked", fullConfig.useJSFourIdCard); + $("#settings_canUseActionsMenuWhileOffDuty").prop("checked", fullConfig.canUseActionsMenuWhileOffDuty); + $("#settings_marketSellOnePerTime").prop("checked", fullConfig.marketSellOnePerTime); + + // Weapon/Driving licenses + if(fullConfig.licenses) { + for(const[licenseType, licenses] of Object.entries(fullConfig.licenses)) { + clearLicensesInList(licenseType); + + Object.keys(licenses).forEach(licenseName => { + addNewLicenseInList(licenseName, licenseType); + }) + } + } + + // Menu position + setTomSelectValue("#settings_menuPosition", fullConfig.menuPosition) + + // Actions key + $("#settings_actionsMenuKey").val(fullConfig.actionsMenuKey); + + loadIntegrationsSettings(fullConfig.externalScriptsNames); + loadModulesSettings(fullConfig.modules); + + // SHARED + $("#settings_allowAfkFarming").prop("checked", fullConfig.allowAfkFarming); + setTomSelectValue("#settings_locale", fullConfig.locale) + + // Generic + $("#settings_unemployedJob").val(fullConfig.unemployedJob); + $("#settings_unemployedGrade").val(fullConfig.unemployedGrade); + $("#settings_acePermission").val(fullConfig.acePermission); + + // Discord logs webhooks + $("#settings_isDiscordLogActive").prop("checked", fullConfig.areDiscordLogsActive); + toggleDiscordLogsInSettings(fullConfig.areDiscordLogsActive); + + $("#settings_discordWebhook").val(fullConfig.mainDiscordWebhook); + + // Handcuffs + toggleSettingsHandcuffsRequireItem(fullConfig.handcuffRequireItem); + $("#settings_handcuffsItemName").val(fullConfig.handcuffsItemName) + $("#settings_handcuffsRemoveOnUse").prop("checked", fullConfig.handcuffsRemoveOnUse) + $("#settings_handcuffsEnableSelfRelease").prop("checked", fullConfig.handcuffsEnableSelfRelease); + + $("#settings_freezeWhenSoftHandcuffed").prop("checked", fullConfig.freezeWhenSoftHandcuffed); + $("#settings_freezeWhenHardHandcuffed").prop("checked", fullConfig.freezeWhenHardHandcuffed); + + // Whitelisted controls while handcuffed + $("#whitelisted-controls-while-handcuffed-list").empty(); + + fullConfig.whitelistedControlsWhileHandcuffed.forEach(control => { + addWhitelistedControlWhileHandcuffed(control); + }) + + // Toggle drag + $("#toggle-drag-enabled").prop("checked", fullConfig.toggleDrag.enabled); + $("#toggle-drag-default-key").val(fullConfig.toggleDrag.key); + + // Search + $("#settings_searchRequiresHandcuffState").prop("checked", fullConfig.searchRequiresHandcuffState); + + // Lockpick + toggleSettingsLockpickRequireItem(fullConfig.lockpickCarRequireItem); + $("#settings_lockpickItemName").val(fullConfig.lockpickItemName) + $("#settings_lockpickRemoveOnUse").prop("checked", fullConfig.lockpickRemoveOnUse) + + // Vehicle repair + toggleSettingsVehicleRepairRequireItem(fullConfig.repairVehicleRequireItem); + $("#settings_repairVehicleItemName").val(fullConfig.repairVehicleItemName); + $("#settings_repairVehicleRemoveOnUse").prop("checked", fullConfig.repairVehicleRemoveOnUse); + + // Vehicle cleaning + toggleSettingsVehicleCleaningRequireItem(fullConfig.cleanVehicleRequireItem); + $("#settings_cleanVehicleItemName").val(fullConfig.cleanVehicleItemName); + $("#settings_cleanVehicleRemoveOnUse").prop("checked", fullConfig.cleanVehicleRemoveOnUse); + + // Healing + toggleSettingsHealingRequireItem(fullConfig.healRequireItem); + $("#settings_healItemName").val(fullConfig.healItemName); + $("#settings_healRemoveOnUse").prop("checked", fullConfig.healRemoveOnUse); + + // Reviving + toggleSettingsRevivingRequireItem(fullConfig.reviveRequireItem); + $("#settings_reviveItemName").val(fullConfig.reviveItemName); + $("#settings_reviveRemoveOnUse").prop("checked", fullConfig.reviveRemoveOnuse); + + // Robbable accounts + $("#settings_robbableAccountsList").empty(); + if(fullConfig.robbableAccounts) { + fullConfig.robbableAccounts.forEach(account => { + addNewRobbableAccountInList(account) + }); + } + + $("#settings_canAlwaysCarryItem").prop("checked", fullConfig.canAlwaysCarryItem); + + // Depositable accounts + $("#settings_depositableAccountsList").empty(); + if(fullConfig.depositableInSafeAccounts) { + fullConfig.depositableInSafeAccounts.forEach(account => { + addNewDepositableAccountInList(account) + }); + } + + $("#settings_enablePropertyOutfits").prop("checked", fullConfig.enablePropertyOutfits); + + $("#settings_parkAllOwnedVehiclesOnRestart").prop("checked", fullConfig.parkAllOwnedVehiclesOnRestart); + + for(const[markerType, webhook] of Object.entries(fullConfig.specificWebhooks)) { + $("#settings_specific_webhooks").find(`[data-marker-type="${markerType}"]`).val(webhook); + } + + // Reset employee work time setting + $("#settings_resetEmployeeWorkTimeEveryNDays").val(fullConfig.resetEmployeeWorkTimeEveryNDays); +} + +$("#settingsRestoreDefaultBtn").click(async function() { + if(! await confirmDeletion(getLocalizedText("menu:are_you_sure_to_restore_settings"))) return; + + const defaultConfiguration = await $.post(`https://${resName}/getDefaultConfiguration`); + loadSettings(defaultConfiguration); +}) + +function addNewRobbableAccountInList(accountName) { + var listDiv = $("#settings_robbableAccountsList"); + + if(listDiv) { + listDiv.append(` + + `); + + listDiv.find(".remove-account").click(function() { + $(this).parent().remove(); + }); + } +} +$("#settings_addNewRobbableAccountBtn").click(function() { + let robbableAccount = $("#settings_newRobbableAccount").val(); + + if(robbableAccount) { + $("#settings_newRobbableAccount").val(""); + addNewRobbableAccountInList(robbableAccount); + } +}) + +function getRobbableAccounts() { + var listDiv = $("#settings_robbableAccountsList"); + + let robbableAccounts = []; + + listDiv.find(".robbable-account").each(function(index, element) { + robbableAccounts.push( $(element).data("account") ); + }) + + return robbableAccounts; +} + +function addNewDepositableAccountInList(accountName) { + var listDiv = $("#settings_depositableAccountsList"); + + if(listDiv) { + listDiv.append(` + + `); + + listDiv.find(".remove-account").click(function() { + $(this).parent().remove(); + }); + } +} + +$("#settings_addNewDepositableAccountBtn").click(function() { + let depositableAccount = $("#settings_newDepositableAccount").val(); + + if(depositableAccount) { + $("#settings_newDepositableAccount").val(""); + addNewDepositableAccountInList(depositableAccount); + } +}) + +function getDepositableInSafeAccounts() { + var listDiv = $("#settings_depositableAccountsList"); + + let depositableAccounts = []; + + listDiv.find(".depositable-account").each(function(index, element) { + depositableAccounts.push( $(element).data("account") ); + }) + + return depositableAccounts; +} + +// Handcuffs settings +function toggleSettingsHandcuffsRequireItem(enable) { + $("#settings_handcuffRequireItem").prop("checked", enable); + + $("#settings_handcuffsItemName").prop("disabled", !enable); + $("#settings_handcuffsItemName").prop("required", enable); + + $("#settings_handcuffsRemoveOnUse").prop("disabled", !enable); +} + +$("#settings_handcuffRequireItem").change(function() { + toggleSettingsHandcuffsRequireItem( $("#settings_handcuffRequireItem").prop("checked") ); +}) + +function getAllWhitelistedControlsWhileHandcuffed() { + let controls = []; + + $("#whitelisted-controls-while-handcuffed-list").find(".control-btn").each(function(index, element) { + const controlNumber = parseInt( $(element).val() ); + if(controlNumber) controls.push(controlNumber); + }) + + return controls; +} + +function addWhitelistedControlWhileHandcuffed(control="") { + const div = $(` +
    + + +
    + + +
    +
    + `); + + div.find(".btn-close").click(function() { + div.remove(); + }); + + div.find(".control-btn").click(async function() { + const controlNumber = await controlsDialog(); + if(!controlNumber) return; + + $(this).val(controlNumber); + }); + + $("#whitelisted-controls-while-handcuffed-list").append(div); +} + +$("#add-whitelisted-control-while-handcuffed-btn").click(function() { + addWhitelistedControlWhileHandcuffed(); +}) + +// Lockpick settings +function toggleSettingsLockpickRequireItem(enable) { + $("#settings_lockpickCarRequireItem").prop("checked", enable); + + $("#settings_lockpickItemName").prop("disabled", !enable); + $("#settings_lockpickItemName").prop("required", enable); + + $("#settings_lockpickRemoveOnUse").prop("disabled", !enable); +} + +$("#settings_lockpickCarRequireItem").change(function() { + toggleSettingsLockpickRequireItem( $(this).prop("checked") ); +}) + +// Vehicle repair settings +function toggleSettingsVehicleRepairRequireItem(enable) { + $("#settings_repairVehicleRequireItem").prop("checked", enable); + + $("#settings_repairVehicleItemName").prop("disabled", !enable); + $("#settings_repairVehicleItemName").prop("required", enable); + + $("#settings_repairVehicleRemoveOnUse").prop("disabled", !enable); +} + +$("#settings_repairVehicleRequireItem").change(function() { + toggleSettingsVehicleRepairRequireItem( $(this).prop("checked") ); +}) + +// Vehicle cleaning settings +function toggleSettingsVehicleCleaningRequireItem(enable) { + $("#settings_cleanVehicleRequireItem").prop("checked", enable); + + $("#settings_cleanVehicleItemName").prop("disabled", !enable); + $("#settings_cleanVehicleItemName").prop("required", enable); + + $("#settings_cleanVehicleRemoveOnUse").prop("disabled", !enable); +} + +$("#settings_cleanVehicleRequireItem").change(function() { + toggleSettingsVehicleCleaningRequireItem( $(this).prop("checked") ); +}) + +// Healing settings +function toggleSettingsHealingRequireItem(enable) { + $("#settings_healRequireItem").prop("checked", enable); + + $("#settings_healItemName").prop("disabled", !enable); + $("#settings_healItemName").prop("required", enable); + + $("#settings_healRemoveOnUse").prop("disabled", !enable); +} + +$("#settings_healRequireItem").change(function() { + toggleSettingsHealingRequireItem( $(this).prop("checked") ); +}) + +// Reviving settings +function toggleSettingsRevivingRequireItem(enable) { + $("#settings_reviveRequireItem").prop("checked", enable); + + $("#settings_reviveItemName").prop("disabled", !enable); + $("#settings_reviveItemName").prop("required", enable); + + $("#settings_reviveRemoveOnUse").prop("disabled", !enable); +} + +$("#settings_reviveRequireItem").change(function() { + toggleSettingsRevivingRequireItem( $(this).prop("checked") ); +}) + +// Closes menu when clicking ESC +$(document).on('keyup', function(e) { + if (e.key == "Escape") { + if( $("#job-creator").is(":visible") ) { + exit(); + } else if( $("#edit-job").is(":visible") ) { + exitFromEditJob(); + } + } +}); \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/bh.json b/resources/[creators]/jobs_creator/html/menu_translations/bh.json new file mode 100644 index 0000000..60a26b4 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/bh.json @@ -0,0 +1,397 @@ +{ + "menu:jobs": " Poslovi", + "menu:public_markers": " Javni markeri", + "menu:statistics": " Statistika", + "menu:settings": " Podesavanja", + + "menu:create_new_job": "Kreiraj posao", + + "menu:job_label": "Posao label", + "menu:job_id": "Posao ID", + "menu:ranks": "Rankovi", + + "menu:create_new_marker": "Kreiraj novi marker", + + "menu:marker:id": "ID", + "menu:marker:label": "Label", + "menu:marker:type": "Tip", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Minimalna razina", + + "menu:online_players": "Online igraci", + "menu:total_players": "Totalni broj igraca", + "menu:society_money": "Society novac", + + "menu:job:ranks": " Rankovi", + "menu:job:markers": " Markeri", + "menu:job:statistics": " Statistika", + "menu:job:settings": " Postavke", + + "menu:create_new_rank": "Kreiraj novi rank", + + "menu:rank:id": "ID", + "menu:rank:label": "Label", + "menu:rank:name": "Ime", + "menu:rank:grade": "Razina", + "menu:rank:salary": "Plata", + + "menu:job_settings:whitelisted": "Whitelistovan", + "menu:job_settings:enable_billing": "Dozvoli racune", + "menu:job_settings:enable_search_players": "Dozvoli pretrazivanje igraca", + "menu:job_settings:enable_handcuff_players": "Dozvoli vezanje igraca", + "menu:job_settings:enable_lockpick_players": "Dozvoli obijanje vozila", + "menu:job_settings:enable_wash_vehicles": "Dozvoli pranje vozila", + "menu:job_settings:enable_repair_vehicles": "Dozvoli popravljanje vozila", + "menu:job_settings:enable_impound_vehicles": "Dozvoli impound vozila", + "menu:job_settings:enable_check_identities": "Dozvoli provjeru identiteta", + "menu:job_settings:enable_check_vehicle_owner": "Dozvoli provjeru vlasnika vozila", + "menu:job_settings:enable_check_driving_license": "Dozvoli provjeru vozackih dozvola", + "menu:job_settings:enable_check_weapon_license": "Dozvoli provjeru dozvole za oruzje", + "menu:job_settings:enable_heal": "Dozvoli heal-anje", + "menu:job_settings:enable_revive": "Dozvoli revive-anje", + + "menu:job_settings:delete_job": "Obrisi posao", + "menu:job_settings:save_changes": "Sacuvaj podesavanja", + + "menu:rank_creation:create_rank": "Kreiraj rank", + "menu:rank_creation:label": "Label", + "menu:rank_creation:name": "Ime (id)", + "menu:rank_creation:grade": "Razina", + "menu:rank_creation:salary": "Plata", + "menu:rank_creation:close": "Zatvori", + "menu:rank_creation:create": "Kreiraj", + + "menu:rank_edit:edit": "Uredi rank", + "menu:rank_edit:label": "Label", + "menu:rank_edit:name_id": "Ime (id)", + "menu:rank_edit:grade": "Razina", + "menu:rank_edit:salary": "Plata", + "menu:rank_edit:delete": "Obrisi", + "menu:rank_edit:close": "Zatvori", + "menu:rank_edit:save": "Sacuvaj", + + "menu:delete_dialog:delete": "Obrisi", + "menu:delete_dialog:close": "Zatvori", + + "menu:edit_marker:edit_marker": "Uredi marker", + "menu:edit_marker:label": "Label", + "menu:edit_marker:marker_type": "Marker Tip", + "menu:edit_marker:minimum_grade": "Minimalna razina", + "menu:edit_marker:specific_grades": "Specificna razina", + "menu:edit_marker:choose_grades": "Odaberi razinu", + "menu:edit_marker:use_minimum_grade": "Koristi najmanju razinu", + "menu:edit_marker:use_specific_grades": "Koristi specificnu razinu", + "menu:edit_marker:marker_size": "Marker velicina", + "menu:edit_marker:scale_x": "Velicina X", + "menu:edit_marker:scale_y": "Velicina Y", + "menu:edit_marker:scale_z": "Velicina Z", + "menu:edit_marker:marker_coordinates": "Marker koordinate", + "menu:edit_marker:coord_x": "Pozicija X", + "menu:edit_marker:coord_y": "Pozicija Y", + "menu:edit_marker:coord_z": "Pozicija Z", + "menu:edit_marker:current_coords": "Trenutne koordinate", + "menu:edit_marker:marker_color": "Marker boja", + "menu:edit_marker:marker_opacity": "Marker jacina", + "menu:edit_marker:map_blip": "Mapa blip", + "menu:edit_marker:blip_sprite": "Sprite", + "menu:edit_marker:blip_color": "Boja", + "menu:edit_marker:blip_scale": "Velicina", + "menu:edit_marker:standing_npc": "NPC kao marker", + "menu:edit_marker:npc_model": "Model", + "menu:edit_marker:npc_heading": "Rotacija", + "menu:edit_marker:object": "Objekt", + "menu:edit_marker:object_model": "Model", + "menu:edit_marker:object_rotation_pitch": "Nagib", + "menu:edit_marker:object_rotation_roll": "Roll", + "menu:edit_marker:object_rotation_yaw": "Skretanje", + + "menu:grades_dialog:title": "Posao razina", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Vozilo Spawnpoint", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Spawnpoint rotacija", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Trenutne koordinate i rotacija", + "menu:edit_marker:temporary_garage:vehicle_model": "Vozilo Model", + "menu:edit_marker:temporary_garage:vehicle_name": "Vozilo Ime", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Primarna boja", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Sekundarna boja", + "menu:edit_marker:temporary_garage:vehicle_plate": "Tablice", + "menu:edit_marker:temporary_garage:delete": "Obrisi", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Novi model vozila", + "menu:edit_marker:temporary_garage:cant_be_empty": "Ne moze biti prazno", + "menu:edit_marker:temporary_garage:add_vehicle": "Dodaj vozilo", + + "menu:edit_marker:boss:can_wash_money": "Moze prati novac?", + "menu:edit_marker:boss:return_percentage_after_wash": "Procenat povrata nakon pranja", + "menu:edit_marker:boss:add_money_to_society_account": "Dodaj novac na racun firme", + "menu:edit_marker:boss:can_withdraw_money": "Moze podignuti novac?", + "menu:edit_marker:boss:can_deposit_money": "Moze poliziti novac?", + "menu:edit_marker:boss:can_manage_employees": "Moze upravljati zaposlenima?", + "menu:edit_marker:boss:can_manage_wages": "Moze upravljati platama/rankovima?", + + "menu:edit_marker:shop:add_to_shop": "Dodaj shop", + "menu:edit_marker:shop:item_id": "Item ID", + "menu:edit_marker:shop:item_price": "Item cijena", + "menu:edit_marker:shop:black_money": "Prljav novac", + "menu:edit_marker:shop:remove_item": "Ukolini item", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Vozilo Spawnpoint", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Spawnpoint rotacija", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Trenutne koordinate i rotacija", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Novi model vozila", + "menu:edit_marker:garage_buyable:add_vehicle": "Dodaj vozilo", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Vozilo Spawnpoint", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Spawnpoint rotacija", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Trenutne koordinate i rotacija", + + "menu:edit_marker:crafting_table:create_new_craft": "Kreiraj novi krafting spot", + + "menu:edit_marker:armory:is_armory_shared": "Dijeljena oruzarnica?", + "menu:edit_marker:armory:max_ammo_when_take": "Maximalan broj metaka?", + "menu:edit_marker:armory:delete_armory_content": "Isprazni oruzarnicu", + + "menu:edit_marker:stash:delete_stash_content": "Isprazni stash", + + "menu:edit_marker:job_outfit:create_new_outfit": "Kreiraj novi outfit", + + "menu:edit_marker:teleport:teleport_to": "Teleport do", + "menu:edit_marker:teleport:current_coords": "Trenutne koordinate", + + "menu:edit_marker:market:item_id": "Item ID", + "menu:edit_marker:market:item_min_price": "Item minimalna cijena", + "menu:edit_marker:market:item_max_price": "Item maksimalna cijena", + "menu:edit_marker:market:black_money": "Prljav novac?", + "menu:edit_marker:market:time_to_sell": "Vrijeme prodaje", + "menu:edit_marker:market:remove": "Ukloni item", + "menu:edit_marker:market:add_item": "Dodaj item", + + "menu:edit_marker:harvest:requires_a_tool": "Potreban alat?", + "menu:edit_marker:harvest:tool_to_harvest": "Alat za branje", + "menu:edit_marker:harvest:lose_on_use": "Oduzmi nakon koriscenja", + "menu:edit_marker:harvest:quantity_to_lose": "Oduzmi kolicina", + "menu:edit_marker:harvest:probability_to_lose": "Vjerovatnoca za izgubiti", + "menu:edit_marker:harvest:disappear_after_use": "Oduzmi nakon koriscenja", + "menu:edit_marker:harvest:disappear_seconds": "Oduzmi nakon _ sekundi", + "menu:edit_marker:harvest:animations": "Animacije", + "menu:edit_marker:harvest:add_item": "Dodaj item", + + "menu:edit_marker:process:remove_item": "Ukloni item", + "menu:edit_marker:process:give_item": "Daj item", + "menu:edit_marker:process:time_to_process": "Vrijeme procesuiranja", + "menu:edit_marker:process:animations": "Animacije", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Extended Okvir", + "menu:edit_marker:weapon_upgrader:drum_clip": "Drum Okvir", + "menu:edit_marker:weapon_upgrader:flashlight": "Lampica", + "menu:edit_marker:weapon_upgrader:suppressor": "Prigusivac", + "menu:edit_marker:weapon_upgrader:scope": "Scope", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Advanced Scope", + "menu:edit_marker:weapon_upgrader:grip": "Grip", + "menu:edit_marker:weapon_upgrader:box_clip": "Box Clip", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Luxary Finish", + "menu:edit_marker:weapon_upgrader:default_tint": "Default tint", + "menu:edit_marker:weapon_upgrader:green_tint": "Green tint", + "menu:edit_marker:weapon_upgrader:gold_tint": "Gold tint", + "menu:edit_marker:weapon_upgrader:pink_tint": "Pink tint", + "menu:edit_marker:weapon_upgrader:army_tint": "Army tint", + "menu:edit_marker:weapon_upgrader:lspd_tint": "LSPD tint", + "menu:edit_marker:weapon_upgrader:orange_tint": "Orange tint", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platinum tint", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Posao koji moze prodavati iteme?", + "menu:edit_marker:job_shop:allowed_job": "Dozvoli poslu da moze prodavati", + "menu:edit_marker:job_shop:minimum_grade": "Minimalna razina za prodaju", + + "menu:edit_marker:delete_marker": "Obrisi marker", + "menu:edit_marker:close": "Zatvori", + "menu:edit_marker:save": "Sacuvaj", + + "menu:input_text:close": "Zatvori", + "menu:input_text:confirm": "Potvrdi", + + "menu:notification:notification": "Notifikacija", + "menu:notification:close": "Zatvori", + + "menu:not_allowed:you_are_not_allowed": "Nemas dozvolu za kristenje ovog menija!", + "menu:not_allowed:if_you_are_admin": "Gdje si posao??? If you are a server admin, you need to add ACE permission to your server.cfg", + + "menu:animations:animations": "Animacije", + "menu:animations:add_animation": "Dodaj animaciju", + "menu:animations:close": "Zatvori", + "menu:animations:save": "Sacuvaj", + + "menu:dynamic:create_new_job": "Kreiraj novi posao", + "menu:dynamic:new_job_label": "Novi posao label:", + "menu:dynamic:new_job_name": "Novi posao ime (id):", + + "menu:dynamic:delete_job_confirm": "Da li si siguran da zelis obrisati posao?", + + "menu:dynamic:job_markers:create_marker": "Kreiraj marker", + "menu:dynamic:job_markers:label": "Label", + "menu:dynamic:job_markers:coord_x": "Pozicija X", + "menu:dynamic:job_markers:coord_y": "Pozicija Y", + "menu:dynamic:job_markers:coord_z": "Pozicija Z", + "menu:dynamic:job_markers:current_coords": "Trenutne koordinate", + "menu:dynamic:job_markers:min_grade": "Minimalna razina", + + "menu:dynamic:public_markers:create_public_marker": "Kreiraj javni marker", + "menu:dynamic:public_markers:label": "Label", + "menu:dynamic:public_markers:coord_x": "Pozicija X", + "menu:dynamic:public_markers:coord_y": "Pozicija Y", + "menu:dynamic:public_markers:coord_z": "Pozicija Z", + "menu:dynamic:public_markers:current_coords": "Trenutne koordinate", + + "menu:dynamic:harvest:name": "Ime (ID)", + "menu:dynamic:harvest:min_quantity": "Minimalna kolicina", + "menu:dynamic:harvest:max_quantity": "Maksimalna kolicina", + "menu:dynamic:harvest:time_to_harvest": "Vrijeme branja (sekunde)", + "menu:dynamic:harvest:probabilty": "Probability to find", + + "menu:dynamic:default": "Default", + + "menu:dynamic:animations:animation_dictionary": "Animacije:", + "menu:dynamic:animations:animation_name": "Ime animacije:", + "menu:dynamic:animations:animation_duration": "Trajanje animacije (sekunde):", + "menu:dynamic:animations:scenario_name": "Ime scenarija", + "menu:dynamic:animations:scenario_duration": "Trajanje scenarija (sekunde):", + "menu:dynamic:animations:remove": "Obrisi", + + "menu:dynamic:marker_info:stash": "Stash", + "menu:dynamic:marker_info:stash_settings": "Stash podesavanja", + "menu:dynamic:marker_info:armory": "Oruzarnica", + "menu:dynamic:marker_info:armory_settings": "Oruzarnica podesavanja", + "menu:dynamic:marker_info:safe": "Sef", + "menu:dynamic:marker_info:temporary_garage": "Garaza - Privremena vozila", + "menu:dynamic:marker_info:temporary_garage_settings": "Garaza podesavanja", + "menu:dynamic:marker_info:garage_buyable": "Garaza - Vozila na kupovinu", + "menu:dynamic:marker_info:garage_buyable_settings": "Garaza podesavanja", + "menu:dynamic:marker_info:garage_owned": "Vozila u vlasnistvu", + "menu:dynamic:marker_info:garage_owned_settings": "Garaza podesavanja", + "menu:dynamic:marker_info:boss": "Sef", + "menu:dynamic:marker_info:boss_settings": "Sef podesavanja", + "menu:dynamic:marker_info:wardrobe": "Uniforma - Sacuvane uniforme", + "menu:dynamic:marker_info:job_outfit": "Posao Outfit", + "menu:dynamic:marker_info:job_outfit_settings": "Outfiti", + "menu:dynamic:marker_info:shop": "Trgovina (kupi iteme)", + "menu:dynamic:marker_info:shop_settings": "Kupovina stvari", + "menu:dynamic:marker_info:market": "Trgovina (prodaj iteme)", + "menu:dynamic:marker_info:market_settings": "Prodaja stvari", + "menu:dynamic:marker_info:harvest": "Branje pozicija", + "menu:dynamic:marker_info:harvest_settings": "Item za branje", + "menu:dynamic:marker_info:process": "Procesurianje pozicija", + "menu:dynamic:marker_info:process_settings": "Item za procesuiranje", + "menu:dynamic:marker_info:crafting_table": "Stol za kraftanje", + "menu:dynamic:marker_info:crafting_table_settings": "Recepti za kraftanje", + "menu:dynamic:marker_info:teleport": "Teleporter", + "menu:dynamic:marker_info:teleport_settings": "Teleporter podesavanja", + "menu:dynamic:marker_info:weapon_upgrader": "Nadogradnja oruzja", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Komponente/Tinte cijene", + "menu:dynamic:marker_info:duty": "On/Off Duznost", + "menu:dynamic:marker_info:job_shop": "Posao trgovina", + "menu:dynamic:marker_info:job_shop_settings": "Trgovina podesavanja", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Vrijeme kraftanja (sekunde)", + "menu:dynamic:marker:crafting_table:result_item": "Item koji dobije", + "menu:dynamic:marker:crafting_table:quantity": "Kolicina", + "menu:dynamic:marker:crafting_table:item_id": "Item ID", + "menu:dynamic:marker:crafting_table:item_quantity": "Item kolicina", + "menu:dynamic:marker:crafting_table:lose_on_use": "Oduzmi na koriscenje", + "menu:dynamic:marker:crafting_table:remove": "Oduzmi", + "menu:dynamic:marker:crafting_table:animations": "Animacije", + "menu:dynamic:marker:crafting_table:add_to_craft": "Dodaj na kraftovanje", + "menu:dynamic:marker:crafting_table:remove_craft": "Ukloni sa kraftovanja", + + "menu:dynamic:marker:temporary_garage:delete": "Obrisi", + "menu:dynamic:marker:temporary_garage:random_plate": "Random tablice", + + "menu:datatable:lengthMenu": "Pokazi _MENU_ rezultati", + "menu:datatable:zeroRecords": "Nema rezultata", + "menu:datatable:info": "Pokazivanje _PAGE_ od _PAGES_", + "menu:datatable:infoEmpty": "Nema rezultata", + "menu:datatable:infoFiltered": "(filter od _MAX_ rezultata)", + "menu:datatable:search": "Pretrazi:", + "menu:datatable:next": "Dalje", + "menu:datatable:previous": "Predhodno", + + "menu:chart:players_in_rank": "Igraci sa rankom", + + "menu:settings:player_menu_position": "Pozicija menija", + "menu:settings:player_menu_position:bottom_right": "Dole desno", + "menu:settings:player_menu_position:top_right": "Gore desno", + "menu:settings:player_menu_position:bottom_left": "Dole lijevo", + "menu:settings:player_menu_position:top_left": "Gore lijevo", + "menu:settings:max_distance_marker": "Maksimalna distanca vidljivosti markera", + "menu:settings:use3Dtext": "Koristi 3D text", + "menu:settings:text_size": "Text velicina", + "menu:settings:font_to_use": "Font texta", + "menu:settings:seconds_to_lockpick_car": "Trajanje lockpickpickovanja", + "menu:settings:vehicle_alarm": "Ukljuci alarm vozila?", + "menu:settings:jsfour_idcard": "Koristi jsfour-idcard skriptu (if you have it) to view target ID card in check identity/vehicle license/weapon license action", + "menu:settings:can_use_actions_off_duty": "Moze li koristiti F6 menu ako nije na duznosti?", + "menu:settings:car_driving_licenses_ids": "Vozacke dozvole", + "menu:settings:weapon_licenses_ids": "Oruzje dozvole", + "menu:settings:new_driving_license": "Nove vozacke dozvole", + "menu:settings:add": "Dodaj", + "menu:settings:new_weapon_license": "Nove dozvole za oruzje", + "menu:settings:can_sell_multiple_items": "Moze prodati vecu kolicinu?", + "menu:settings:language": "Jezik", + "menu:settings:allow_afk_farming": "Dozvoli automatsko branje i procesuiranje", + "menu:settings:unemployed_job_id": "Nezaposlen posao ID", + "menu:settings:unemployed_job_grade": "Nezaposlen posao razina", + "menu:settings:ace_permission": "ACE premisija", + + "menu:settings:enable_discord_logs": "Dozvoli discord logove", + "menu:settings:discord_webhooks": "Discord webhooks", + "menu:settings:main_webhook": "Glavni webhook", + "menu:settings:separated_webhooks": "Odvojeni webhooks", + + "menu:settings:handcuffs_requires_item": "Vezanje zahtjeva item", + "menu:settings:handcuffs_item_name": "Lisice item", + + "menu:settings:lockpick_requires_item": "Lockpickovanje zahtjeva item", + "menu:settings:lockpick_item_name": "Lockpick item ime", + "menu:settings:lockpickRemoveOnUse": "Oduzmi nakon koriscenja?", + + "menu:settings:robbable_accounts": "Racuni moguci za oplajckati", + "menu:settings:new_robbable_account": "Novi racun", + "menu:settings:canAlwaysCarryItem": "Moze uvjek nositi iteme", + "menu:settings:accounts_depositable_in_safe": "Vrste novca koje se mogu ostaviti u sef", + "menu:settings:enable_cash_in_safes_old_esx": "Dozvoli kes u efovima za stari ESX", + + "menu:settings:vehicle_reparation": "Popravka vozila", + "menu:settings:repair_vehicle_requires_item": "Popravi vozilo zahtjeva item", + "menu:settings:repair_vehicle_item_name": "Fixkit item ime", + "menu:settings:lose_fixkit_on_use": "Oduzmi nakon koriscenja?", + + "menu:settings:vehicle_cleaning": "Pranje vozila", + "menu:settings:clean_vehicle_requires_item": "Pranje zahtjeva item", + "menu:settings:clean_vehicle_item_name": "Spuzva item ime", + "menu:settings:lose_sponge_on_use": "Oduzmi nakon koriscenja?", + + "menu:settings:healing": "Lijecenje", + "menu:settings:healing_requires_item": "Lijecenje zahtjeva item", + "menu:settings:healing_item_name": "Bandage item ime", + "menu:settings:lose_bandage_on_use": "Oduzmi nakon koriscenja?", + + "menu:settings:reviving": "Reanimacija", + "menu:settings:reviving_requires_item": "Reanimacija zahtjeva item", + "menu:settings:reviving_item_name": "Medikit item ime", + "menu:settings:lose_medikit_on_use": "Oduzmi nakon koriscenja?", + + "menu:settings:enable_property_outfits": "Dozvoli outfite iz property datastore u ormaricima za presvlacenje", + + "menu:settings:apply_changes": "Potvrdi promjene", + "menu:settings:restore_default_config": "Vrati na tvornicke", + "menu:are_you_sure_to_restore_settings": "Da li si siguran da zelis sve obrisati?", + + "menu:items_dialog:title": "Lista item", + "menu:items_dialog:search_item": "Trazi item", + + "menu:weapons_dialog:title": "Lista oruzja", + "menu:weapons_dialog:search_weapon": "Trazi oruzje", + + "menu:dialog:choose_item": "Odaberi item", + "menu:dialog:choose_weapon": "Odaberi oruzje" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/cz.json b/resources/[creators]/jobs_creator/html/menu_translations/cz.json new file mode 100644 index 0000000..bb13366 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/cz.json @@ -0,0 +1,422 @@ +{ + "menu:jobs": " Pracovní nabídky", + "menu:public_markers": " Veřejné značky", + "menu:statistics": " Statistiky", + "menu:settings": " Nastavení", + + "menu:create_new_job": "Vytvoření nové práce", + + "menu:job_label": "Označení práce", + "menu:job_id": "Práce ID", + "menu:ranks": "Hodnosti", + + "menu:create_new_marker": "Vytvořit nový marker", + + "menu:marker:id": "ID", + "menu:marker:label": "Označení", + "menu:marker:type": "Typ", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Minimální známka", + + "menu:online_players": "Online hráči", + "menu:total_players": "Celkový počet hráčů", + "menu:society_money": "Peníze společnosti", + + "menu:job:ranks": " Hodnosti", + "menu:job:markers": " Markery", + "menu:job:statistics": " Statistiky", + "menu:job:settings": " Nastavení", + + "menu:create_new_rank": "Vytvoření nové hodnosti", + + "menu:rank:id": "ID", + "menu:rank:label": "Označení", + "menu:rank:name": "Název", + "menu:rank:grade": "Třída", + "menu:rank:salary": "Plat", + + "menu:job_settings:whitelisted": "Whitelisted", + "menu:job_settings:enable_billing": "Povolení fakturace", + "menu:job_settings:enable_search_players": "Povolit okrádání/vyhledávání hráčů", + "menu:job_settings:enable_handcuff_players": "Povolit pouta hráčů", + "menu:job_settings:enable_lockpick_players": "Povolení lockpick vozů", + "menu:job_settings:enable_wash_vehicles": "Povolit mytí vozidel", + "menu:job_settings:enable_repair_vehicles": "Umožnit opravu vozidel", + "menu:job_settings:enable_impound_vehicles": "Povolit zabavení vozidel", + "menu:job_settings:enable_check_identities": "Povolení kontrolních identit", + "menu:job_settings:enable_check_vehicle_owner": "Povolit kontrolu vlastníka vozidla", + "menu:job_settings:enable_check_driving_license": "Povolit kontrolu řidičského průkazu", + "menu:job_settings:enable_check_weapon_license": "Povolit kontrolu zbrojního průkazu", + "menu:job_settings:enable_heal": "Povolit léčení", + "menu:job_settings:enable_revive": "Povolit oživení", + + "menu:job_settings:delete_job": "Odstranění úlohy", + "menu:job_settings:save_changes": "Uložení změn", + + "menu:rank_creation:create_rank": "Vytvořit hodnost", + "menu:rank_creation:label": "Označení", + "menu:rank_creation:name": "Název (id)", + "menu:rank_creation:grade": "Třída", + "menu:rank_creation:salary": "Salary", + "menu:rank_creation:close": "Zavřít", + "menu:rank_creation:create": "Vytvořit", + + "menu:rank_edit:edit": "Upravit hodnost", + "menu:rank_edit:label": "Označení", + "menu:rank_edit:name_id": "Název (id)", + "menu:rank_edit:grade": "Grade", + "menu:rank_edit:salary": "SSalaryalary", + "menu:rank_edit:delete": "Odstranit", + "menu:rank_edit:close": "Zavřít", + "menu:rank_edit:save": "Uložit", + + "menu:delete_dialog:delete": "Odstranit", + "menu:delete_dialog:close": "Zavřít", + + "menu:edit_marker:edit_marker": "Upravit marker", + "menu:edit_marker:label": "Označení", + "menu:edit_marker:marker_type": "Typ markeru", + "menu:edit_marker:minimum_grade": "Minimální stupeň", + "menu:edit_marker:specific_grades": "Specifické třídy", + "menu:edit_marker:choose_grades": "Zvolte si stupně", + "menu:edit_marker:use_minimum_grade": "Použijte minimální stupeň", + "menu:edit_marker:use_specific_grades": "Použití specifických tříd", + "menu:edit_marker:marker_size": "Velikost markeru", + "menu:edit_marker:scale_x": "Scale X", + "menu:edit_marker:scale_y": "Scale Y", + "menu:edit_marker:scale_z": "Scale Z", + "menu:edit_marker:marker_coordinates": "Souřadnice markerů", + "menu:edit_marker:coord_x": "Koordinace X", + "menu:edit_marker:coord_y": "Koordinace Y", + "menu:edit_marker:coord_z": "Koordinace Z", + "menu:edit_marker:current_coords": "Aktuální souřadnice", + "menu:edit_marker:marker_color": "Barva markeru", + "menu:edit_marker:marker_opacity": "Neprůhlednost markeru", + "menu:edit_marker:map_blip": "Mapa blipu", + "menu:edit_marker:blip_sprite": "Sprite", + "menu:edit_marker:blip_color": "Barva", + "menu:edit_marker:blip_scale": "Scale", + "menu:edit_marker:standing_npc": "Stojící NPC", + "menu:edit_marker:npc_model": "Model", + "menu:edit_marker:npc_heading": "Heading", + "menu:edit_marker:object": "Objekt", + "menu:edit_marker:object_model": "Model", + "menu:edit_marker:object_rotation_pitch": "Pitch", + "menu:edit_marker:object_rotation_roll": "Roll", + "menu:edit_marker:object_rotation_yaw": "Yaw", + + "menu:grades_dialog:title": "Stupně práce", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Spawnpoint vozidla", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Spawnpoint heading", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Aktuální souřadnice a kurz", + "menu:edit_marker:temporary_garage:vehicle_model": "Model vozidla", + "menu:edit_marker:temporary_garage:vehicle_name": "Název vozidla", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Základní barva", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Sekundární barva", + "menu:edit_marker:temporary_garage:vehicle_plate": "SPZ", + "menu:edit_marker:temporary_garage:delete": "Smazat", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Nový model vozidla", + "menu:edit_marker:temporary_garage:cant_be_empty": "Nemůže být prázdný", + "menu:edit_marker:temporary_garage:add_vehicle": "Přidat vozidlo", + + "menu:edit_marker:boss:can_wash_money": "Umí prát peníze?", + "menu:edit_marker:boss:return_percentage_after_wash": "Procento návratnosti po praní", + "menu:edit_marker:boss:add_money_to_society_account": "Přidat peníze na účet společnosti", + "menu:edit_marker:boss:can_withdraw_money": "Můžete si vybrat peníze?", + "menu:edit_marker:boss:can_deposit_money": "Můžete vložit peníze?", + "menu:edit_marker:boss:can_manage_employees": "Může spravovat zaměstnance?", + "menu:edit_marker:boss:can_manage_wages": "Může spravovat mzdy/třídy?", + "menu:edit_marker:boss:maximum_salary": "Maximální plat", + + "menu:edit_marker:shop:add_to_shop": "Přidat do obchodu", + "menu:edit_marker:shop:item_id": "Item ID", + "menu:edit_marker:shop:item_price": "Cena položky", + "menu:edit_marker:shop:black_money": "Špivané peníze", + "menu:edit_marker:shop:remove_item": "Odstranit položku", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Spawnpoint vozidla", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Spawnpoint heading", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Aktuální souřadnice a kurz", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Nový model vozidla", + "menu:edit_marker:garage_buyable:add_vehicle": "Přidat vozidlo", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Spawnpoint vozidla", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Spawnpoint heading", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Aktuální souřadnice a kurz", + + "menu:edit_marker:crafting_table:create_new_craft": "Vytvořit nové řemeslo", + + "menu:edit_marker:armory:is_armory_shared": "Je zbrojnice společná?", + "menu:edit_marker:armory:max_ammo_when_take": "Max. munice při převzetí?", + "menu:edit_marker:armory:delete_armory_content": "Smazat obsah zbrojnice", + + "menu:edit_marker:stash:delete_stash_content": "Smazat obsah skrýše", + + "menu:edit_marker:job_outfit:create_new_outfit": "Vytvořit nový outfit", + + "menu:edit_marker:teleport:teleport_to": "Teleport do", + "menu:edit_marker:teleport:current_coords": "Aktuální souřadnice", + + "menu:edit_marker:market:item_id": "ID položky", + "menu:edit_marker:market:item_min_price": "Minimální cena položky", + "menu:edit_marker:market:item_max_price": "Maximální cena položky", + "menu:edit_marker:market:black_money": "Špinavé peníze?", + "menu:edit_marker:market:time_to_sell": "Čas do prodeje", + "menu:edit_marker:market:remove": "Odstranit", + "menu:edit_marker:market:add_item": "Přidat položku", + "menu:edit_marker_market:society_percentage": "Procento, které společnost obdrží", + + "menu:edit_marker:harvest:requires_a_tool": "Vyžaduje nástroj?", + "menu:edit_marker:harvest:tool_to_harvest": "Nástroj pro sklizeň", + "menu:edit_marker:harvest:lose_on_use": "Ztráta při použití", + "menu:edit_marker:harvest:quantity_to_lose": "Množství ke ztrátě", + "menu:edit_marker:harvest:probability_to_lose": "Pravděpodobnost prohry", + "menu:edit_marker:harvest:disappear_after_use": "Po použití zmizí", + "menu:edit_marker:harvest:disappear_seconds": "Zmizet vteřiny", + "menu:edit_marker:harvest:animations": "Animace", + "menu:edit_marker:harvest:add_item": "Přidat položku", + + "menu:edit_marker:process:remove_item": "Odstranit položku", + "menu:edit_marker:process:give_item": "Dejte položku", + "menu:edit_marker:process:time_to_process": "Čas do zpracování", + "menu:edit_marker:process:animations": "Animace", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Extended Clip", + "menu:edit_marker:weapon_upgrader:drum_clip": "Drum Clip", + "menu:edit_marker:weapon_upgrader:flashlight": "Flashlight", + "menu:edit_marker:weapon_upgrader:suppressor": "Suppressor", + "menu:edit_marker:weapon_upgrader:scope": "Scope", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Advanced Scope", + "menu:edit_marker:weapon_upgrader:grip": "Grip", + "menu:edit_marker:weapon_upgrader:box_clip": "Box Clip", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Luxary Finish", + "menu:edit_marker:weapon_upgrader:default_tint": "Výchozí odstín", + "menu:edit_marker:weapon_upgrader:green_tint": "Zelený odstín", + "menu:edit_marker:weapon_upgrader:gold_tint": "Zlatý odstín", + "menu:edit_marker:weapon_upgrader:pink_tint": "Růžový odstín", + "menu:edit_marker:weapon_upgrader:army_tint": "Armádní odstín", + "menu:edit_marker:weapon_upgrader:lspd_tint": "LSPD tint", + "menu:edit_marker:weapon_upgrader:orange_tint": "Oranžový odstín", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platinový odstín", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Práce, která může dát na prodejní položky", + "menu:edit_marker:job_shop:allowed_job": "Povolená práce k prodeji", + "menu:edit_marker:job_shop:minimum_grade": "Minimální třída povolená k prodeji", + + "menu:edit_marker:delete_marker": "Odstranit značku", + "menu:edit_marker:close": "Zavřít", + "menu:edit_marker:save": "Uložit", + + "menu:input_text:close": "Zavřít", + "menu:input_text:confirm": "Potvrďte", + + "menu:notification:notification": "Notification", + "menu:notification:close": "Zavřít", + + "menu:not_allowed:you_are_not_allowed": "Tuto nabídku nesmíte používat", + "menu:not_allowed:if_you_are_admin": "Pokud jste správce serveru, musíte do souboru server.cfg přidat oprávnění ACE.", + + "menu:animations:animations": "Animace", + "menu:animations:add_animation": "Přidání animace", + "menu:animations:close": "Zavřít", + "menu:animations:save": "Uložit", + + "menu:dynamic:create_new_job": "Vytvoření nové úlohy", + "menu:dynamic:new_job_label": "Nové označení pracovních míst:", + "menu:dynamic:new_job_name": "Název nového pracovního místa (id):", + + "menu:dynamic:delete_job_confirm": "Opravdu chcete tuto úlohu odstranit?", + + "menu:dynamic:job_markers:create_marker": "Vytvořit značku", + "menu:dynamic:job_markers:label": "Označení", + "menu:dynamic:job_markers:coord_x": "Koordinace X", + "menu:dynamic:job_markers:coord_y": "Koordinace Y", + "menu:dynamic:job_markers:coord_z": "Koordinace Z", + "menu:dynamic:job_markers:current_coords": "Aktuální souřadnice", + "menu:dynamic:job_markers:min_grade": "Minimální stupeň", + + "menu:dynamic:public_markers:create_public_marker": "Vytvořit veřejnou značku", + "menu:dynamic:public_markers:label": "Označení", + "menu:dynamic:public_markers:coord_x": "Koordinace X", + "menu:dynamic:public_markers:coord_y": "Koordinace Y", + "menu:dynamic:public_markers:coord_z": "Koordinace Z", + "menu:dynamic:public_markers:current_coords": "Aktuální souřadnice", + + "menu:dynamic:harvest:name": "Název (ID)", + "menu:dynamic:harvest:min_quantity": "Minimální množství", + "menu:dynamic:harvest:max_quantity": "Maximální množství", + "menu:dynamic:harvest:time_to_harvest": "Doba do sklizně (sekundy)", + "menu:dynamic:harvest:probabilty": "Pravděpodobnost nalezení", + + "menu:dynamic:default": "Výchozí", + + "menu:dynamic:animations:animation_dictionary": "Animační slovník:", + "menu:dynamic:animations:animation_name": "Název animace:", + "menu:dynamic:animations:animation_duration": "Doba trvání animace (sekundy):", + "menu:dynamic:animations:scenario_name": "Název scénáře", + "menu:dynamic:animations:scenario_duration": "Doba trvání scénáře (v sekundách):", + "menu:dynamic:animations:remove": "Odstranit", + + "menu:dynamic:marker_info:stash": "Úschovna", + "menu:dynamic:marker_info:stash_settings": "Nastavení skrýše", + "menu:dynamic:marker_info:armory": "Zbrojnice", + "menu:dynamic:marker_info:armory_settings": "Nastavení zbrojnice", + "menu:dynamic:marker_info:safe": "Safe", + "menu:dynamic:marker_info:temporary_garage": "Garáž - Dočasná vozidla", + "menu:dynamic:marker_info:temporary_garage_settings": "Nastavení garáže", + "menu:dynamic:marker_info:garage_buyable": "Garáž - Zakoupitelná vozidla", + "menu:dynamic:marker_info:garage_buyable_settings": "Nastavení garáže", + "menu:dynamic:marker_info:garage_owned": "Vlastní vozidla", + "menu:dynamic:marker_info:garage_owned_settings": "Nastavení garáže", + "menu:dynamic:marker_info:boss": "Šéf", + "menu:dynamic:marker_info:boss_settings": "Nastavení šéfa", + "menu:dynamic:marker_info:wardrobe": "Šatník - oblečení uložené hráčem", + "menu:dynamic:marker_info:job_outfit": "Pracovní oblečení", + "menu:dynamic:marker_info:job_outfit_settings": "Oblečení", + "menu:dynamic:marker_info:shop": "Obchod (nákup položek)", + "menu:dynamic:marker_info:shop_settings": "Položky obchodu", + "menu:dynamic:marker_info:market": "Trh (prodej zboží)", + "menu:dynamic:marker_info:market_settings": "Položky na trhu", + "menu:dynamic:marker_info:harvest": "Bod sklizně", + "menu:dynamic:marker_info:harvest_settings": "Položky, které lze sklízet", + "menu:dynamic:marker_info:process": "Procesní bod", + "menu:dynamic:marker_info:process_settings": "Zpracovatelná položka", + "menu:dynamic:marker_info:crafting_table": "Stůl pro řemeslníky", + "menu:dynamic:marker_info:crafting_table_settings": "Recepty pro řemeslnou výrobu", + "menu:dynamic:marker_info:teleport": "Teleportační bod", + "menu:dynamic:marker_info:teleport_settings": "Nastavení teleportu", + "menu:dynamic:marker_info:weapon_upgrader": "Vylepšovač zbraní", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Komponenty/Ceny odstínů", + "menu:dynamic:marker_info:duty": "On/Off Duty", + "menu:dynamic:marker_info:job_shop": "Obchod s pracovními příležitostmi", + "menu:dynamic:marker_info:job_shop_settings": "Nastavení obchodu", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Čas do craftingu (sekundy)", + "menu:dynamic:marker:crafting_table:result_item": "Položka výsledku", + "menu:dynamic:marker:crafting_table:quantity": "Množství", + "menu:dynamic:marker:crafting_table:item_id": "Item ID", + "menu:dynamic:marker:crafting_table:item_quantity": "Množství položky", + "menu:dynamic:marker:crafting_table:lose_on_use": "Ztratit při použití", + "menu:dynamic:marker:crafting_table:remove": "Odstranění adresy", + "menu:dynamic:marker:crafting_table:animations": "Animace", + "menu:dynamic:marker:crafting_table:add_to_craft": "Přidat do řemesla", + "menu:dynamic:marker:crafting_table:remove_craft": "Odebrat plavidlo", + + "menu:dynamic:marker:temporary_garage:delete": "Odstranit", + "menu:dynamic:marker:temporary_garage:random_plate": "Náhodná spz", + + "menu:datatable:lengthMenu": "Zobrazit výsledky _MENU_", + "menu:datatable:zeroRecords": "Žádné výsledky", + "menu:datatable:info": "Zobrazení _PAGE_ of _PAGES_", + "menu:datatable:infoEmpty": "Nejsou k dispozici žádné výsledky", + "menu:datatable:infoFiltered": "(filtrováno z _MAX_ výsledků)", + "menu:datatable:search": "Hledat:", + "menu:datatable:next": "Další", + "menu:datatable:previous": "Předchozí", + + "menu:chart:players_in_rank": "Hráči v pořadí", + + "menu:settings:player_menu_position": "Pozice nabídky hráče", + "menu:settings:player_menu_position:bottom_right": "Vpravo dole", + "menu:settings:player_menu_position:top_right": "Vpravo nahoře", + "menu:settings:player_menu_position:right": "Vpravo", + "menu:settings:player_menu_position:bottom_left": "Vlevo dole", + "menu:settings:player_menu_position:top_left": "Vlevo nahoře", + "menu:settings:player_menu_position:left": "Vlevo", + "menu:settings:max_distance_marker": "Max. vzdálenost, ve které je marker vidět", + "menu:settings:use3Dtext": "Použít 3D text místo značek", + "menu:settings:text_size": "Velikost textu", + "menu:settings:font_to_use": "Použité písmo", + "menu:settings:seconds_to_lockpick_car": "Sekundy na odemknutí auta", + "menu:settings:vehicle_alarm": "Má mít vozidlo při lockpickování alarm?", + "menu:settings:jsfour_idcard": "Použijte skript jsfour-idcard (pokud jej máte) pro zobrazení cílové ID karty v akci kontrola totožnosti/licence vozidla/licence zbraně", + "menu:settings:can_use_actions_off_duty": "Může hráč používat nabídku akcí F6, když je mimo službu?", + "menu:settings:car_driving_licenses_ids": "ID řidičských průkazů automobilů", + "menu:settings:weapon_licenses_ids": "ID licencí na zbraně", + "menu:settings:new_driving_licence": "Nový řidičský průkaz", + "menu:settings:add": "Přidat", + "menu:settings:new_weapon_licence": "Nový zbrojní průkaz", + "menu:settings:can_sell_multiple_items": "Lze na trhu prodávat více položek najednou?", + "menu:settings:language": "Jazyk", + "menu:settings:allow_afk_farming": "Povolení automatické sklizně a zpracování markerů v zemědělství", + "menu:settings:unemployed_job_id": "ID nezaměstnaného zaměstnání", + "menu:settings:unemployed_job_grade": "Třída nezaměstnanosti", + "menu:settings:ace_permission": "Povolení ACE", + + "menu:settings:enable_discord_logs": "Povolit protokoly diskordu", + "menu:settings:discord_webhooks": "Discord webhook", + "menu:settings:main_webhook": "Hlavní webhook", + "menu:settings:separated_webhooks": "Oddělené webhooky", + + "menu:settings:handcuffs_requires_item": "Pouta vyžadují položku", + "menu:settings:handcuffs_item_name": "Název položky Pouta", + + "menu:settings:lockpick_requires_item": "Lockpick vozidla vyžaduje položku", + "menu:settings:lockpick_item_name": "Název položky Lockpick", + "menu:settings:lockpickRemoveOnUse": "Ztráta lockpicku při použití", + + "menu:settings:robbable_accounts": "Robbovatelné účty", + "menu:settings:new_robbable_account": "Nový účet", + "menu:settings:canAlwaysCarryItem": "Může vždy nosit předměty", + "menu:settings:accounts_depositable_in_safe": "Účty ukládané do trezoru", + "menu:settings:enable_cash_in_safes_old_esx": "Povolení hotovosti v trezoru pro starou verzi ESX", + + "menu:settings:vehicle_reparation": "Vehicle reparation", + "menu:settings:repair_vehicle_requires_item": "Oprava vozidla vyžaduje položku", + "menu:settings:repair_vehicle_item_name": "Název položky sady Fixkit", + "menu:settings:lose_fixkit_on_use": "Ztráta sady fixkit při použití", + + "menu:settings:vehicle_cleaning": "Čištění vozidel", + "menu:settings:clean_vehicle_requires_item": "Čisté vozidlo vyžaduje položku", + "menu:settings:clean_vehicle_item_name": "Název položky houby", + "menu:settings:lose_sponge_on_use": "Ztráta houby při použití", + + "menu:settings:healing": "Léčení", + "menu:settings:healing_requires_item": "Léčení vyžaduje položku", + "menu:settings:healing_item_name": "Název položky obvazu", + "menu:settings:lose_bandage_on_use": "Ztráta obvazu při použití", + + "menu:settings:reviving": "Oživení", + "menu:settings:reviving_requires_item": "Oživení vyžaduje položku", + "menu:settings:reviving_item_name": "Název položky Medikit", + "menu:settings:lose_medikit_on_use": "Lose Ztráta lékárničky při použitímedikit on use", + + "menu:settings:enable_property_outfits": "Povolit oblečení z datového skladu majetku ve značce skříně", + + "menu:settings:apply_changes": "Použít změny", + "menu:settings:restore_default_config": "Obnovit výchozí konfiguraci", + "menu:are_you_sure_to_restore_settings": "Určitě chcete obnovit výchozí nastavení?", + + "menu:items_dialog:title": "Seznam položek", + "menu:items_dialog:search_item": "Hledat položku", + + "menu:weapons_dialog:title": "Seznam zbraní", + "menu:weapons_dialog:search_weapon": "Hledat zbraň", + + "menu:dialog:choose_item": "Vyberte si položku", + "menu:dialog:choose_weapon": "Výběr zbraně", + + "menu:settings:actions_menu_key": "Klávesa pro otevření nabídky akcí", + + "menu:settings:park_all_owned_vehicles_on_restart": "Zaparkujte všechna vlastní vozidla na restartu", + + "menu:account_name": "Název účtu", + "menu:accounts_dialog:title": "Seznam účtů", + "menu:minimum_amount": "Minimální částka", + + "menu:edit_marker:requires_minimum_account_money": "Vyžaduje minimální částku na účtu?", + + "menu:actions": "Akce", + + "menu:settings:freeze_when_soft_handcuffed": "Zmrazení při použití měkkých pout", + "menu:settings:freeze_when_hard_handcuffed": "Zamrznutí při pevném spoutání", + + "menu:coords": "Souřadnice", + "menu:heading": "Heading", + "menu:add_spawnpoint": "Přidání spawnpointu", + "menu:spawnpoints": "Spawnpointy", + "menu:radius": "Poloměr" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/da.json b/resources/[creators]/jobs_creator/html/menu_translations/da.json new file mode 100644 index 0000000..18c6350 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/da.json @@ -0,0 +1,412 @@ +{ + "menu:jobs": " Jobs", + "menu:public_markers": " offetlige markers", + "menu:statistics": " Statistikker", + "menu:settings": " Indstillinger", + + "menu:create_new_job": "Lav nyt job", + + "menu:job_label": "Job label", + "menu:job_id": "Job ID", + "menu:ranks": "Stillinger", + + "menu:create_new_marker": "Lav ny marker", + + "menu:marker:id": "ID", + "menu:marker:label": "Label", + "menu:marker:type": "Type", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Minimum stilling", + + "menu:online_players": "Online spillere", + "menu:total_players": "Alle Spillere", + "menu:society_money": "Firma penge", + + "menu:job:ranks": " Stillinger", + "menu:job:markers": " Markers", + "menu:job:statistics": " Statistikker", + "menu:job:settings": " Indstillinger", + + "menu:create_new_rank": "Lav ny stilling", + + "menu:rank:id": "ID", + "menu:rank:label": "Label", + "menu:rank:name": "Navn", + "menu:rank:grade": "Grad", + "menu:rank:salary": "Løn", + + "menu:job_settings:whitelisted": "Whitelisted", + "menu:job_settings:enable_billing": "Kan skrive regninger", + "menu:job_settings:enable_search_players": "Kan røve/visitere spillere", + "menu:job_settings:enable_handcuff_players": "Kan bruge håndjern", + "menu:job_settings:enable_lockpick_players": "Kan dirke låse", + "menu:job_settings:enable_wash_vehicles": "Kan vaske køretøjer", + "menu:job_settings:enable_repair_vehicles": "Kan lave køretøjer", + "menu:job_settings:enable_impound_vehicles": "Kan beslaglægge biler", + "menu:job_settings:enable_check_identities": "Kan tjekke id", + "menu:job_settings:enable_check_vehicle_owner": "Kan tjekker køretøjsejer", + "menu:job_settings:enable_check_driving_license": "Kan tjekke kørekort", + "menu:job_settings:enable_check_weapon_license": "Kan tjekke jagtegn", + "menu:job_settings:enable_heal": "Kan heale", + "menu:job_settings:enable_revive": "Kan kurer", + + "menu:job_settings:delete_job": "Slet job", + "menu:job_settings:save_changes": "Gem ændringer", + + "menu:rank_creation:create_rank": "Lav ny stilling", + "menu:rank_creation:label": "Label", + "menu:rank_creation:name": "Navn (id)", + "menu:rank_creation:grade": "Grad", + "menu:rank_creation:salary": "Løn", + "menu:rank_creation:close": "Luk", + "menu:rank_creation:create": "Lav", + + "menu:rank_edit:edit": "Rediger stilling", + "menu:rank_edit:label": "Label", + "menu:rank_edit:name_id": "Navn (id)", + "menu:rank_edit:grade": "Stilling", + "menu:rank_edit:salary": "Løn", + "menu:rank_edit:delete": "Slet", + "menu:rank_edit:close": "Luk", + "menu:rank_edit:save": "Gem", + + "menu:delete_dialog:delete": "Slet", + "menu:delete_dialog:close": "Luk", + + "menu:edit_marker:edit_marker": "Rediger marker", + "menu:edit_marker:label": "Label", + "menu:edit_marker:marker_type": "Marker Type", + "menu:edit_marker:minimum_grade": "Minimum Stilling", + "menu:edit_marker:specific_grades": "Specifik stilling", + "menu:edit_marker:choose_grades": "Vælg Stillinger", + "menu:edit_marker:use_minimum_grade": "Brug minimum stilling", + "menu:edit_marker:use_specific_grades": "Brug specifik stilling", + "menu:edit_marker:marker_size": "Marker størrelse", + "menu:edit_marker:scale_x": "Scale X", + "menu:edit_marker:scale_y": "Scale Y", + "menu:edit_marker:scale_z": "Scale Z", + "menu:edit_marker:marker_coordinates": "Marker kordinater", + "menu:edit_marker:coord_x": "Coord X", + "menu:edit_marker:coord_y": "Coord Y", + "menu:edit_marker:coord_z": "Coord Z", + "menu:edit_marker:current_coords": "Nuværende kordinater", + "menu:edit_marker:marker_color": "Marker farve", + "menu:edit_marker:marker_opacity": "Marker synlighed", + "menu:edit_marker:map_blip": "Map blip", + "menu:edit_marker:blip_sprite": "Sprite", + "menu:edit_marker:blip_color": "Color", + "menu:edit_marker:blip_scale": "Scale", + "menu:edit_marker:standing_npc": "Stående NPC", + "menu:edit_marker:npc_model": "Model", + "menu:edit_marker:npc_heading": "Rotation", + "menu:edit_marker:object": "Objekt", + "menu:edit_marker:object_model": "Model", + "menu:edit_marker:object_rotation_pitch": "Pitch", + "menu:edit_marker:object_rotation_roll": "Roll", + "menu:edit_marker:object_rotation_yaw": "Yaw", + + "menu:grades_dialog:title": "Job Stillinger", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Køretøj spawnpunkt", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Spawnpunkt rotation", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Nurværende kordinater og rotation", + "menu:edit_marker:temporary_garage:vehicle_model": "Køretøj Model", + "menu:edit_marker:temporary_garage:vehicle_name": "Køretøj Navn", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Primær farve", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Sekunder farve", + "menu:edit_marker:temporary_garage:vehicle_plate": "Nummerplade", + "menu:edit_marker:temporary_garage:delete": "Slet", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Ny køretøjs model", + "menu:edit_marker:temporary_garage:cant_be_empty": "Kan ikke være tom", + "menu:edit_marker:temporary_garage:add_vehicle": "Tilføj køretøj", + + "menu:edit_marker:boss:can_wash_money": "Kan vaske penge?", + "menu:edit_marker:boss:return_percentage_after_wash": "Retur procent efter hvidvask", + "menu:edit_marker:boss:add_money_to_society_account": "Tilføj penge til firmakonto", + "menu:edit_marker:boss:can_withdraw_money": "Kan hæve penge?", + "menu:edit_marker:boss:can_deposit_money": "Kan indsætte penge?", + "menu:edit_marker:boss:can_manage_employees": "Kan administere ansatte?", + "menu:edit_marker:boss:can_manage_wages": "Kan administere ansatte løn?", + "menu:edit_marker:boss:maximum_salary": "Maksimum løn", + + "menu:edit_marker:shop:add_to_shop": "Tilføj til shop", + "menu:edit_marker:shop:item_id": "Genstand ID", + "menu:edit_marker:shop:item_price": "Genstand pris", + "menu:edit_marker:shop:black_money": "Sorte penge", + "menu:edit_marker:shop:remove_item": "Fjern genstand", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Køretøj spawnpunkt", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Spawnpunkt rotation", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Nuværende kordinater og rotation", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Ny køretøjs model", + "menu:edit_marker:garage_buyable:add_vehicle": "Tilføj køretøj", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Køretøj spawnpunkt", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Spawnpunkt rotation", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Nuværende kordinater og rotation", + + "menu:edit_marker:crafting_table:create_new_craft": "Lav ny crafting-opskrift", + + "menu:edit_marker:armory:is_armory_shared": "Er våbenskab delt melle spillere?", + "menu:edit_marker:armory:max_ammo_when_take": "Maks ammunition der kan tages?", + "menu:edit_marker:armory:delete_armory_content": "Slet våbenskabs indhold", + + "menu:edit_marker:stash:delete_stash_content": "Slet kiste indhold", + + "menu:edit_marker:job_outfit:create_new_outfit": "Lav nyt outfit", + + "menu:edit_marker:teleport:teleport_to": "Teleporter til", + "menu:edit_marker:teleport:current_coords": "Nuværende kordinater", + + "menu:edit_marker:market:item_id": "Item ID", + "menu:edit_marker:market:item_min_price": "Genstand minimum pris", + "menu:edit_marker:market:item_max_price": "Genstand maksimum pris", + "menu:edit_marker:market:black_money": "Sorte penge?", + "menu:edit_marker:market:time_to_sell": "Hvor lang tid tager det at sælge", + "menu:edit_marker:market:remove": "Fjern", + "menu:edit_marker:market:add_item": "Tilføj genstand", + "menu:edit_marker_market:society_percentage": "Procentdel firmaet vil modtage", + + "menu:edit_marker:harvest:requires_a_tool": "Kræver værktøj?", + "menu:edit_marker:harvest:tool_to_harvest": "Værktøj der bruges til at høste", + "menu:edit_marker:harvest:lose_on_use": "Fjern når det bruges?", + "menu:edit_marker:harvest:quantity_to_lose": "Mængde der skal mistes", + "menu:edit_marker:harvest:probability_to_lose": "Chance for at miste", + "menu:edit_marker:harvest:disappear_after_use": "Fjern efter brug", + "menu:edit_marker:harvest:disappear_seconds": "Fjern efter hvor mange sekunder", + "menu:edit_marker:harvest:animations": "Animationer", + "menu:edit_marker:harvest:add_item": "Tilføj genstand", + + "menu:edit_marker:process:remove_item": "Fjern genstand", + "menu:edit_marker:process:give_item": "Giv genstand", + "menu:edit_marker:process:time_to_process": "Tid", + "menu:edit_marker:process:animations": "Animationer", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Udvidet magazin", + "menu:edit_marker:weapon_upgrader:drum_clip": "Drum magazin", + "menu:edit_marker:weapon_upgrader:flashlight": "Lommelygte", + "menu:edit_marker:weapon_upgrader:suppressor": "Lyddæmper", + "menu:edit_marker:weapon_upgrader:scope": "Sigtekorn", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Advanceret sigtekorn", + "menu:edit_marker:weapon_upgrader:grip": "Greb", + "menu:edit_marker:weapon_upgrader:box_clip": "Boks magazin", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Luxary Finish", + "menu:edit_marker:weapon_upgrader:default_tint": "Standard farve", + "menu:edit_marker:weapon_upgrader:green_tint": "Grøn farve", + "menu:edit_marker:weapon_upgrader:gold_tint": "Guld farve", + "menu:edit_marker:weapon_upgrader:pink_tint": "Pink farve", + "menu:edit_marker:weapon_upgrader:army_tint": "Militær farve", + "menu:edit_marker:weapon_upgrader:lspd_tint": "LSPD farve", + "menu:edit_marker:weapon_upgrader:orange_tint": "Orange farve", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platinum farve", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Genstande jobbet kan sælge", + "menu:edit_marker:job_shop:allowed_job": "Tilladte jobs det kan sælge", + "menu:edit_marker:job_shop:minimum_grade": "Minimum stilling der kan sælge", + + "menu:edit_marker:delete_marker": "Slet marker", + "menu:edit_marker:close": "Luk", + "menu:edit_marker:save": "Gem", + + "menu:input_text:close": "Luk", + "menu:input_text:confirm": "Godkend", + + "menu:notification:notification": "Notifikation", + "menu:notification:close": "Luk", + + "menu:not_allowed:you_are_not_allowed": "Du har ikke tilladelse til at bruge denne menu", + "menu:not_allowed:if_you_are_admin": "Hvis du er server admin skal du tilføje ACE tilladelser til server.cfg", + + "menu:animations:animations": "Animationer", + "menu:animations:add_animation": "Tilføj animation", + "menu:animations:close": "Luk", + "menu:animations:save": "Gem", + + "menu:dynamic:create_new_job": "Lav nyt job", + "menu:dynamic:new_job_label": "Nyt job label:", + "menu:dynamic:new_job_name": "Nyt job navn (id):", + + "menu:dynamic:delete_job_confirm": "Er du sikker på at du vil slette det job?", + + "menu:dynamic:job_markers:create_marker": "Lav marker", + "menu:dynamic:job_markers:label": "Label", + "menu:dynamic:job_markers:coord_x": "Coord X", + "menu:dynamic:job_markers:coord_y": "Coord Y", + "menu:dynamic:job_markers:coord_z": "Coord Z", + "menu:dynamic:job_markers:current_coords": "Nuværende kordinater", + "menu:dynamic:job_markers:min_grade": "Minimum stilling", + + "menu:dynamic:public_markers:create_public_marker": "Lav offenligt marker", + "menu:dynamic:public_markers:label": "Label", + "menu:dynamic:public_markers:coord_x": "Coord X", + "menu:dynamic:public_markers:coord_y": "Coord Y", + "menu:dynamic:public_markers:coord_z": "Coord Z", + "menu:dynamic:public_markers:current_coords": "Nurværende kordinater", + + "menu:dynamic:harvest:name": "Navn (ID)", + "menu:dynamic:harvest:min_quantity": "Minimum mængde", + "menu:dynamic:harvest:max_quantity": "Maksimum mængde", + "menu:dynamic:harvest:time_to_harvest": "Tid det tager at høste (sekunder)", + "menu:dynamic:harvest:probabilty": "Chance for at finde", + + "menu:dynamic:default": "Standard", + + "menu:dynamic:animations:animation_dictionary": "Animations liste:", + "menu:dynamic:animations:animation_name": "Animations navn:", + "menu:dynamic:animations:animation_duration": "Animation varighed (Sekunder):", + "menu:dynamic:animations:scenario_name": "Scenarie navn", + "menu:dynamic:animations:scenario_duration": "Scenarie varighed (Sekunder):", + "menu:dynamic:animations:remove": "Fjen", + + "menu:dynamic:marker_info:stash": "Kiste", + "menu:dynamic:marker_info:stash_settings": "Kiste indstillinder", + "menu:dynamic:marker_info:armory": "Våbenskab", + "menu:dynamic:marker_info:armory_settings": "Våbenskabs indstillinger", + "menu:dynamic:marker_info:safe": "Pengeskab", + "menu:dynamic:marker_info:temporary_garage": "Garage - Midlertidige køretøjer", + "menu:dynamic:marker_info:temporary_garage_settings": "Garage indstillinger", + "menu:dynamic:marker_info:garage_buyable": "Garage - Bil Butiks garage", + "menu:dynamic:marker_info:garage_buyable_settings": "Garage indstillinger", + "menu:dynamic:marker_info:garage_owned": "Ejet Køretøjer", + "menu:dynamic:marker_info:garage_owned_settings": "Garage indstillinger", + "menu:dynamic:marker_info:boss": "Boss", + "menu:dynamic:marker_info:boss_settings": "Boss indstillinger", + "menu:dynamic:marker_info:wardrobe": "Garderobe - Spiller gemte outfits", + "menu:dynamic:marker_info:job_outfit": "Job outfits", + "menu:dynamic:marker_info:job_outfit_settings": "Outfits", + "menu:dynamic:marker_info:shop": "Butik (Køb genstande)", + "menu:dynamic:marker_info:shop_settings": "Butiks genstande", + "menu:dynamic:marker_info:market": "Marked (Sælg genstande)", + "menu:dynamic:marker_info:market_settings": "Marked genstande", + "menu:dynamic:marker_info:harvest": "Høste punkt", + "menu:dynamic:marker_info:harvest_settings": "Genstande der kan høstes", + "menu:dynamic:marker_info:process": "Omdaningspunkr", + "menu:dynamic:marker_info:process_settings": "Omdanlige genstande", + "menu:dynamic:marker_info:crafting_table": "Arbejdsbord (craft)", + "menu:dynamic:marker_info:crafting_table_settings": "Crafting opskrifte", + "menu:dynamic:marker_info:teleport": "Teleporterings punkter", + "menu:dynamic:marker_info:teleport_settings": "Teleporterings indstillinger", + "menu:dynamic:marker_info:weapon_upgrader": "Våben reparering/upgrader", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Komponenter/Farve priser", + "menu:dynamic:marker_info:duty": "Af/på job", + "menu:dynamic:marker_info:job_shop": "Job butik", + "menu:dynamic:marker_info:job_shop_settings": "Butik - indstillinger", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Tid at lave (sekunder)", + "menu:dynamic:marker:crafting_table:result_item": "Modtagende genstand", + "menu:dynamic:marker:crafting_table:quantity": "Mængde", + "menu:dynamic:marker:crafting_table:item_id": "Item ID", + "menu:dynamic:marker:crafting_table:item_quantity": "Genstands mængde", + "menu:dynamic:marker:crafting_table:lose_on_use": "Fjern ved brug", + "menu:dynamic:marker:crafting_table:remove": "Fjern", + "menu:dynamic:marker:crafting_table:animations": "Animationer", + "menu:dynamic:marker:crafting_table:add_to_craft": "Tilføj til crafing", + "menu:dynamic:marker:crafting_table:remove_craft": "Fjern craft", + + "menu:dynamic:marker:temporary_garage:delete": "Slet", + "menu:dynamic:marker:temporary_garage:random_plate": "Tilfældig nummerplade", + + "menu:datatable:lengthMenu": "Vis _MENU_ resultater", + "menu:datatable:zeroRecords": "Ingen resultater", + "menu:datatable:info": "Vise _PAGE_ af _PAGES_", + "menu:datatable:infoEmpty": "Ingen resultater", + "menu:datatable:infoFiltered": "(Fitreret fra _MAX_ resultater)", + "menu:datatable:search": "Søg:", + "menu:datatable:next": "Næste", + "menu:datatable:previous": "Forrige", + + "menu:chart:players_in_rank": "Spiller i stilling", + + "menu:settings:player_menu_position": "Spiller menu postion", + "menu:settings:player_menu_position:bottom_right": "Bund højre", + "menu:settings:player_menu_position:top_right": "Top højre", + "menu:settings:player_menu_position:right": "Højre", + "menu:settings:player_menu_position:bottom_left": "Bund venstre", + "menu:settings:player_menu_position:top_left": "Top venstre", + "menu:settings:player_menu_position:left": "Venstre", + "menu:settings:max_distance_marker": "Maks distance maker kan blive set fra", + "menu:settings:use3Dtext": "Brug 3D tekst istedet for markers", + "menu:settings:text_size": "Tekst størrelse", + "menu:settings:font_to_use": "Skrifttype", + "menu:settings:seconds_to_lockpick_car": "Sekunder for at dirke lås op", + "menu:settings:vehicle_alarm": "Aktiver bilalarm når den dirkes?", + "menu:settings:jsfour_idcard": "Brug jsfour-idcard script (Hvis du har det) For at vise ID kort i check Identitet/køretøj lisens/våben lisens", + "menu:settings:can_use_actions_off_duty": "Kan spillere bruge f6 menuen når de ikke er på job?", + "menu:settings:car_driving_licenses_ids": "Kørekort IDs", + "menu:settings:weapon_licenses_ids": "Jagtegn IDs", + "menu:settings:new_driving_license": "Nyt kørekort", + "menu:settings:add": "Tilføj", + "menu:settings:new_weapon_license": "Nyt jagttegn", + "menu:settings:can_sell_multiple_items": "Kan sælge forskellige genstande på marked?", + "menu:settings:language": "Sprog:", + "menu:settings:allow_afk_farming": "Aktiver automatisk høstning", + "menu:settings:unemployed_job_id": "Arbejdsløs job id", + "menu:settings:unemployed_job_grade": "Arbejdsløs job stillinge", + "menu:settings:ace_permission": "ACE tilladelser", + + "menu:settings:enable_discord_logs": "Aktiver discord logs", + "menu:settings:discord_webhooks": "Discord webhooks", + "menu:settings:main_webhook": "Primær webhook", + "menu:settings:separated_webhooks": "Separate webhooks", + + "menu:settings:handcuffs_requires_item": "Håndjern skal bruge genstand", + "menu:settings:handcuffs_item_name": "Håndjern genstand navn", + "menu:settings:freeze_when_handcuffed": "Frys spiller i håndjen", + + "menu:settings:lockpick_requires_item": "Dirkning af biler skal bruge genstand", + "menu:settings:lockpick_item_name": "Lockpick item navn", + "menu:settings:lockpickRemoveOnUse": "Fjern lockpick ved brug", + + "menu:settings:robbable_accounts": "Konto plyndring", + "menu:settings:new_robbable_account": "Ny konto", + "menu:settings:canAlwaysCarryItem": "Kan altid bære genstand", + "menu:settings:accounts_depositable_in_safe": "Konto der kan indsættes i pengeskab", + "menu:settings:enable_cash_in_safes_old_esx": "Aktiver penge i pengeskab for gamle ESX version", + + "menu:settings:vehicle_reparation": "Køretøjs reparation", + "menu:settings:repair_vehicle_requires_item": "Reperaring af køretøj kræver genstand", + "menu:settings:repair_vehicle_item_name": "Fixkit item navn", + "menu:settings:lose_fixkit_on_use": "Fjern fixkit ved brug", + + "menu:settings:vehicle_cleaning": "køretøj rensning", + "menu:settings:clean_vehicle_requires_item": "Rensning af køretøj skal bruge genstand", + "menu:settings:clean_vehicle_item_name": "Sponge item navn", + "menu:settings:lose_sponge_on_use": "Fjern sponge ved brug", + + "menu:settings:healing": "Healing", + "menu:settings:healing_requires_item": "Healing skal bruge genstand", + "menu:settings:healing_item_name": "Bandage item navn", + "menu:settings:lose_bandage_on_use": "Fjern bandage ved brug", + + "menu:settings:reviving": "Genoplivning", + "menu:settings:reviving_requires_item": "Genoplivning skal bruge genstand", + "menu:settings:reviving_item_name": "Medikit item name", + "menu:settings:lose_medikit_on_use": "Fjern medikit ved brug", + + "menu:settings:enable_property_outfits": "Aktiver outfits af egendom i garderobe-marker", + + "menu:settings:apply_changes": "Gem ændringer", + "menu:settings:restore_default_config": "Gå tilbage til standard config", + "menu:are_you_sure_to_restore_settings": "Er du sikker på at du vil gå tilbage til standard configgen?", + + "menu:items_dialog:title": "Genstands liste", + "menu:items_dialog:search_item": "Søg genstand", + + "menu:weapons_dialog:title": "Våben liste", + "menu:weapons_dialog:search_weapon": "Søg våben", + + "menu:dialog:choose_item": "Vælg genstand", + "menu:dialog:choose_weapon": "Vælg våben", + + "menu:settings:actions_menu_key": "Knap for at åbne action menuen", + + "menu:settings:park_all_owned_vehicles_on_restart": "Parker alle spillerejet køretøjer ved genstart", + + "menu:account_name": "Konto navn", + "menu:accounts_dialog:title": "Konto liste", + "menu:minimum_amount": "Minimums pris", + + "menu:edit_marker:requires_minimum_account_money": "mindst penge på kontoen?" +} diff --git a/resources/[creators]/jobs_creator/html/menu_translations/de.json b/resources/[creators]/jobs_creator/html/menu_translations/de.json new file mode 100644 index 0000000..33cba62 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/de.json @@ -0,0 +1,397 @@ +{ + "menu:jobs": " Jobs", + "menu:public_markers": " Öffentliche Markierungen", + "menu:statistics": " Statistiken", + "menu:settings": " Einstellungen", + + "menu:create_new_job": "Job erstellen", + + "menu:job_label": "Job Kategorie", + "menu:job_id": "Job ID", + "menu:ranks": "Ränge", + + "menu:create_new_marker": "Neuer Aktionspunkt", + + "menu:marker:id": "ID", + "menu:marker:label": "Titel", + "menu:marker:type": "Marker ID", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Minimaler Rang", + + "menu:online_players": "Spieler Online", + "menu:total_players": "Alle Spieler", + "menu:society_money": "Gesellschafts Geld", + + "menu:job:ranks": " Ränge", + "menu:job:markers": " Aktionspunkte", + "menu:job:statistics": " Statistiken", + "menu:job:settings": " Einstelungen", + + "menu:create_new_rank": "Neuer Rang", + + "menu:rank:id": "ID", + "menu:rank:label": "Anzeigename", + "menu:rank:name": "Name", + "menu:rank:grade": "Stufe", + "menu:rank:salary": "Gehalt", + + "menu:job_settings:whitelisted": "Whitelisted", + "menu:job_settings:enable_billing": "Rechnungsmenü", + "menu:job_settings:enable_search_players": "Durchsuchen", + "menu:job_settings:enable_handcuff_players": "Fesseln", + "menu:job_settings:enable_lockpick_players": "Fahrzeuge aufbrechen", + "menu:job_settings:enable_wash_vehicles": "Fahrzeuge waschen", + "menu:job_settings:enable_repair_vehicles": "Fahrzeuge reparieren", + "menu:job_settings:enable_impound_vehicles": "Fahrzeuge abschleppen", + "menu:job_settings:enable_check_identities": "Identitäten abrufen", + "menu:job_settings:enable_check_vehicle_owner": "Fahrzeugbesitzer identifizieren", + "menu:job_settings:enable_check_driving_license": "Fahrlizenz abrufen", + "menu:job_settings:enable_check_weapon_license": "Waffenlizenz abrufen", + "menu:job_settings:enable_heal": "Heilen", + "menu:job_settings:enable_revive": "Wiederbeleben", + + "menu:job_settings:delete_job": "Job löschen", + "menu:job_settings:save_changes": "Anwenden", + + "menu:rank_creation:create_rank": "Neuer Rang", + "menu:rank_creation:label": "Anzeigename", + "menu:rank_creation:name": "Name (ID)", + "menu:rank_creation:grade": "Stufe", + "menu:rank_creation:salary": "Gehalt", + "menu:rank_creation:close": "Schließen", + "menu:rank_creation:create": "Erstellen", + + "menu:rank_edit:edit": "Rang editieren", + "menu:rank_edit:label": "Anzeigename", + "menu:rank_edit:name_id": "Name (ID)", + "menu:rank_edit:grade": "Stufe", + "menu:rank_edit:salary": "Gehalt", + "menu:rank_edit:delete": "Löschen", + "menu:rank_edit:close": "Schließen", + "menu:rank_edit:save": "Speichern", + + "menu:delete_dialog:delete": "Löschen", + "menu:delete_dialog:close": "Schließen", + + "menu:edit_marker:edit_marker": "Aktionspunkt bearbeiten", + "menu:edit_marker:label": "Kategorie", + "menu:edit_marker:marker_type": "Marker-Typ", + "menu:edit_marker:minimum_grade": "Minimale Stufe", + "menu:edit_marker:specific_grades": "Spezifische Stufe", + "menu:edit_marker:choose_grades": "Wähle Stufe", + "menu:edit_marker:use_minimum_grade": "Minimale Stufe", + "menu:edit_marker:use_specific_grades": "Spezifische Stufe ", + "menu:edit_marker:marker_size": "Aktions Bereich", + "menu:edit_marker:scale_x": "Scale X", + "menu:edit_marker:scale_y": "Scale Y", + "menu:edit_marker:scale_z": "Scale Z", + "menu:edit_marker:marker_coordinates": "Aktions Koordinaten", + "menu:edit_marker:coord_x": "Coord X", + "menu:edit_marker:coord_y": "Coord Y", + "menu:edit_marker:coord_z": "Coord Z", + "menu:edit_marker:current_coords": "Aktuelle Koordinaten", + "menu:edit_marker:marker_color": "Aktions Farbe", + "menu:edit_marker:marker_opacity": "Deckkraft", + "menu:edit_marker:map_blip": "Karten Blip", + "menu:edit_marker:blip_sprite": "Blip ID", + "menu:edit_marker:blip_color": "Farbe", + "menu:edit_marker:blip_scale": "Größe", + "menu:edit_marker:standing_npc": "Stehender NPC", + "menu:edit_marker:npc_model": "Model", + "menu:edit_marker:npc_heading": "Richtung", + "menu:edit_marker:object": "Objekt", + "menu:edit_marker:object_model": "Model", + "menu:edit_marker:object_rotation_pitch": "x", + "menu:edit_marker:object_rotation_roll": "y", + "menu:edit_marker:object_rotation_yaw": "z", + + "menu:grades_dialog:title": "Job Stufen", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Fahrzeug ausparkpunkt", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Erscheinungsrichtung", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Aktuelle Koordinaten und Richtung", + "menu:edit_marker:temporary_garage:vehicle_model": "Fahrzeug Model", + "menu:edit_marker:temporary_garage:vehicle_name": "Fahrzeug Name", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Primär Farbe", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Zweit Farbe", + "menu:edit_marker:temporary_garage:vehicle_plate": "Nummernschild", + "menu:edit_marker:temporary_garage:delete": "Löschen", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Neues Auto Model", + "menu:edit_marker:temporary_garage:cant_be_empty": "Kann nicht leer sein", + "menu:edit_marker:temporary_garage:add_vehicle": "Fahrzeug hinzufügen", + + "menu:edit_marker:boss:can_wash_money": "Geldwäsche?", + "menu:edit_marker:boss:return_percentage_after_wash": "Rückgabequote in %", + "menu:edit_marker:boss:add_money_to_society_account": "Gemeinschaftsgeld einzahlen", + "menu:edit_marker:boss:can_withdraw_money": "Gemeinschaftsgeld abheben?", + "menu:edit_marker:boss:can_deposit_money": "Gemeinschaftsgeld einzahlen?", + "menu:edit_marker:boss:can_manage_employees": "Mitarbeiter - Verwaltung?", + "menu:edit_marker:boss:can_manage_wages": "Rang | Gehalt - Verwaltung?", + + "menu:edit_marker:shop:add_to_shop": "Zum Laden hinzufügen", + "menu:edit_marker:shop:item_id": "Gegenstand ID", + "menu:edit_marker:shop:item_price": "Preis", + "menu:edit_marker:shop:black_money": "Schwarzgeld?", + "menu:edit_marker:shop:remove_item": "Gegenstand entfernen", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Fahrzeug ausparkpunkt", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Erscheinungsrichtung", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Aktuelle Koordinaten und Richtung", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Neues Fahrzeug Model", + "menu:edit_marker:garage_buyable:add_vehicle": "Füge Fahrzeug hinzu", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Fahrzeug ausparkpunkt", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Erscheinugsrichtung", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Aktuelle Koordinaten und Richtung", + + "menu:edit_marker:crafting_table:create_new_craft": "Neues Handwerk", + + "menu:edit_marker:armory:is_armory_shared": "Gemeinsame nutzung?", + "menu:edit_marker:armory:max_ammo_when_take": "Maximale Munition beim herausnehmen", + "menu:edit_marker:armory:delete_armory_content": "Inhalt der Waffenkammer löschen", + + "menu:edit_marker:stash:delete_stash_content": "Inhalt des Lagers löschen", + + "menu:edit_marker:job_outfit:create_new_outfit": "Erstelle ein neues Outfit", + + "menu:edit_marker:teleport:teleport_to": "Teleportiere zu", + "menu:edit_marker:teleport:current_coords": "Aktuelle Koordinaten", + + "menu:edit_marker:market:item_id": "Gegenstands ID", + "menu:edit_marker:market:item_min_price": "Minimaler Preis", + "menu:edit_marker:market:item_max_price": "Maximaler Preis", + "menu:edit_marker:market:black_money": "Schwarzgeld?", + "menu:edit_marker:market:time_to_sell": "Verkaufszeit", + "menu:edit_marker:market:remove": "Entfernen", + "menu:edit_marker:market:add_item": "Gegenstand hinzufügen", + + "menu:edit_marker:harvest:requires_a_tool": "Benötigt ein Werkzeug?", + "menu:edit_marker:harvest:tool_to_harvest": "Werkzeug zum sammeln", + "menu:edit_marker:harvest:lose_on_use": "Verlieren bei nutzung?", + "menu:edit_marker:harvest:quantity_to_lose": "Anzahl zu verlieren", + "menu:edit_marker:harvest:probability_to_lose": "Wahrscheinlichkeit zu verlieren", + "menu:edit_marker:harvest:disappear_after_use": "Verschwinden nach Gebrauch", + "menu:edit_marker:harvest:disappear_seconds": "Wieviele Sekunden?", + "menu:edit_marker:harvest:animations": "Animationen", + "menu:edit_marker:harvest:add_item": "Gegenstand hinzufügen", + + "menu:edit_marker:process:remove_item": "Entferne Gegenstand", + "menu:edit_marker:process:give_item": "Gebe Gegenstand", + "menu:edit_marker:process:time_to_process": "Herstellungszeit", + "menu:edit_marker:process:animations": "Animationen", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Erweitertes Magazin", + "menu:edit_marker:weapon_upgrader:drum_clip": "Trommelmagazin", + "menu:edit_marker:weapon_upgrader:flashlight": "Taschenlampe", + "menu:edit_marker:weapon_upgrader:suppressor": "Schalldämpfer", + "menu:edit_marker:weapon_upgrader:scope": "Zielvisier", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Verbessertes Zielvisier", + "menu:edit_marker:weapon_upgrader:grip": "Griff", + "menu:edit_marker:weapon_upgrader:box_clip": "Box Clip", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Luxuriöse Ausführung", + "menu:edit_marker:weapon_upgrader:default_tint": "Standart Farbe", + "menu:edit_marker:weapon_upgrader:green_tint": "Green farbe", + "menu:edit_marker:weapon_upgrader:gold_tint": "Gold farbe", + "menu:edit_marker:weapon_upgrader:pink_tint": "Pinke farbe", + "menu:edit_marker:weapon_upgrader:army_tint": "Army farbe", + "menu:edit_marker:weapon_upgrader:lspd_tint": "LSPD farbe", + "menu:edit_marker:weapon_upgrader:orange_tint": "Orange farbe", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platinum farbe", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Zugelassener Job", + "menu:edit_marker:job_shop:allowed_job": "Erlaubt Job zu verkaufen", + "menu:edit_marker:job_shop:minimum_grade": "Minimaler Rang um zu verkaufen", + + "menu:edit_marker:delete_marker": "Lösche Markierung", + "menu:edit_marker:close": "Schließen", + "menu:edit_marker:save": "Speichern", + + "menu:input_text:close": "Schließen", + "menu:input_text:confirm": "Bestätigen", + + "menu:notification:notification": "Benachrichtigung", + "menu:notification:close": "Schließen", + + "menu:not_allowed:you_are_not_allowed": "Du bist nicht dazu berechtigt dieses Menü zu benutzen!", + "menu:not_allowed:if_you_are_admin": "Wenn Sie ein Server-Administrator sind, müssen Sie die ACE-Berechtigung zu Ihrer server.cfg hinzufügen", + + "menu:animations:animations": "Animationen", + "menu:animations:add_animation": "Füge Animation hinzu", + "menu:animations:close": "Schließen", + "menu:animations:save": "Speichern", + + "menu:dynamic:create_new_job": "Neuer Job", + "menu:dynamic:new_job_label": "Neuer Name:", + "menu:dynamic:new_job_name": "Neuer Job Name (ID):", + + "menu:dynamic:delete_job_confirm": "Bist du dir sicher, dass du den Job löschen möchtest?", + + "menu:dynamic:job_markers:create_marker": "Neue Markierung", + "menu:dynamic:job_markers:label": "Name", + "menu:dynamic:job_markers:coord_x": "Coord X", + "menu:dynamic:job_markers:coord_y": "Coord Y", + "menu:dynamic:job_markers:coord_z": "Coord Z", + "menu:dynamic:job_markers:current_coords": "Aktuelle Koordinaten", + "menu:dynamic:job_markers:min_grade": "Stufe", + + "menu:dynamic:public_markers:create_public_marker": "Erstelle eine öffentliche Markierung", + "menu:dynamic:public_markers:label": "Name", + "menu:dynamic:public_markers:coord_x": "Coord X", + "menu:dynamic:public_markers:coord_y": "Coord Y", + "menu:dynamic:public_markers:coord_z": "Coord Z", + "menu:dynamic:public_markers:current_coords": "Aktuelle Koordinaten", + + "menu:dynamic:harvest:name": "Name (ID)", + "menu:dynamic:harvest:min_quantity": "Mindestanzahl", + "menu:dynamic:harvest:max_quantity": "Maximalanzahl", + "menu:dynamic:harvest:time_to_harvest": "Erntedauer (Sec)", + "menu:dynamic:harvest:probabilty": "Ernte - Warscheinlichkeit", + + "menu:dynamic:default": "Standart", + + "menu:dynamic:animations:animation_dictionary": "Liste der Animationen:", + "menu:dynamic:animations:animation_name": "Animations name:", + "menu:dynamic:animations:animation_duration": "Animations länge (Sec):", + "menu:dynamic:animations:scenario_name": "Name des Szenarios", + "menu:dynamic:animations:scenario_duration": "Szenario dauer (Sec):", + "menu:dynamic:animations:remove": "Entferne", + + "menu:dynamic:marker_info:stash": "Lager", + "menu:dynamic:marker_info:stash_settings": "Lager Einstellungen", + "menu:dynamic:marker_info:armory": "Waffenkammer", + "menu:dynamic:marker_info:armory_settings": "Waffenkammer Einstellungen", + "menu:dynamic:marker_info:safe": "Tresor", + "menu:dynamic:marker_info:temporary_garage": "Garage - Temporäre Fahrzeuge", + "menu:dynamic:marker_info:temporary_garage_settings": "Garage - Einstellungen", + "menu:dynamic:marker_info:garage_buyable": "Garage - Kaufbare Fahrzeuge", + "menu:dynamic:marker_info:garage_buyable_settings": "Garage - Einstellungen", + "menu:dynamic:marker_info:garage_owned": "Autos im Besitz", + "menu:dynamic:marker_info:garage_owned_settings": "Garage - Einstellungen", + "menu:dynamic:marker_info:boss": "Boss", + "menu:dynamic:marker_info:boss_settings": "Boss - Einstellungen", + "menu:dynamic:marker_info:wardrobe": "Garderobe - Gespeicherte Outfits vom Spieler", + "menu:dynamic:marker_info:job_outfit": "Job Outfit", + "menu:dynamic:marker_info:job_outfit_settings": "Outfits", + "menu:dynamic:marker_info:shop": "Geschäft (kaufbare Gegenstände)", + "menu:dynamic:marker_info:shop_settings": "Geschäft Gegenstände", + "menu:dynamic:marker_info:market": "Markt (verkaufe Gegenstände)", + "menu:dynamic:marker_info:market_settings": "Markt Gegenstände", + "menu:dynamic:marker_info:harvest": "Ernte punkt", + "menu:dynamic:marker_info:harvest_settings": "Erntbare Gegenstände", + "menu:dynamic:marker_info:process": "Verarbeitungspunkt", + "menu:dynamic:marker_info:process_settings": "Verarbeitungs Gegenstände", + "menu:dynamic:marker_info:crafting_table": "Werkzeugtisch", + "menu:dynamic:marker_info:crafting_table_settings": "Handwerksrezepte", + "menu:dynamic:marker_info:teleport": "Teleportions Punkt", + "menu:dynamic:marker_info:teleport_settings": "Teleportions Einstellungen", + "menu:dynamic:marker_info:weapon_upgrader": "Waffen Verbesserer", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Komponenten/Farben preise", + "menu:dynamic:marker_info:duty": "An/Aus Dienst", + "menu:dynamic:marker_info:job_shop": "Job Geschäft", + "menu:dynamic:marker_info:job_shop_settings": "Geschäfts einstellungen", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Herstellungszeit (Sec)", + "menu:dynamic:marker:crafting_table:result_item": "Ergebnis", + "menu:dynamic:marker:crafting_table:quantity": "Menge", + "menu:dynamic:marker:crafting_table:item_id": "Gegenstand ID", + "menu:dynamic:marker:crafting_table:item_quantity": "Menge", + "menu:dynamic:marker:crafting_table:lose_on_use": "Verlieren beim benutzen", + "menu:dynamic:marker:crafting_table:remove": "Entferne", + "menu:dynamic:marker:crafting_table:animations": "Animationen", + "menu:dynamic:marker:crafting_table:add_to_craft": "Hinzufügen zum herstellen", + "menu:dynamic:marker:crafting_table:remove_craft": "Entferne Herstellung", + + "menu:dynamic:marker:temporary_garage:delete": "Lösche", + "menu:dynamic:marker:temporary_garage:random_plate": "Zufalls Nummernschild", + + "menu:datatable:lengthMenu": "_MENU_ Ergebnisse anzeigen", + "menu:datatable:zeroRecords": "Keine Ergebnisse", + "menu:datatable:info": "Zeige _Seiten_ von _Seiten_", + "menu:datatable:infoEmpty": "Keine ergebnisse verfügbar", + "menu:datatable:infoFiltered": "(gefiltert aus _MAX_ Ergebnissen)", + "menu:datatable:search": "Suche:", + "menu:datatable:next": "Nächste", + "menu:datatable:previous": "vorherige", + + "menu:chart:players_in_rank": "Spieler im rang", + + "menu:settings:player_menu_position": "Menü Position", + "menu:settings:player_menu_position:bottom_right": "Unten Rechts", + "menu:settings:player_menu_position:top_right": "Oben Rechts", + "menu:settings:player_menu_position:bottom_left": "Unten Links", + "menu:settings:player_menu_position:top_left": "Oben Links", + "menu:settings:max_distance_marker": "Maximale Betrachtungsdistanz", + "menu:settings:use3Dtext": "3D-Text anstelle von Markierungen verwenden", + "menu:settings:text_size": "Text Größe", + "menu:settings:font_to_use": "Zu verwendende Schriftart", + "menu:settings:seconds_to_lockpick_car": "Sekunden, um ein Auto zu knacken", + "menu:settings:vehicle_alarm": "Alarm während Fahrzeug aufbruch?", + "menu:settings:jsfour_idcard": "Verwendung von 'jsfour-idcard'?", + "menu:settings:can_use_actions_off_duty": "F6 Menü außerhalb vom Dienst nutzbar?", + "menu:settings:car_driving_licenses_ids": "Fahrzeuglizenzen IDs", + "menu:settings:weapon_licenses_ids": "Waffenlizenzen IDs", + "menu:settings:new_driving_license": "Neue Fahrzeuglizenz", + "menu:settings:add": "Hinzufügen", + "menu:settings:new_weapon_license": "Neue Waffenlizenz", + "menu:settings:can_sell_multiple_items": "Mehrere Items gleichzeitig verkaufen?", + "menu:settings:language": "Sprache", + "menu:settings:allow_afk_farming": "Automatisches ernten am Farm-Aktionspunkt?", + "menu:settings:unemployed_job_id": "Arbeitslosen Job-ID", + "menu:settings:unemployed_job_grade": "Arbeitslosigkeitsgrad", + "menu:settings:ace_permission": "ACE-Rechte", + + "menu:settings:enable_discord_logs": "Discord-Webhooks aktivieren", + "menu:settings:discord_webhooks": "Discord-Webhooks", + "menu:settings:main_webhook": "Haupt Webhook", + "menu:settings:separated_webhooks": "Getrennte webhooks", + + "menu:settings:handcuffs_requires_item": "Fesseln erfordert Item?", + "menu:settings:handcuffs_item_name": "Handschellen Item-ID", + + "menu:settings:lockpick_requires_item": "Fahrzeug aufbrechen erfordert Item?", + "menu:settings:lockpick_item_name": "Dietrich Item-ID", + "menu:settings:lockpickRemoveOnUse": "Item nach benutzung verlieren?", + + "menu:settings:robbable_accounts": "Ausraubare Accounts", + "menu:settings:new_robbable_account": "Neuer Account", + "menu:settings:canAlwaysCarryItem": "Kein Gewicht-Bypass?", + "menu:settings:accounts_depositable_in_safe": "Im Tresor hinterlegbare Konten", + "menu:settings:enable_cash_in_safes_old_esx": "Bargeld im Tresor für alte ESX-Version aktivieren?", + + "menu:settings:vehicle_reparation": "Fahrzeug Reparatur", + "menu:settings:repair_vehicle_requires_item": "Reparatur benötigt Item?", + "menu:settings:repair_vehicle_item_name": "Reparaturkasten Item-ID", + "menu:settings:lose_fixkit_on_use": "Verliere Item beim benutzen?", + + "menu:settings:vehicle_cleaning": "Fahrzeuge waschen", + "menu:settings:clean_vehicle_requires_item": "Fahrzeug waschen benötigt Item?", + "menu:settings:clean_vehicle_item_name": "Fahrzeug Wäsche Item-ID", + "menu:settings:lose_sponge_on_use": "Verliere Item beim benutzen?", + + "menu:settings:healing": "Heilen", + "menu:settings:healing_requires_item": "Heilen benötigt Item?", + "menu:settings:healing_item_name": "Heilen Item-ID", + "menu:settings:lose_bandage_on_use": "Verliere Item beim benutzen?", + + "menu:settings:reviving": "Wiederbeleben", + "menu:settings:reviving_requires_item": "Wiederbleben benötigt Item?", + "menu:settings:reviving_item_name": "Wiederbeleben Item-ID", + "menu:settings:lose_medikit_on_use": "Verliere Item beim benutzen?", + + "menu:settings:enable_property_outfits": "Fraktions Outfits in Kleiderkammer aktivieren?", + + "menu:settings:apply_changes": "Änderungen anwenden", + "menu:settings:restore_default_config": "Standardkonfiguration wiederherstellen", + "menu:are_you_sure_to_restore_settings": "Sind Sie sicher, dass Sie die Standardeinstellungen wiederherstellen wollen?", + + "menu:items_dialog:title": "Gegenstandsliste", + "menu:items_dialog:search_item": "Suche Gegenstand", + + "menu:weapons_dialog:title": "Waffenliste", + "menu:weapons_dialog:search_weapon": "Suche Waffe", + + "menu:dialog:choose_item": "Wähle Gegendstand", + "menu:dialog:choose_weapon": "Wähle Waffe" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/el.json b/resources/[creators]/jobs_creator/html/menu_translations/el.json new file mode 100644 index 0000000..e714d52 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/el.json @@ -0,0 +1,397 @@ +{ + "menu:jobs": " Δουλειές", + "menu:public_markers": " Δημόσια Markers", + "menu:statistics": " Στατιστικά", + "menu:settings": " Ρυθμίσεις", + + "menu:create_new_job": "Δημιουργήστε νέα δουλειά", + + "menu:job_label": "Όνομα δουλειάς", + "menu:job_id": "Αναγνωριστικό δουλειάς(SetJob)", + "menu:ranks": "Βαθμοί", + + "menu:create_new_marker": "Δημιουργία νέου Μarker", + + "menu:marker:id": "ID", + "menu:marker:label": "Όνομα", + "menu:marker:type": "Τύπος Marker", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Ελάχιστος βαθμός", + + "menu:online_players": "Ενεργοί παίκτες", + "menu:total_players": "Σύνολο παικτών", + "menu:society_money": "Χρήματα Επιχείρησης", + + "menu:job:ranks": " Βαθμοί", + "menu:job:markers": " Markers", + "menu:job:statistics": " Στατιστικά", + "menu:job:settings": " Ρυθμίσεις", + + "menu:create_new_rank": "Δημιουργία νέου Βαθμού", + + "menu:rank:id": "ID", + "menu:rank:label": "Όνομα", + "menu:rank:name": "Όνομα", + "menu:rank:grade": "Βαθμός", + "menu:rank:salary": "Μισθός", + + "menu:job_settings:whitelisted": "Public/Private", + "menu:job_settings:enable_billing": "Ενεργοποίηση χρέωσης", + "menu:job_settings:enable_search_players": "Ενεργοποίηση κλοπή/ψάξιμο παικτών", + "menu:job_settings:enable_handcuff_players": "Ενεργοποίηση επιλογής για χειροπέδες", + "menu:job_settings:enable_lockpick_players": "Ενεργοποίηση κλοπής οχήματως", + "menu:job_settings:enable_wash_vehicles": "Ενεργοποίηση πλύσης οχήματως", + "menu:job_settings:enable_repair_vehicles": "Ενεργοποίηση επισκευής οχήματως", + "menu:job_settings:enable_impound_vehicles": "Ενεργοποίηση κατάσχεσης οχήματως", + "menu:job_settings:enable_check_identities": "Ενεργοποίηση ελέγχου ταυτότητας", + "menu:job_settings:enable_check_vehicle_owner": "Ενεργοποίηση ελέγχου ιδιοκτήτη οχήματος", + "menu:job_settings:enable_check_driving_license": "Ενεργοποίηση ελέγχου άδειας οδήγησης", + "menu:job_settings:enable_check_weapon_license": "Ενεργοποίηση ελέγχου άδειας όπλου", + "menu:job_settings:enable_heal": "Ενεργοποίηση Heal", + "menu:job_settings:enable_revive": "Ενεργοποίηση Revive", + + "menu:job_settings:delete_job": "Διαγραφή δουλειάς", + "menu:job_settings:save_changes": "Αποθήκευση αλλαγών", + + "menu:rank_creation:create_rank": "Δημιουργία βαθμού", + "menu:rank_creation:label": "Όνομα", + "menu:rank_creation:name": "Όνομα (ID)", + "menu:rank_creation:grade": "Βαθμός", + "menu:rank_creation:salary": "Μισθός", + "menu:rank_creation:close": "Κλείσε", + "menu:rank_creation:create": "Δημιουργία", + + "menu:rank_edit:edit": "Επεξεργασία Βαθμού", + "menu:rank_edit:label": "Όνομα", + "menu:rank_edit:name_id": "Όνομα (ID)", + "menu:rank_edit:grade": "Βαθμός", + "menu:rank_edit:salary": "Μισθός", + "menu:rank_edit:delete": "Διαγραφή", + "menu:rank_edit:close": "Κλείσε", + "menu:rank_edit:save": "Αποθηκεύση", + + "menu:delete_dialog:delete": "Διαγραφή", + "menu:delete_dialog:close": "Κλείσε", + + "menu:edit_marker:edit_marker": "Επεξεργασία Marker", + "menu:edit_marker:label": "Όνομα", + "menu:edit_marker:marker_type": "Τύπος Marker", + "menu:edit_marker:minimum_grade": "Ελάχιστος Βαθμός", + "menu:edit_marker:specific_grades": "Συγκεκριμένοι βαθμοί", + "menu:edit_marker:choose_grades": "Διάλεξε βαθμούς", + "menu:edit_marker:use_minimum_grade": "Χρήση ελάχιστου βαθμού", + "menu:edit_marker:use_specific_grades": "Χρησιμοποιήστε συγκεκριμένους βαθμούς", + "menu:edit_marker:marker_size": "Μέγεθος Marker", + "menu:edit_marker:scale_x": "Κλίμακα X", + "menu:edit_marker:scale_y": "Κλίμακα Y", + "menu:edit_marker:scale_z": "Κλίμακα Z", + "menu:edit_marker:marker_coordinates": "Συντεταγμένες Marker", + "menu:edit_marker:coord_x": "Κλίμακα X", + "menu:edit_marker:coord_y": "Κλίμακα Y", + "menu:edit_marker:coord_z": "Κλίμακα Z", + "menu:edit_marker:current_coords": "Τωρινή Τοποθεσία", + "menu:edit_marker:marker_color": "Χρώμα Marker", + "menu:edit_marker:marker_opacity": "Ορατότητα Marker", + "menu:edit_marker:map_blip": "Map blip", + "menu:edit_marker:blip_sprite": "ID", + "menu:edit_marker:blip_color": "Χρώμα", + "menu:edit_marker:blip_scale": "Κλίμακα", + "menu:edit_marker:standing_npc": "Θέση NPC", + "menu:edit_marker:npc_model": "Μοντέλο", + "menu:edit_marker:npc_heading": "Οπτική γωνία", + "menu:edit_marker:object": "Αντικείμενο", + "menu:edit_marker:object_model": "Μοντέλο", + "menu:edit_marker:object_rotation_pitch": "Κλίση", + "menu:edit_marker:object_rotation_roll": "Roll", + "menu:edit_marker:object_rotation_yaw": "Yaw", + + "menu:grades_dialog:title": "Βαθμοί εργασίας", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Σημείο Spawn οχήματος", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Κατεύθυνση Spawn Point", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Τρέχουσες συντεταγμένες και Κατεύθυνση", + "menu:edit_marker:temporary_garage:vehicle_model": "Μοντέλο οχήματος", + "menu:edit_marker:temporary_garage:vehicle_name": "Όνομα οχήματος", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Κύριο χρώμα", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Δευτερεύον χρώμα", + "menu:edit_marker:temporary_garage:vehicle_plate": "Πινακίδα", + "menu:edit_marker:temporary_garage:delete": "Διαγραφή", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Νέο μοντέλο οχήματος", + "menu:edit_marker:temporary_garage:cant_be_empty": "Δεν μπορεί να είναι άδειο", + "menu:edit_marker:temporary_garage:add_vehicle": "Προσθήκη οχήματος", + + "menu:edit_marker:boss:can_wash_money": "Μπορεί να πλύνει χρήματα?", + "menu:edit_marker:boss:return_percentage_after_wash": "Ποσοστό επιστροφής μετά το πλύσιμο", + "menu:edit_marker:boss:add_money_to_society_account": "Προσθέστε τα χρήματα στον λογαριασμό της επιχείρησης", + "menu:edit_marker:boss:can_withdraw_money": "Μπορεί να κάνει ανάληψη χρημάτων?", + "menu:edit_marker:boss:can_deposit_money": "Μπορεί να καταθέσει χρήματα?", + "menu:edit_marker:boss:can_manage_employees": "Μπορεί να διαχειριστεί υπαλλήλους?", + "menu:edit_marker:boss:can_manage_wages": "Μπορεί να διαχειριστεί μισθούς/βαθμούς?", + + "menu:edit_marker:shop:add_to_shop": "Προσθήκη στο κατάστημα", + "menu:edit_marker:shop:item_id": "Αναγνωριστικό αντικειμένου", + "menu:edit_marker:shop:item_price": "Τιμη προιοντος", + "menu:edit_marker:shop:black_money": "Μαύρα χρήματα", + "menu:edit_marker:shop:remove_item": "Αφαίρεση αντικειμένου", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Σημείο Spawn οχήματος", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Κατεύθυνση Spawn Point", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Τρέχουσες συντεταγμένες και Κατεύθυνση", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Νέο μοντέλο οχήματος", + "menu:edit_marker:garage_buyable:add_vehicle": "Προσθήκη οχήματος", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Σημείο Spawn οχήματος", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Κατεύθυνση Spawn Point", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Τρέχουσες συντεταγμένες και Κατεύθυνση", + + "menu:edit_marker:crafting_table:create_new_craft": "Δημιουργία νέου Crafting", + + "menu:edit_marker:armory:is_armory_shared": "Το οπλοστάσιο είναι κοινόχρηστο?", + "menu:edit_marker:armory:max_ammo_when_take": "Αναπλήρωση σφαιρών όταν λαμβάνεται?", + "menu:edit_marker:armory:delete_armory_content": "Διαγραφή περιεχομένου οπλοστάσιο", + + "menu:edit_marker:stash:delete_stash_content": "Διαγραφή περιεχομένου κρυφής αποθήκης", + + "menu:edit_marker:job_outfit:create_new_outfit": "Δημιούργησε νέο ντύσιμο", + + "menu:edit_marker:teleport:teleport_to": "Τηλεμεταφορά προς", + "menu:edit_marker:teleport:current_coords": "Τωρινή Τοποθεσία", + + "menu:edit_marker:market:item_id": "Αναγνωριστικό αντικειμένου", + "menu:edit_marker:market:item_min_price": "Ελάχιστη τιμή προϊόντος", + "menu:edit_marker:market:item_max_price": "Μέγιστη τιμή προϊόντος", + "menu:edit_marker:market:black_money": "Μαύρα χρήματα?", + "menu:edit_marker:market:time_to_sell": "Time to sell", + "menu:edit_marker:market:remove": "Αφαίρεση", + "menu:edit_marker:market:add_item": "Πρόσθεσε αντικέιμενο", + + "menu:edit_marker:harvest:requires_a_tool": "Απαιτεί εργαλείο?", + "menu:edit_marker:harvest:tool_to_harvest": "Εργαλείο για τη συγκομιδή", + "menu:edit_marker:harvest:lose_on_use": "Χάνεται μετά από πολλή χρήση", + "menu:edit_marker:harvest:quantity_to_lose": "Ποσότητα για να χαθεί", + "menu:edit_marker:harvest:probability_to_lose": "Πιθανότητα να χαθεί", + "menu:edit_marker:harvest:disappear_after_use": "Εξαφανίζεται μετά τη χρήση", + "menu:edit_marker:harvest:disappear_seconds": "Εξαφάνιση δευτερολέπτων", + "menu:edit_marker:harvest:animations": "Animations", + "menu:edit_marker:harvest:add_item": "Πρόσθεσε αντικέιμενο", + + "menu:edit_marker:process:remove_item": "Αφαίρεση αντικειμένου", + "menu:edit_marker:process:give_item": "Δώσε αντικείμενο", + "menu:edit_marker:process:time_to_process": "Ώρα για την επεξεργασία", + "menu:edit_marker:process:animations": "Animations", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Extended Clip", + "menu:edit_marker:weapon_upgrader:drum_clip": "Drum Clip", + "menu:edit_marker:weapon_upgrader:flashlight": "Flashlight", + "menu:edit_marker:weapon_upgrader:suppressor": "Suppressor", + "menu:edit_marker:weapon_upgrader:scope": "Scope", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Advanced Scope", + "menu:edit_marker:weapon_upgrader:grip": "Grip", + "menu:edit_marker:weapon_upgrader:box_clip": "Box Clip", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Luxary Finish", + "menu:edit_marker:weapon_upgrader:default_tint": "Default tint", + "menu:edit_marker:weapon_upgrader:green_tint": "Green tint", + "menu:edit_marker:weapon_upgrader:gold_tint": "Gold tint", + "menu:edit_marker:weapon_upgrader:pink_tint": "Pink tint", + "menu:edit_marker:weapon_upgrader:army_tint": "Army tint", + "menu:edit_marker:weapon_upgrader:lspd_tint": "LSPD tint", + "menu:edit_marker:weapon_upgrader:orange_tint": "Orange tint", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platinum tint", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Δουλειά που μπορεί να βάλει προς πώληση αντικείμενα", + "menu:edit_marker:job_shop:allowed_job": "Δουλειά που μπορεί να βάλει προς πώληση αντικείμενα", + "menu:edit_marker:job_shop:minimum_grade": "Ελάχιστος βαθμός που επιτρέπεται να βάλει προς πώληση αντικείμενα", + + "menu:edit_marker:delete_marker": "Διαγραφή Marker", + "menu:edit_marker:close": "Κλείσε", + "menu:edit_marker:save": "Αποθηκεύση", + + "menu:input_text:close": "Κλείσε", + "menu:input_text:confirm": "Επιβεβαίωση", + + "menu:notification:notification": "Ειδοποίηση", + "menu:notification:close": "Κλείσε", + + "menu:not_allowed:you_are_not_allowed": "Δεν επιτρέπεται να χρησιμοποιήσετε αυτό το μενού", + "menu:not_allowed:if_you_are_admin": "Εάν είστε διαχειριστής διακομιστή, πρέπει να προσθέσετε άδεια ACE στον server.cfg", + + "menu:animations:animations": "Animations", + "menu:animations:add_animation": "Προσθήκη Animation", + "menu:animations:close": "Κλείσε", + "menu:animations:save": "Αποθηκεύση", + + "menu:dynamic:create_new_job": "Δημιουργία νέας δουλειάς", + "menu:dynamic:new_job_label": "Όνομα νέας δουλειάς:", + "menu:dynamic:new_job_name": "Αναγνωριστικό νέας δουλειάς(SetJob):", + + "menu:dynamic:delete_job_confirm": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτή την δουλειά?", + + "menu:dynamic:job_markers:create_marker": "Δημιουργία marker", + "menu:dynamic:job_markers:label": "Όνομα", + "menu:dynamic:job_markers:coord_x": "Κλίμακα X", + "menu:dynamic:job_markers:coord_y": "Κλίμακα Y", + "menu:dynamic:job_markers:coord_z": "Κλίμακα Z", + "menu:dynamic:job_markers:current_coords": "Τωρινή Τοποθεσία", + "menu:dynamic:job_markers:min_grade": "Minimum grade", + + "menu:dynamic:public_markers:create_public_marker": "Δημιουργία δημόσιου Marker", + "menu:dynamic:public_markers:label": "Όνομα", + "menu:dynamic:public_markers:coord_x": "Κλίμακα X", + "menu:dynamic:public_markers:coord_y": "Κλίμακα Y", + "menu:dynamic:public_markers:coord_z": "Κλίμακα Z", + "menu:dynamic:public_markers:current_coords": "Τωρινή Τοποθεσία", + + "menu:dynamic:harvest:name": "Όνομα (ID)", + "menu:dynamic:harvest:min_quantity": "Ελάχιστη ποσότητα", + "menu:dynamic:harvest:max_quantity": "Μέγιστη ποσότητα", + "menu:dynamic:harvest:time_to_harvest": "Χρόνος συγκομιδής (δευτερόλεπτα)", + "menu:dynamic:harvest:probabilty": "Πιθανότητα εύρεσης", + + "menu:dynamic:default": "Default", + + "menu:dynamic:animations:animation_dictionary": "Animation dictionary:", + "menu:dynamic:animations:animation_name": "Animation name:", + "menu:dynamic:animations:animation_duration": "Animation duration (seconds):", + "menu:dynamic:animations:scenario_name": "Scenario name", + "menu:dynamic:animations:scenario_duration": "Scenario duration (seconds):", + "menu:dynamic:animations:remove": "Αφαίρεση", + + "menu:dynamic:marker_info:stash": "Αποθήκη", + "menu:dynamic:marker_info:stash_settings": "Ρυθμίσεις Αποθήκης", + "menu:dynamic:marker_info:armory": "Οπλοστάσιο", + "menu:dynamic:marker_info:armory_settings": "Ρυθμίσεις οπλοστάσιο", + "menu:dynamic:marker_info:safe": "Χρηματοκιβώτιο", + "menu:dynamic:marker_info:temporary_garage": "Γκαράζ - Προσωρινά αυτοκίνητα", + "menu:dynamic:marker_info:temporary_garage_settings": "Ρυθμίσεις γκαράζ", + "menu:dynamic:marker_info:garage_buyable": "Γκαράζ - Αγορά οχημάτων", + "menu:dynamic:marker_info:garage_buyable_settings": "Ρυθμίσεις γκαράζ", + "menu:dynamic:marker_info:garage_owned": "Ιδιόκτητα οχήματα(Owner Vehicle)", + "menu:dynamic:marker_info:garage_owned_settings": "Ρυθμίσεις γκαράζ", + "menu:dynamic:marker_info:boss": "Aφεντικό", + "menu:dynamic:marker_info:boss_settings": "Ρυθμίσεις αφεντικού", + "menu:dynamic:marker_info:wardrobe": "Ντουλάπα - Αποθηκευμένες ρούχα παικτών", + "menu:dynamic:marker_info:job_outfit": "Στολή εργασίας", + "menu:dynamic:marker_info:job_outfit_settings": "Στολές", + "menu:dynamic:marker_info:shop": "Αγορά (αγορά αντικειμένων)", + "menu:dynamic:marker_info:shop_settings": "Αγορά ειδών", + "menu:dynamic:marker_info:market": "Αγορά (πώληση αντικειμένων)", + "menu:dynamic:marker_info:market_settings": "Είδη αγοράς", + "menu:dynamic:marker_info:harvest": "Σημείο συγκομιδής(Harvest)", + "menu:dynamic:marker_info:harvest_settings": "Αντικείμενα Συγκομιδής", + "menu:dynamic:marker_info:process": "Σημείο επεξεργασίας", + "menu:dynamic:marker_info:process_settings": "Επεξεργάσιμο στοιχείο", + "menu:dynamic:marker_info:crafting_table": "Crafting Table", + "menu:dynamic:marker_info:crafting_table_settings": "Crafting recipes", + "menu:dynamic:marker_info:teleport": "Σημείο Teleport", + "menu:dynamic:marker_info:teleport_settings": "Ρυθμίσεις Teleport", + "menu:dynamic:marker_info:weapon_upgrader": "Weapon Upgrader", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Components/Tints prices", + "menu:dynamic:marker_info:duty": "On/Off Duty", + "menu:dynamic:marker_info:job_shop": "Job Shop", + "menu:dynamic:marker_info:job_shop_settings": "Shop settings", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Time to craft (seconds)", + "menu:dynamic:marker:crafting_table:result_item": "Result item", + "menu:dynamic:marker:crafting_table:quantity": "Quantity", + "menu:dynamic:marker:crafting_table:item_id": "Αναγνωριστικό αντικειμένου", + "menu:dynamic:marker:crafting_table:item_quantity": "Item quantity", + "menu:dynamic:marker:crafting_table:lose_on_use": "Lose on use", + "menu:dynamic:marker:crafting_table:remove": "Αφαίρεση", + "menu:dynamic:marker:crafting_table:animations": "Animations", + "menu:dynamic:marker:crafting_table:add_to_craft": "Add to craft", + "menu:dynamic:marker:crafting_table:remove_craft": "Remove craft", + + "menu:dynamic:marker:temporary_garage:delete": "Διαγραφή", + "menu:dynamic:marker:temporary_garage:random_plate": "Random plate", + + "menu:datatable:lengthMenu": "Προβολή _MENU_ Αποτελέσματα", + "menu:datatable:zeroRecords": "Κανένα αποτέλεσμα", + "menu:datatable:info": "Εμφάνιση _PAGE_ από _PAGES_", + "menu:datatable:infoEmpty": "Δεν υπάρχουν διαθέσιμα αποτελέσματα", + "menu:datatable:infoFiltered": "(filtred from _MAX_ Αποτελέσματα)", + "menu:datatable:search": "Αναζήτηση:", + "menu:datatable:next": "Επόμενο", + "menu:datatable:previous": "Προηγούμενο", + + "menu:chart:players_in_rank": "Παίκτες στην κατάταξη", + + "menu:settings:player_menu_position": "Player menu position", + "menu:settings:player_menu_position:bottom_right": "Bottom right", + "menu:settings:player_menu_position:top_right": "Top right", + "menu:settings:player_menu_position:bottom_left": "Bottom left", + "menu:settings:player_menu_position:top_left": "Top left", + "menu:settings:max_distance_marker": "Μέγιστη απόσταση όπου θα φαίνονται τα Marker", + "menu:settings:use3Dtext": "Χρησιμοποιήστε 3D Text αντί για Marker", + "menu:settings:text_size": "3D Text Size", + "menu:settings:font_to_use": "Γραμματοσειρά για χρήση", + "menu:settings:seconds_to_lockpick_car": "Δευτερόλεπτα για να ξεκλειδώσετε ένα αυτοκίνητο", + "menu:settings:vehicle_alarm": "Πρέπει το όχημα να έχει συναγερμό κατά το ξεκλείδωμα?", + "menu:settings:jsfour_idcard": "Αν χρησιμοποιείται το jsfour-idcard για να βλέπετε την ταυτότητα του παίκτη στον έλεγχο ταυτότητα/άδεια οχήματος/άδεια όπλου", + "menu:settings:can_use_actions_off_duty": "Μπορεί ο παίκτης να χρησιμοποιήσει το μενού ενεργειών F6 όταν είναι εκτός υπηρεσίας?", + "menu:settings:car_driving_licenses_ids": "Ταυτότητες άδειας οδήγησης αυτοκινήτου", + "menu:settings:weapon_licenses_ids": "Ταυτότητες αδειών οπλοφορίας", + "menu:settings:new_driving_license": "Νέα άδεια οδήγησης", + "menu:settings:add": "Προσθήκη", + "menu:settings:new_weapon_license": "Νέα άδεια οπλοφορίας", + "menu:settings:can_sell_multiple_items": "Μπορεί να πουλήσει πολλά αντικείμενα ταυτόχρονα στην αγορά?", + "menu:settings:language": "Γλώσσα", + "menu:settings:allow_afk_farming": "Ενεργοποίηση αυτόματου Harvest και Process δεικτών διεργασίας", + "menu:settings:unemployed_job_id": "Δουλειά άνεργου ID", + "menu:settings:unemployed_job_grade": "Δουλειά άνεργου grade", + "menu:settings:ace_permission": "ACE permission", + + "menu:settings:enable_discord_logs": "Ενεργοποιήσετε τα Discord Logs", + "menu:settings:discord_webhooks": "Discord webhooks", + "menu:settings:main_webhook": "Κύριο webhook", + "menu:settings:separated_webhooks": "Χωριστά webhooks", + + "menu:settings:handcuffs_requires_item": "Απαιτούμενο αντικείμενο για της χειροπέδες", + "menu:settings:handcuffs_item_name": "Όνομα αντικειμένου", + + "menu:settings:lockpick_requires_item": "Απαιτείται αντικείμενο για το ξεκλείδωμα του οχήματος", + "menu:settings:lockpick_item_name": "Όνομα αντικειμένου", + "menu:settings:lockpickRemoveOnUse": "Να χάνετε το αντικείμενο μετά το ξεκλείδωμα", + + "menu:settings:robbable_accounts": "Λογαριασμοί που μπορούν κλαπούν", + "menu:settings:new_robbable_account": "Νέος λογαριασμός", + "menu:settings:canAlwaysCarryItem": "Μπορεί να μεταφέρει πάντα αντικείμενα", + "menu:settings:accounts_depositable_in_safe": "Λογαριασμοί που κατατίθενται σε χρηματοκιβώτιο", + "menu:settings:enable_cash_in_safes_old_esx": "Ενεργοποίηση μετρητών σε χρηματοκιβώτιο για την παλιά έκδοση ESX", + + "menu:settings:vehicle_reparation": "Επισκευή οχήματος", + "menu:settings:repair_vehicle_requires_item": "Για την επισκευή οχήματος απαιτεί αντικείμενο", + "menu:settings:repair_vehicle_item_name": "Όνομα αντικειμένου", + "menu:settings:lose_fixkit_on_use": "Να χάνετε το αντικείμενο μετά την επισκευή", + + "menu:settings:vehicle_cleaning": "Καθαρισμός οχημάτων", + "menu:settings:clean_vehicle_requires_item": "Για τον καθαρισμό οχήματος απαιτεί αντικείμενο", + "menu:settings:clean_vehicle_item_name": "Όνομα αντικειμένου", + "menu:settings:lose_sponge_on_use": "Να χάνετε το αντικείμενο μετά τον καθαρισμό", + + "menu:settings:healing": "Healing", + "menu:settings:healing_requires_item": "To Heal απαιτεί αντικείμενο", + "menu:settings:healing_item_name": "Όνομα αντικειμένου", + "menu:settings:lose_bandage_on_use": "Να χάνετε το αντικείμενο μετά το Heal", + + "menu:settings:reviving": "Reviving", + "menu:settings:reviving_requires_item": "To Revive απαιτεί αντικείμενο", + "menu:settings:reviving_item_name": "Όνομα αντικειμένου", + "menu:settings:lose_medikit_on_use": "Να χάνετε το αντικείμενο μετά το Revive", + + "menu:settings:enable_property_outfits": "Ενεργοποίηση εξαρτημάτων αποθήκευσης δεδομένων ιδιοκτησίας στη ντουλάπα", + + "menu:settings:apply_changes": "Εφαρμογή αλλαγών", + "menu:settings:restore_default_config": "Επαναφορά προεπιλεγμένων ρυθμίσεων", + "menu:are_you_sure_to_restore_settings": "Είστε βέβαιοι ότι θα επαναφέρετε τις προεπιλεγμένες ρυθμίσεις?", + + "menu:items_dialog:title": "Λίστα αντικειμένων", + "menu:items_dialog:search_item": "Αναζήτηση αντικειμένου", + + "menu:weapons_dialog:title": "Λίστα όπλων", + "menu:weapons_dialog:search_weapon": "Αναζήτηση όπλου", + + "menu:dialog:choose_item": "Διαλέξτε αντικείμενο", + "menu:dialog:choose_weapon": "Διάλεξε όπλο" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/en.json b/resources/[creators]/jobs_creator/html/menu_translations/en.json new file mode 100644 index 0000000..e7a0233 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/en.json @@ -0,0 +1,547 @@ +{ + "menu:jobs": " Jobs", + "menu:public_markers": " Public markers", + "menu:statistics": " Statistics", + "menu:settings": " Settings", + + "menu:create_new_job": "Create new job", + + "menu:job_label": "Job label", + "menu:job_id": "Job ID", + "menu:ranks": "Ranks", + + "menu:create_new_marker": "Create new marker", + + "menu:marker:id": "ID", + "menu:marker:label": "Label", + "menu:marker:type": "Type", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Minimum grade", + + "menu:online_players": "Online players", + "menu:total_players": "Total players", + "menu:society_money": "Society money", + + "menu:job:ranks": " Ranks", + "menu:job:markers": " Markers", + "menu:job:statistics": " Statistics", + "menu:job:settings": " Settings", + + "menu:create_new_rank": "Create new rank", + + "menu:rank:id": "ID", + "menu:rank:label": "Label", + "menu:rank:name": "Name", + "menu:rank:grade": "Grade", + "menu:rank:salary": "Salary", + + "menu:job_settings:whitelisted": "Whitelisted", + "menu:job_settings:enable_billing": "Enable billing", + "menu:job_settings:enable_search_players": "Enable rob/search players", + "menu:job_settings:enable_handcuff_players": "Enable handcuff players", + "menu:job_settings:enable_lockpick_players": "Enable lockpick cars", + "menu:job_settings:enable_wash_vehicles": "Enable wash vehicles", + "menu:job_settings:enable_repair_vehicles": "Enable repair vehicles", + "menu:job_settings:enable_impound_vehicles": "Enable impound vehicles", + "menu:job_settings:enable_check_identities": "Enable check identities", + "menu:job_settings:enable_check_vehicle_owner": "Enable check vehicle owner", + "menu:job_settings:enable_check_driving_license": "Enable check driving license", + "menu:job_settings:enable_check_weapon_license": "Enable check weapon license", + "menu:job_settings:enable_heal": "Enable heal", + "menu:job_settings:enable_revive": "Enable revive", + + "menu:job_settings:delete_job": "Delete job", + "menu:job_settings:save_changes": "Save changes", + + "menu:rank_creation:create_rank": "Create rank", + "menu:rank_creation:label": "Label", + "menu:rank_creation:name": "Name (id)", + "menu:rank_creation:grade": "Grade", + "menu:rank_creation:salary": "Salary", + "menu:rank_creation:close": "Close", + "menu:rank_creation:create": "Create", + + "menu:rank_edit:edit": "Edit rank", + "menu:rank_edit:label": "Label", + "menu:rank_edit:name_id": "Name (id)", + "menu:rank_edit:grade": "Grade", + "menu:rank_edit:salary": "Salary", + "menu:rank_edit:delete": "Delete", + "menu:rank_edit:close": "Close", + "menu:rank_edit:save": "Save", + + "menu:delete_dialog:delete": "Delete", + "menu:delete_dialog:close": "Close", + + "menu:edit_marker:edit_marker": "Edit marker", + "menu:edit_marker:label": "Label", + "menu:edit_marker:marker_type": "Marker Type", + "menu:edit_marker:minimum_grade": "Minimum Grade", + "menu:edit_marker:specific_grades": "Specific grades", + "menu:edit_marker:choose_grades": "Choose grades", + "menu:edit_marker:use_minimum_grade": "Use minimum Grade", + "menu:edit_marker:use_specific_grades": "Use specific grades", + "menu:edit_marker:marker_size": "Marker size", + "menu:edit_marker:scale_x": "Scale X", + "menu:edit_marker:scale_y": "Scale Y", + "menu:edit_marker:scale_z": "Scale Z", + "menu:edit_marker:marker_coordinates": "Marker coordinates", + "menu:edit_marker:coord_x": "Coord X", + "menu:edit_marker:coord_y": "Coord Y", + "menu:edit_marker:coord_z": "Coord Z", + "menu:edit_marker:current_coords": "Current coords", + "menu:edit_marker:marker_color": "Marker color", + "menu:edit_marker:marker_opacity": "Marker opacity", + "menu:edit_marker:map_blip": "Map blip", + "menu:edit_marker:blip_sprite": "Sprite", + "menu:edit_marker:blip_color": "Color", + "menu:edit_marker:blip_scale": "Scale", + "menu:edit_marker:standing_npc": "Standing NPC", + "menu:edit_marker:npc_model": "Model", + "menu:edit_marker:npc_heading": "Heading", + "menu:edit_marker:object": "Object", + "menu:edit_marker:object_model": "Model", + "menu:edit_marker:object_rotation_pitch": "Pitch", + "menu:edit_marker:object_rotation_roll": "Roll", + "menu:edit_marker:object_rotation_yaw": "Yaw", + + "menu:grades_dialog:title": "Job grades", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Vehicle Spawnpoint", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Spawnpoint heading", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Current coords and heading", + "menu:edit_marker:temporary_garage:vehicle_model": "Vehicle Model", + "menu:edit_marker:temporary_garage:vehicle_name": "Vehicle Name", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Primary Color", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Secondary Color", + "menu:edit_marker:temporary_garage:vehicle_plate": "Plate", + "menu:edit_marker:temporary_garage:delete": "Delete", + "menu:edit_marker:temporary_garage:new_vehicle_model": "New vehicle model", + "menu:edit_marker:temporary_garage:cant_be_empty": "Can't be empty", + "menu:edit_marker:temporary_garage:add_vehicle": "Add vehicle", + + "menu:edit_marker:boss:can_wash_money": "Can wash money?", + "menu:edit_marker:boss:return_percentage_after_wash": "Return percentage after wash", + "menu:edit_marker:boss:add_money_to_society_account": "Add money to society account", + "menu:edit_marker:boss:can_withdraw_money": "Can withdraw money?", + "menu:edit_marker:boss:can_deposit_money": "Can deposit money?", + "menu:edit_marker:boss:can_manage_employees": "Can manage employees?", + "menu:edit_marker:boss:can_manage_wages": "Can manage wages/grades?", + "menu:edit_marker:boss:maximum_salary": "Maximum salary", + + "menu:edit_marker:shop:add_to_shop": "Add to shop", + "menu:edit_marker:shop:item_id": "Item ID", + "menu:edit_marker:shop:item_price": "Item Price", + "menu:edit_marker:shop:black_money": "Black money", + "menu:edit_marker:shop:remove_item": "Remove item", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Vehicle Spawnpoint", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Spawnpoint heading", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Current coords and heading", + "menu:edit_marker:garage_buyable:new_vehicle_model": "New vehicle model", + "menu:edit_marker:garage_buyable:add_vehicle": "Add vehicle", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Vehicle Spawnpoint", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Spawnpoint heading", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Current coords and heading", + + "menu:edit_marker:crafting_table:create_new_craft": "Create new craft", + + "menu:edit_marker:armory:is_armory_shared": "Is armory shared?", + "menu:edit_marker:armory:max_ammo_when_take": "Max ammo when take?", + "menu:edit_marker:armory:delete_armory_content": "Delete armory content", + + "menu:edit_marker:stash:delete_stash_content": "Delete stash content", + + "menu:edit_marker:job_outfit:create_new_outfit": "Create new outfit", + + "menu:edit_marker:teleport:teleport_to": "Teleport to", + "menu:edit_marker:teleport:current_coords": "Current coords", + + "menu:edit_marker:market:item_id": "Item ID", + "menu:edit_marker:market:item_min_price": "Item minimum price", + "menu:edit_marker:market:item_max_price": "Item maximum price", + "menu:edit_marker:market:black_money": "Black money?", + "menu:edit_marker:market:time_to_sell": "Time to sell", + "menu:edit_marker:market:remove": "Remove", + "menu:edit_marker:market:add_item": "Add item", + "menu:edit_marker_market:society_percentage": "Percentage that the society will receive", + + "menu:edit_marker:harvest:requires_a_tool": "Requires a tool?", + "menu:edit_marker:harvest:tool_to_harvest": "Tool to harvest", + "menu:edit_marker:harvest:lose_on_use": "Lose on use", + "menu:edit_marker:harvest:quantity_to_lose": "Quantity to lose", + "menu:edit_marker:harvest:probability_to_lose": "Probability to lose", + "menu:edit_marker:harvest:disappear_after_use": "Disappear after use", + "menu:edit_marker:harvest:disappear_seconds": "Disappear seconds", + "menu:edit_marker:harvest:animations": "Animations", + "menu:edit_marker:harvest:add_item": "Add item", + + "menu:edit_marker:process:remove_item": "Remove item", + "menu:edit_marker:process:give_item": "Give item", + "menu:edit_marker:process:time_to_process": "Time to process", + "menu:edit_marker:process:animations": "Animations", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Extended Clip", + "menu:edit_marker:weapon_upgrader:drum_clip": "Drum Clip", + "menu:edit_marker:weapon_upgrader:flashlight": "Flashlight", + "menu:edit_marker:weapon_upgrader:suppressor": "Suppressor", + "menu:edit_marker:weapon_upgrader:scope": "Scope", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Advanced Scope", + "menu:edit_marker:weapon_upgrader:grip": "Grip", + "menu:edit_marker:weapon_upgrader:box_clip": "Box Clip", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Luxary Finish", + "menu:edit_marker:weapon_upgrader:default_tint": "Default tint", + "menu:edit_marker:weapon_upgrader:green_tint": "Green tint", + "menu:edit_marker:weapon_upgrader:gold_tint": "Gold tint", + "menu:edit_marker:weapon_upgrader:pink_tint": "Pink tint", + "menu:edit_marker:weapon_upgrader:army_tint": "Army tint", + "menu:edit_marker:weapon_upgrader:lspd_tint": "LSPD tint", + "menu:edit_marker:weapon_upgrader:orange_tint": "Orange tint", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platinum tint", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Job that can put on sale items", + "menu:edit_marker:job_shop:allowed_job": "Allowed job to sell", + "menu:edit_marker:job_shop:minimum_grade": "Minimum grade allowed to sell", + + "menu:edit_marker:delete_marker": "Delete marker", + "menu:edit_marker:close": "Close", + "menu:edit_marker:save": "Save", + + "menu:input_text:close": "Close", + "menu:input_text:confirm": "Confirm", + + "menu:notification:notification": "Notification", + "menu:notification:close": "Close", + + "menu:not_allowed:you_are_not_allowed": "You are not allowed to use this menu", + "menu:not_allowed:if_you_are_admin": "If you are a server admin, you need to add ACE permission to your server.cfg", + + "menu:animations:animations": "Animations", + "menu:animations:add_animation": "Add animation", + "menu:animations:close": "Close", + "menu:animations:save": "Save", + + "menu:dynamic:create_new_job": "Create new job", + "menu:dynamic:new_job_label": "New job label:", + "menu:dynamic:new_job_name": "New job name (id):", + + "menu:dynamic:delete_job_confirm": "Are you sure you want to delete this job?", + + "menu:dynamic:job_markers:create_marker": "Create marker", + "menu:dynamic:job_markers:label": "Label", + "menu:dynamic:job_markers:coord_x": "Coord X", + "menu:dynamic:job_markers:coord_y": "Coord Y", + "menu:dynamic:job_markers:coord_z": "Coord Z", + "menu:dynamic:job_markers:current_coords": "Current coords", + "menu:dynamic:job_markers:min_grade": "Minimum grade", + + "menu:dynamic:public_markers:create_public_marker": "Create public marker", + "menu:dynamic:public_markers:label": "Label", + "menu:dynamic:public_markers:coord_x": "Coord X", + "menu:dynamic:public_markers:coord_y": "Coord Y", + "menu:dynamic:public_markers:coord_z": "Coord Z", + "menu:dynamic:public_markers:current_coords": "Current coords", + + "menu:dynamic:harvest:name": "Name (ID)", + "menu:dynamic:harvest:min_quantity": "Minimum quantity", + "menu:dynamic:harvest:max_quantity": "Maximum quantity", + "menu:dynamic:harvest:time_to_harvest": "Time to harvest (seconds)", + "menu:dynamic:harvest:probabilty": "Probability to find", + + "menu:dynamic:default": "Default", + + "menu:dynamic:animations:animation_dictionary": "Animation dictionary:", + "menu:dynamic:animations:animation_name": "Animation name:", + "menu:dynamic:animations:animation_duration": "Animation duration (seconds):", + "menu:dynamic:animations:scenario_name": "Scenario name", + "menu:dynamic:animations:scenario_duration": "Scenario duration (seconds):", + "menu:dynamic:animations:remove": "Remove", + + "menu:dynamic:marker_info:stash": "Stash", + "menu:dynamic:marker_info:stash_settings": "Stash settings", + "menu:dynamic:marker_info:armory": "Armory", + "menu:dynamic:marker_info:armory_settings": "Armory settings", + "menu:dynamic:marker_info:safe": "Safe", + "menu:dynamic:marker_info:temporary_garage": "Garage - Temporary vehicles", + "menu:dynamic:marker_info:temporary_garage_settings": "Garage settings", + "menu:dynamic:marker_info:garage_buyable": "Garage - Buyable vehicles", + "menu:dynamic:marker_info:garage_buyable_settings": "Garage settings", + "menu:dynamic:marker_info:garage_owned": "Owned vehicles", + "menu:dynamic:marker_info:garage_owned_settings": "Garage settings", + "menu:dynamic:marker_info:boss": "Boss", + "menu:dynamic:marker_info:boss_settings": "Boss settings", + "menu:dynamic:marker_info:wardrobe": "Wardrobe - Player saved outfits", + "menu:dynamic:marker_info:job_outfit": "Job Outfit", + "menu:dynamic:marker_info:job_outfit_settings": "Outfits", + "menu:dynamic:marker_info:shop": "Shop (buy items)", + "menu:dynamic:marker_info:shop_settings": "Shop items", + "menu:dynamic:marker_info:market": "Market (sell items)", + "menu:dynamic:marker_info:market_settings": "Market items", + "menu:dynamic:marker_info:harvest": "Harvest point", + "menu:dynamic:marker_info:harvest_settings": "Harvestable items", + "menu:dynamic:marker_info:process": "Process point", + "menu:dynamic:marker_info:process_settings": "Processable item", + "menu:dynamic:marker_info:crafting_table": "Crafting Table", + "menu:dynamic:marker_info:crafting_table_settings": "Crafting recipes", + "menu:dynamic:marker_info:teleport": "Teleport point", + "menu:dynamic:marker_info:teleport_settings": "Teleport settings", + "menu:dynamic:marker_info:weapon_upgrader": "Weapon Upgrader", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Components/Tints prices", + "menu:dynamic:marker_info:duty": "On/Off Duty", + "menu:dynamic:marker_info:job_shop": "Job Shop", + "menu:dynamic:marker_info:job_shop_settings": "Shop settings", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Time to craft (seconds)", + "menu:dynamic:marker:crafting_table:result_item": "Result item", + "menu:dynamic:marker:crafting_table:quantity": "Quantity", + "menu:dynamic:marker:crafting_table:item_id": "Item ID", + "menu:dynamic:marker:crafting_table:item_quantity": "Item quantity", + "menu:dynamic:marker:crafting_table:lose_on_use": "Lose on use", + "menu:dynamic:marker:crafting_table:remove": "Remove", + "menu:dynamic:marker:crafting_table:animations": "Animations", + "menu:dynamic:marker:crafting_table:add_to_craft": "Add to craft", + "menu:dynamic:marker:crafting_table:remove_craft": "Remove craft", + + "menu:dynamic:marker:temporary_garage:delete": "Delete", + "menu:dynamic:marker:temporary_garage:random_plate": "Random plate", + + "menu:datatable:lengthMenu": "Show _MENU_ results", + "menu:datatable:zeroRecords": "No results", + "menu:datatable:info": "Showing _PAGE_ of _PAGES_", + "menu:datatable:infoEmpty": "No results available", + "menu:datatable:infoFiltered": "(filtred from _MAX_ results)", + "menu:datatable:search": "Search:", + "menu:datatable:next": "Next", + "menu:datatable:previous": "Previous", + + "menu:chart:players_in_rank": "Players in rank", + + "menu:settings:player_menu_position": "Player menu position", + "menu:settings:player_menu_position:bottom_right": "Bottom right", + "menu:settings:player_menu_position:top_right": "Top right", + "menu:settings:player_menu_position:right": "Right", + "menu:settings:player_menu_position:bottom_left": "Bottom left", + "menu:settings:player_menu_position:top_left": "Top left", + "menu:settings:player_menu_position:left": "Left", + "menu:settings:max_distance_marker": "Max distance where marker can be seen", + "menu:settings:use3Dtext": "Use 3D text instead of markers", + "menu:settings:text_size": "Text size", + "menu:settings:font_to_use": "Font to use", + "menu:settings:seconds_to_lockpick_car": "Seconds to lockpick a car", + "menu:settings:vehicle_alarm": "Should the vehicle have alarm while lockpicking?", + "menu:settings:jsfour_idcard": "Use jsfour-idcard script (if you have it) to view target ID card in check identity/vehicle license/weapon license action", + "menu:settings:can_use_actions_off_duty": "Can the player use the F6 actions menu when it's off duty?", + "menu:settings:car_driving_licenses_ids": "Car driving licenses IDs", + "menu:settings:weapon_licenses_ids": "Weapon licenses IDs", + "menu:settings:new_driving_license": "New driving license", + "menu:settings:add": "Add", + "menu:settings:new_weapon_license": "New weapon license", + "menu:settings:can_sell_multiple_items": "Can sell multiple items at a time in market?", + "menu:settings:language": "Language", + "menu:settings:allow_afk_farming": "Enable automatic harvest and process marker farming", + "menu:settings:unemployed_job_id": "Unemployed job ID", + "menu:settings:unemployed_job_grade": "Unemployed job grade", + "menu:settings:ace_permission": "ACE permission", + + "menu:settings:enable_discord_logs": "Enable discord logs", + "menu:settings:discord_webhooks": "Discord webhooks", + "menu:settings:main_webhook": "Main webhook", + "menu:settings:separated_webhooks": "Separated webhooks", + + "menu:settings:handcuffs": "Handcuffs", + "menu:settings:handcuffs_requires_item": "Handcuffs requires item", + "menu:settings:handcuffs_item_name": "Handcuffs item name", + + "menu:settings:lockpick_requires_item": "Lockpick vehicle requires item", + "menu:settings:lockpick_item_name": "Lockpick item name", + "menu:settings:lockpickRemoveOnUse": "Lose lockpick on use", + + "menu:settings:robbable_accounts": "Robbable accounts", + "menu:settings:new_robbable_account": "New account", + "menu:settings:canAlwaysCarryItem": "Can always carry items", + "menu:settings:accounts_depositable_in_safe": "Accounts depositable in safe", + "menu:settings:enable_cash_in_safes_old_esx": "Enable cash in safe for old ESX version", + + "menu:settings:vehicle_reparation": "Vehicle reparation", + "menu:settings:repair_vehicle_requires_item": "Repair vehicle requires item", + "menu:settings:repair_vehicle_item_name": "Fixkit item name", + "menu:settings:lose_fixkit_on_use": "Lose fixkit on use", + + "menu:settings:vehicle_cleaning": "Vehicle cleaning", + "menu:settings:clean_vehicle_requires_item": "Clean vehicle requires item", + "menu:settings:clean_vehicle_item_name": "Sponge item name", + "menu:settings:lose_sponge_on_use": "Lose sponge on use", + + "menu:settings:healing": "Healing", + "menu:settings:healing_requires_item": "Healing requires item", + "menu:settings:healing_item_name": "Bandage item name", + "menu:settings:lose_bandage_on_use": "Lose bandage on use", + + "menu:settings:reviving": "Reviving", + "menu:settings:reviving_requires_item": "Reviving requires item", + "menu:settings:reviving_item_name": "Medikit item name", + "menu:settings:lose_medikit_on_use": "Lose medikit on use", + + "menu:settings:enable_property_outfits": "Enable outfits of property datastore in wardrobe marker", + + "menu:settings:apply_changes": "Apply changes", + "menu:settings:restore_default_config": "Restore default config", + "menu:are_you_sure_to_restore_settings": "Are you sure to restore to default settings?", + + "menu:items_dialog:title": "Items list", + "menu:items_dialog:search_item": "Search item", + + "menu:weapons_dialog:title": "Weapons list", + "menu:weapons_dialog:search_weapon": "Search weapon", + + "menu:dialog:choose_item": "Choose item", + "menu:dialog:choose_weapon": "Choose weapon", + + "menu:settings:actions_menu_key": "Key to open actions menu", + + "menu:settings:park_all_owned_vehicles_on_restart": "Park all owned vehicles on restart", + + "menu:account_name": "Account name", + "menu:accounts_dialog:title": "Accounts list", + "menu:minimum_amount": "Minimum amount", + + "menu:edit_marker:requires_minimum_account_money": "Requires minimum money in account?", + + "menu:actions": "Actions", + + "menu:settings:freeze_when_soft_handcuffed": "Freeze when soft handcuffed", + "menu:settings:freeze_when_hard_handcuffed": "Freeze when hard handcuffed", + + "menu:coords": "Coords", + "menu:heading": "Heading", + "menu:add_spawnpoint": "Add spawnpoint", + "menu:spawnpoints": "Spawnpoints", + "menu:radius": "Radius", + + "menu:settings:target_must_be_handcuffed_for_search": "Target must be handcuffed for search/rob", + "menu:job_settings:can_open_actions_menu": "Can open actions menu", + + "menu:intro:welcome": "Welcome to jaksam's Jobs Creator
    I hope that you'll enjoy using this script!", + "menu:intro:next": "Next", + "menu:intro:okay": "Okay", + "menu:intro:skip": "Skip", + "menu:intro:jobs": "You can create new jobs here, they'll be seen by other scripts as normal jobs", + "menu:intro:jobs_table": "Jobs will be shown here and you can click on them for more options", + "menu:intro:public_markers": "Public markers are points that everyone will see, ignoring their job", + "menu:intro:ranks": "Be sure to create ranks for your jobs, otherwise players can't use them", + "menu:intro:job_settings": "Also, don't forget to decide what actions the job can do in the settings (handcuffs, repair, heal, etc.)", + + "menu:note": "Note", + "menu:job_outfit_warning": "Based on your outfits module configuration, you can't configure job outfits from this menu", + + "menu:are_you_sure": "Are you sure?", + "menu:do_you_want_to_delete_the_rank": "Do you want to delete the rank?", + "menu:do_you_want_to_delete_this_marker": "Do you want to delete this marker?", + "menu:do_you_want_to_delete_armory_content": "Do you want to delete this armory's content?", + "menu:do_you_want_to_delete_stash_content": "Do you want to delete this stash content?", + "menu:do_you_want_to_delete_outfit": "Do you want to delete this outfit?", + + "menu:do_you_want_to_create_it_also_for_off_duty_job": "Do you want to create it also for off duty job?", + + "menu:job_settings:placeable_objects": "Placeable objects", + "menu:add_object": "Add object", + "menu:object_model": "Object model", + "menu:limit_per_player": "Limit per player", + "menu:label": "Label", + "menu:settings:new_job": "New job", + "menu:job_settings:no_objects_to_place": "No objects to place", + + "menu:market_info": "In the script settings, you can choose whether to sell items one at a time or select the quantity to sell", + + "menu:nexus:name": "Name", + "menu:nexus:author": "Author", + "menu:nexus:rating": "Rating", + "menu:nexus:not_rated": "Not rated", + "menu:nexus:info": "Info", + "menu:nexus:votes": "Votes", + "menu:nexus:no_description": "No description", + "menu:nexus:import_job": "Import job", + "menu:nexus:share_job": "Share job", + "menu:nexus:description": "Description", + "menu:nexus:upload": "Upload", + "menu:nexus:not_available": "Not available", + "menu:nexus:upload_success": "Successful upload", + "menu:nexus:upload:include_job_markers": "Include job markers", + "menu:nexus:included_markers": "Included markers", + "menu:nexus:markers_included_with_this_job": "Markers included with this job:", + "menu:nexus:included_markers_description": "These markers will be included in the job, but you MUST configure them first!", + + "menu:close": "Close", + + "menu:jobs_dialog:title": "Choose jobs", + "menu:jobs_dialog:search_job": "Search job", + "menu:settings:new_depositable_account": "New depositable account", + + "menu:settings:targeting_script": "Targeting script", + "menu:probably_requires_script_restart": "Probably requires script restart", + "menu:none": "None", + + "menu:settings:help_notification": "Help notification", + + "menu:settings:generic": " Generic", + "menu:settings:discord": " Discord", + "menu:settings:job_actions": " Job Actions", + "menu:settings:markers": " Markers", + "menu:settings:lockpick": "Lockpick", + "menu:settings:market": "Market", + "menu:settings:farming": "Farming", + "menu:settings:garage": "Garage", + "menu:settings:wardrobe": "Wardrobe", + "menu:settings:other": "Other", + + "menu:logs_warning": "Only works when using default Jobs Creator feature, it can't log external scripts", + + "menu:missing_menu_default": "Missing menu_default script", + "menu:missing_menu_default:description": "You must install menu_default script, be sure to start it without renaming", + "menu:download": "Download", + + "menu:settings:whitelisted_controls_while_handcuffed": "Whitelisted controls while handcuffed", + "menu:settings:whitelisted_controls_while_handcuffed:description": "These controls won't be disabled while handcuffed", + "menu:control_number": "Control number", + "menu:controls_dialog:title": "Choose control", + "menu:controls_dialog:info_1": "Press the control you want to use", + "menu:controls_dialog:info_2": "Multiple actions are associated with the key you pressed. Some controls may only work under specific circumstances due to GTA 5's mechanics. If a control doesn't work, try selecting another", + "menu:controls_dialog:info_3": "Changing the key here won't update the translations. Edit them manually in the script files", + + "menu:enable_toggle_drag": "Enable toggle drag", + "menu:default_toggle_drag_key": "Default toggle drag key", + + "menu:settings:lose_handcuffs_on_use": "Lose handcuffs on use", + + "menu:choose_object": "Choose object", + + "menu:settings:black_money": "Black money", + "menu:settings:black_money:quantity": "When giving black money, will give this item with this QUANTITY as worth", + "menu:settings:black_money:metadata": "When giving black money, will give this item with this METADATA as worth", + + "menu:add_something_to_continue": "Add something to continue", + + "menu:settings:external_scripts_links": " External scripts links", + "menu:settings:external_scripts_links:description": "Replace what scripts names are used when calling exports instead of default ones", + "menu:settings:external_scripts_links:info": "Note: Replace ONLY if the other script has the same exports of the script you are replacing, otherwise keep it default", + + "menu:dialogs:resources": "Scripts list", + + "menu:settings:modules": " Modules", + + "menu:edit_marker:temporary_garage:livery": "Livery", + + "menu:intro:settings": "It's important to configure properly the script to not have issues later", + "menu:intro:settings_external_names": "Are you using a script that replaces the default exports of another script? An example is a banking script replacing qb-banking, if so you can configure it here", + "menu:intro:settings_modules": "Do you want to replace a Jobs Creator feature? You can do that here, visit documentation to learn how to create your own modules", + "menu:settings:handcuffs_enable_self_release_skillcheck": "Enable self release skillcheck", + "menu:settings:boss": "Boss menu", + "menu:settings:reset_employee_work_time": "Number of past days to include in employee work time (max 14)", + + "menu:other": "Other", + + "menu:settings:modules:description": "Do you want to replace a Jobs Creator feature? You can do that here, visit documentation to learn how to create your own modules" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/es.json b/resources/[creators]/jobs_creator/html/menu_translations/es.json new file mode 100644 index 0000000..78fe33a --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/es.json @@ -0,0 +1,398 @@ +{ + "menu:jobs": " Trabajos", + "menu:public_markers": " Marcadores públicos", + "menu:statistics": " Estadísticas", + "menu:settings": " Ajustes", + + "menu:create_new_job": "Crear nuevo trabajo", + + "menu:job_label": "Etiqueta del trabajo", + "menu:job_id": "Id del trabajo", + "menu:ranks": "Rangos", + + "menu:create_new_marker": "Crear un nuevo marcador", + + "menu:marker:id": "ID", + "menu:marker:label": "Etiqueta", + "menu:marker:type": "Tipo", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Grado mínimo", + + "menu:online_players": "Jugadores conectados", + "menu:total_players": "Jugadores en total", + "menu:society_money": "Dinero de la sociedad", + + "menu:job:ranks": " Rangos", + "menu:job:markers": " Marcadores", + "menu:job:statistics": " Estadísticas", + "menu:job:settings": " Ajustes", + + "menu:create_new_rank": "Crear nuevo rango", + + "menu:rank:id": "ID", + "menu:rank:label": "Etiqueta", + "menu:rank:name": "Normbre", + "menu:rank:grade": "Grado", + "menu:rank:salary": "Salario", + + "menu:job_settings:whitelisted": "Lista blanca", + "menu:job_settings:enable_billing": "Activar multas", + "menu:job_settings:enable_search_players": "Activar robo a jugadores", + "menu:job_settings:enable_handcuff_players": "Activar esposar a jugadores", + "menu:job_settings:enable_lockpick_players": "Activar forzar vehículos", + "menu:job_settings:enable_wash_vehicles": "Activar limpiar vehículos", + "menu:job_settings:enable_repair_vehicles": "Activar reparar coches", + "menu:job_settings:enable_impound_vehicles": "Activar incautar vehículos", + "menu:job_settings:enable_check_identities": "Activar chequear identidad", + "menu:job_settings:enable_check_vehicle_owner": "Activar chequear propietario del vehículo", + "menu:job_settings:enable_check_driving_license": "Activar chequear licencia de conducir", + "menu:job_settings:enable_check_weapon_license": "Activar chequear licencia armas", + "menu:job_settings:enable_heal": "Activar curar", + "menu:job_settings:enable_revive": "Activar revivir", + + "menu:job_settings:delete_job": "Eliminar trabajo", + "menu:job_settings:save_changes": "Guardar cambios", + + "menu:rank_creation:create_rank": "Crear rango", + "menu:rank_creation:label": "Etiqueta", + "menu:rank_creation:name": "Nombre (id)", + "menu:rank_creation:grade": "Grado", + "menu:rank_creation:salary": "Salario", + "menu:rank_creation:close": "Cerrar", + "menu:rank_creation:create": "Crear", + + "menu:rank_edit:edit": "Editar el rango", + "menu:rank_edit:label": "Etiqueta", + "menu:rank_edit:name_id": "Nombre (id)", + "menu:rank_edit:grade": "Grado", + "menu:rank_edit:salary": "Salario", + "menu:rank_edit:delete": "Eliminar", + "menu:rank_edit:close": "Cerrar", + "menu:rank_edit:save": "Guardar", + + "menu:delete_dialog:delete": "Eliminar", + "menu:delete_dialog:close": "Cerrar", + + "menu:edit_marker:edit_marker": "Editar marcador", + "menu:edit_marker:label": "Etiqueta", + "menu:edit_marker:marker_type": "Tipo de marcador", + "menu:edit_marker:minimum_grade": "Grado mínimo", + "menu:edit_marker:specific_grades": "Grados especificos", + "menu:edit_marker:choose_grades": "Eligir grado", + "menu:edit_marker:use_minimum_grade": "Use grado mínimo", + "menu:edit_marker:use_specific_grades": "Usar grados específicos", + "menu:edit_marker:marker_size": "Tamaño del marcador", + "menu:edit_marker:scale_x": "Escala X", + "menu:edit_marker:scale_y": "Escala Y", + "menu:edit_marker:scale_z": "Escala Z", + "menu:edit_marker:marker_coordinates": "Coordenadas del marcador", + "menu:edit_marker:coord_x": "Coordenadas X", + "menu:edit_marker:coord_y": "Coordenadas Y", + "menu:edit_marker:coord_z": "Coordenadas Z", + "menu:edit_marker:current_coords": "Coordenadas actuales", + "menu:edit_marker:marker_color": "Color del marcador", + "menu:edit_marker:marker_opacity": "Opacidad del marcador", + "menu:edit_marker:map_blip": "Punto en el mapa", + "menu:edit_marker:blip_sprite": "Sprite", + "menu:edit_marker:blip_color": "Color", + "menu:edit_marker:blip_scale": "Escala", + "menu:edit_marker:standing_npc": "NPC permanente", + "menu:edit_marker:npc_model": "Modelo", + "menu:edit_marker:npc_heading": "Rumbo", + "menu:edit_marker:object": "Objeto", + "menu:edit_marker:object_model": "Modelo", + "menu:edit_marker:object_rotation_pitch": "Inclinar", + "menu:edit_marker:object_rotation_roll": "Rodar", + "menu:edit_marker:object_rotation_yaw": "Virar", + "menu:edit_marker:object_current_rotation": "Rotación actual", + + "menu:grades_dialog:title": "Grados del trabajo", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Spawn de coches", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Rumbo del spawn", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Coordenadas y rumbo actual", + "menu:edit_marker:temporary_garage:vehicle_model": "Modelo del vehículo", + "menu:edit_marker:temporary_garage:vehicle_name": "Nombre del vehículo", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Color primario", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Color secundario", + "menu:edit_marker:temporary_garage:vehicle_plate": "Matrícula", + "menu:edit_marker:temporary_garage:delete": "Eliminar", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Nuevo modelo del vehículo", + "menu:edit_marker:temporary_garage:cant_be_empty": "No puede estar vacio", + "menu:edit_marker:temporary_garage:add_vehicle": "Añadir vehículo", + + "menu:edit_marker:boss:can_wash_money": "Se puede lavar el dinero?", + "menu:edit_marker:boss:return_percentage_after_wash": "Porcentaje de devolución después del lavado", + "menu:edit_marker:boss:add_money_to_society_account": "Añadir dinero a la sociedad", + "menu:edit_marker:boss:can_withdraw_money": "Puede retirar el dinero?", + "menu:edit_marker:boss:can_deposit_money": "Se puede depositar dinero?", + "menu:edit_marker:boss:can_manage_employees": "Puede gestionar a los empleados?", + "menu:edit_marker:boss:can_manage_wages": "Puede manejar los salarios/ grados?", + + "menu:edit_marker:shop:add_to_shop": "Añadir a la tienda", + "menu:edit_marker:shop:item_id": "ID del artículo", + "menu:edit_marker:shop:item_price": "Precio del artículo", + "menu:edit_marker:shop:black_money": "Dinero negro", + "menu:edit_marker:shop:remove_item": "Remover artículo", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Spawn de coches", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Dirección del spawn", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Coordenadas y dirección actual", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Nuevo modelo del vehículo", + "menu:edit_marker:garage_buyable:add_vehicle": "Añadir vehículo", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Spawn de coches", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Dirección del spawn", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Coordenadas y dirección actual", + + "menu:edit_marker:crafting_table:create_new_craft": "Crear nuevos crafteos", + + "menu:edit_marker:armory:is_armory_shared": "La armería es compartida?", + "menu:edit_marker:armory:max_ammo_when_take": "Munición máxima cuando se toma?", + "menu:edit_marker:armory:delete_armory_content": "Eliminar el contenido del arsenal", + + "menu:edit_marker:stash:delete_stash_content": "Eliminar el contenido escondido", + + "menu:edit_marker:job_outfit:create_new_outfit": "Crear un nuevo equipo", + + "menu:edit_marker:teleport:teleport_to": "Teletransportarse a", + "menu:edit_marker:teleport:current_coords": "Coordenadas actuales", + + "menu:edit_marker:market:item_id": "ID del artículo", + "menu:edit_marker:market:item_min_price": "Precio mínimo del artículo", + "menu:edit_marker:market:item_max_price": "Precio maximo del artículo", + "menu:edit_marker:market:black_money": "Dinero negro?", + "menu:edit_marker:market:time_to_sell": "Tiempo para vender", + "menu:edit_marker:market:remove": "Remover", + "menu:edit_marker:market:add_item": "Añadir artículo", + + "menu:edit_marker:harvest:requires_a_tool": "Requiere de una herramienta?", + "menu:edit_marker:harvest:tool_to_harvest": "Herramienta para cosechar", + "menu:edit_marker:harvest:lose_on_use": "Perder al usar", + "menu:edit_marker:harvest:quantity_to_lose": "Cantidad que pierde", + "menu:edit_marker:harvest:probability_to_lose": "Probabilidad de perder", + "menu:edit_marker:harvest:disappear_after_use": "Desaparecer después de su uso", + "menu:edit_marker:harvest:disappear_seconds": "Segundos de desaparición", + "menu:edit_marker:harvest:animations": "Animaciones", + "menu:edit_marker:harvest:add_item": "Añadir artículo", + + "menu:edit_marker:process:remove_item": "Remover artículo", + "menu:edit_marker:process:give_item": "Dar artículo", + "menu:edit_marker:process:time_to_process": "Tiempo para procesar", + "menu:edit_marker:process:animations": "Animaciones", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Cargador ampliado", + "menu:edit_marker:weapon_upgrader:drum_clip": "Cargador de tambor", + "menu:edit_marker:weapon_upgrader:flashlight": "Linterna", + "menu:edit_marker:weapon_upgrader:suppressor": "Silenciador", + "menu:edit_marker:weapon_upgrader:scope": "Alcance", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Alcance avanzado", + "menu:edit_marker:weapon_upgrader:grip": "Empuñadura", + "menu:edit_marker:weapon_upgrader:box_clip": "Cargador grande", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Acabado de lujo", + "menu:edit_marker:weapon_upgrader:default_tint": "Tinte predeterminado", + "menu:edit_marker:weapon_upgrader:green_tint": "Tinte verde", + "menu:edit_marker:weapon_upgrader:gold_tint": "Tinte de oro", + "menu:edit_marker:weapon_upgrader:pink_tint": "Tinte rosa", + "menu:edit_marker:weapon_upgrader:army_tint": "Tinte militar", + "menu:edit_marker:weapon_upgrader:lspd_tint": "Tinte policial", + "menu:edit_marker:weapon_upgrader:orange_tint": "Tinte naranja", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Tinte de plata", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Trabajo que puede poner en venta artículos", + "menu:edit_marker:job_shop:allowed_job": "Trabajo permitido para vender", + "menu:edit_marker:job_shop:minimum_grade": "Grado mínimo permitido para vender", + + "menu:edit_marker:delete_marker": "Borrar marcador", + "menu:edit_marker:close": "Cerrar", + "menu:edit_marker:save": "Guardar", + + "menu:input_text:close": "Cerrar", + "menu:input_text:confirm": "Confirmar", + + "menu:notification:notification": "Notificación", + "menu:notification:close": "Cerrar", + + "menu:not_allowed:you_are_not_allowed": "No se le permite utilizar este menú", + "menu:not_allowed:if_you_are_admin": "Si usted es un administrador del servidor, necesita agregar permiso ACE a su server.cfg", + + "menu:animations:animations": "Animaciones", + "menu:animations:add_animation": "Añador animación", + "menu:animations:close": "Cerrar", + "menu:animations:save": "Guardar", + + "menu:dynamic:create_new_job": "Crear nuevo trabajo", + "menu:dynamic:new_job_label": "Nueva etiqueta del trabajo:", + "menu:dynamic:new_job_name": "Nuevo nombre del trabajo (id):", + + "menu:dynamic:delete_job_confirm": "Seguro que quieres borrar este trabajo?", + + "menu:dynamic:job_markers:create_marker": "Crear marcador", + "menu:dynamic:job_markers:label": "Etiqueta", + "menu:dynamic:job_markers:coord_x": "Coordenadas X", + "menu:dynamic:job_markers:coord_y": "Coordenadas Y", + "menu:dynamic:job_markers:coord_z": "Coordenadas Z", + "menu:dynamic:job_markers:current_coords": "Coordenadas actuales", + "menu:dynamic:job_markers:min_grade": "Grado mínimo", + + "menu:dynamic:public_markers:create_public_marker": "Crear un marcador publico", + "menu:dynamic:public_markers:label": "Etiqueta", + "menu:dynamic:public_markers:coord_x": "Coordenadas X", + "menu:dynamic:public_markers:coord_y": "Coordenadas Y", + "menu:dynamic:public_markers:coord_z": "Coordenadas Z", + "menu:dynamic:public_markers:current_coords": "Coordenadas actuales", + + "menu:dynamic:harvest:name": "Nombre (ID)", + "menu:dynamic:harvest:min_quantity": "Cantidad mínima", + "menu:dynamic:harvest:max_quantity": "Cantidad máxima", + "menu:dynamic:harvest:time_to_harvest": "Tiempo de cosechar (segundos)", + "menu:dynamic:harvest:probabilty": "probabilidad de encontrar", + + "menu:dynamic:default": "Predeterminado", + + "menu:dynamic:animations:animation_dictionary": "Diccionario de animación:", + "menu:dynamic:animations:animation_name": "Nombre de la animación:", + "menu:dynamic:animations:animation_duration": "Duración de la animación (segundos):", + "menu:dynamic:animations:scenario_name": "Nombre del escenario", + "menu:dynamic:animations:scenario_duration": "Duración del escenario (segundos):", + "menu:dynamic:animations:remove": "Remover", + + "menu:dynamic:marker_info:stash": "Armario", + "menu:dynamic:marker_info:stash_settings": "Ajustes del armario", + "menu:dynamic:marker_info:armory": "Armeria", + "menu:dynamic:marker_info:armory_settings": "Ajustes de la armería", + "menu:dynamic:marker_info:safe": "Armario propio", + "menu:dynamic:marker_info:temporary_garage": "Garaje temporal", + "menu:dynamic:marker_info:temporary_garage_settings": "Ajustes del garaje", + "menu:dynamic:marker_info:garage_buyable": "Garaje de coches comprables", + "menu:dynamic:marker_info:garage_buyable_settings": "Ajustes del garajes", + "menu:dynamic:marker_info:garage_owned": "vehículos propios", + "menu:dynamic:marker_info:garage_owned_settings": "Ajustes del garaje", + "menu:dynamic:marker_info:boss": "Jefe", + "menu:dynamic:marker_info:boss_settings": "Ajsutes de jefe", + "menu:dynamic:marker_info:wardrobe": "Armario propio", + "menu:dynamic:marker_info:job_outfit": "Ropa del trabajo", + "menu:dynamic:marker_info:job_outfit_settings": "Estilos", + "menu:dynamic:marker_info:shop": "Tienda (Comprar artículos)", + "menu:dynamic:marker_info:shop_settings": "Tienda de artículos", + "menu:dynamic:marker_info:market": "Venta (Vender artículos)", + "menu:dynamic:marker_info:market_settings": "Venta de artículos", + "menu:dynamic:marker_info:harvest": "Punto de cosecha", + "menu:dynamic:marker_info:harvest_settings": "Punto de cosecha", + "menu:dynamic:marker_info:process": "Punto de proceso", + "menu:dynamic:marker_info:process_settings": "Artículo procesable", + "menu:dynamic:marker_info:crafting_table": "Mesa de trabajo", + "menu:dynamic:marker_info:crafting_table_settings": "Recetas de elaboración", + "menu:dynamic:marker_info:teleport": "Punto de teletransporte", + "menu:dynamic:marker_info:teleport_settings": "Ajustes de teletransporte", + "menu:dynamic:marker_info:weapon_upgrader": "Mejorador de armas", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Precios de componentes/tintes", + "menu:dynamic:marker_info:duty": "De servicio/fuera de servicio", + "menu:dynamic:marker_info:job_shop": "Tienda del trabajo", + "menu:dynamic:marker_info:job_shop_settings": "Configuración de la tienda", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Tiempo hasta la embarcación (segundos)", + "menu:dynamic:marker:crafting_table:result_item": "Elemento de resultado", + "menu:dynamic:marker:crafting_table:quantity": "Cantidad", + "menu:dynamic:marker:crafting_table:item_id": "ID del artículo", + "menu:dynamic:marker:crafting_table:item_quantity": "Cantidad de artículos", + "menu:dynamic:marker:crafting_table:lose_on_use": "Perder en uso", + "menu:dynamic:marker:crafting_table:remove": "Remover", + "menu:dynamic:marker:crafting_table:animations": "Animaciones", + "menu:dynamic:marker:crafting_table:add_to_craft": "Añadir a la embarcación", + "menu:dynamic:marker:crafting_table:remove_craft": "Retirar la embarcación", + + "menu:dynamic:marker:temporary_garage:delete": "Eliminar", + "menu:dynamic:marker:temporary_garage:random_plate": "Matrícula aleatoria", + + "menu:datatable:lengthMenu": "Mostrar _MENU_ resultados", + "menu:datatable:zeroRecords": "No hay resultados", + "menu:datatable:info": "Mostrando _PAGE_ de _PAGES_", + "menu:datatable:infoEmpty": "No hay resultados disponibles", + "menu:datatable:infoFiltered": "(filtrado por los _MAX_ resultados)", + "menu:datatable:search": "Buscar:", + "menu:datatable:next": "Siguiente", + "menu:datatable:previous": "Anterior", + + "menu:chart:players_in_rank": "Jugadores en rango", + + "menu:settings:player_menu_position": "Posición del menú del jugador", + "menu:settings:player_menu_position:bottom_right": "Parte inferior derecha", + "menu:settings:player_menu_position:top_right": "Abajo a la derecha", + "menu:settings:player_menu_position:bottom_left": "Parte inferior izquierda", + "menu:settings:player_menu_position:top_left": "Abajo a la izquierda", + "menu:settings:max_distance_marker": "Distancia máxima donde se puede ver el marcador", + "menu:settings:use3Dtext": "Usar texto 3D en lugar de marcadores", + "menu:settings:text_size": "Tamaño del texto", + "menu:settings:font_to_use": "Tipo de letra usado", + "menu:settings:seconds_to_lockpick_car": "Segundos para desbloquear un coche", + "menu:settings:vehicle_alarm": "Debería el vehículo tener alarma mientras se abre la cerradura?", + "menu:settings:jsfour_idcard": "Use el script jsfour-idcard (si lo tiene) para ver la tarjeta de identificación de destino en la acción comprobar identidad/permiso de conducir/licencia de armas", + "menu:settings:can_use_actions_off_duty": "Puede el jugador utilizar el menú de acciones F6 cuando está fuera de servicio?", + "menu:settings:car_driving_licenses_ids": "Carnets de conducir de coche", + "menu:settings:weapon_licenses_ids": "Carnets de armas", + "menu:settings:new_driving_license": "Nuevo permiso de conducir", + "menu:settings:add": "Añadir", + "menu:settings:new_weapon_license": "Nueva licencia de armas", + "menu:settings:can_sell_multiple_items": "Puede vender varios artículos a la vez en el mercado?", + "menu:settings:language": "Idioma", + "menu:settings:allow_afk_farming": "Permitir la cosecha automática y el proceso de marcaje agrícola", + "menu:settings:unemployed_job_id": "Número de desempleados", + "menu:settings:unemployed_job_grade": "Grado de desempleo", + "menu:settings:ace_permission": "permiso ACE", + + "menu:settings:enable_discord_logs": "Activar registros de discord", + "menu:settings:discord_webhooks": "Discord webhooks", + "menu:settings:main_webhook": "Webhook principal", + "menu:settings:separated_webhooks": "Webhooks separado", + + "menu:settings:handcuffs_requires_item": "Esposar requiere artículo", + "menu:settings:handcuffs_item_name": "Nombre del artículo de las esposas", + + "menu:settings:lockpick_requires_item": "Ganzuar vehículo requiere elemento", + "menu:settings:lockpick_item_name": "Nombre del artículo ganzúa", + "menu:settings:lockpickRemoveOnUse": "Perder ganzúa tras el uso", + + "menu:settings:robbable_accounts": "Cuentas robables", + "menu:settings:new_robbable_account": "Nueva cuenta", + "menu:settings:canAlwaysCarryItem": "Siempre puede llevar artículos", + "menu:settings:accounts_depositable_in_safe": "Cuentas depositables en el armario propio", + "menu:settings:enable_cash_in_safes_old_esx": "Habilitar efectivo en el armario propio para la versión antigua de ESX", + + "menu:settings:vehicle_reparation": "Reparación de vehículos", + "menu:settings:repair_vehicle_requires_item": "Reparación de vehículos", + "menu:settings:repair_vehicle_item_name": "Nombre del artículo kit de reparacion", + "menu:settings:lose_fixkit_on_use": "Perder kit de reparacion tras su uso", + + "menu:settings:vehicle_cleaning": "Limpieza de vehículos", + "menu:settings:clean_vehicle_requires_item": "Para lavar coches necesitas una espoja", + "menu:settings:clean_vehicle_item_name": "Nombre del artículo esponja", + "menu:settings:lose_sponge_on_use": "Perder esponja tras su uso", + + "menu:settings:healing": "Curar", + "menu:settings:healing_requires_item": "Para curar necesitas una venda", + "menu:settings:healing_item_name": "Nombre del artículo venda", + "menu:settings:lose_bandage_on_use": "Perder venda cuando se use", + + "menu:settings:reviving": "Revivir", + "menu:settings:reviving_requires_item": "Para revivir necesitas un kit medico", + "menu:settings:reviving_item_name": "Nombre del artículo kit medico", + "menu:settings:lose_medikit_on_use": "Perder kit medico cuando se use", + + "menu:settings:enable_property_outfits": "Habilitar outfits propios en el marcador de armario", + + "menu:settings:apply_changes": "Aplicar cambios", + "menu:settings:restore_default_config": "Restaurar la configuración predeterminada", + "menu:are_you_sure_to_restore_settings": "Está seguro de restaurar la configuración predeterminada?", + + "menu:items_dialog:title": "Lista de artículos", + "menu:items_dialog:search_item": "Buscar artículo", + + "menu:weapons_dialog:title": "Lista de armas", + "menu:weapons_dialog:search_weapon": "Buscar arma", + + "menu:dialog:choose_item": "Elegir artículo", + "menu:dialog:choose_weapon": "Elegir arma" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/fr.json b/resources/[creators]/jobs_creator/html/menu_translations/fr.json new file mode 100644 index 0000000..2904042 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/fr.json @@ -0,0 +1,397 @@ +{ + "menu:jobs": " Emploi", + "menu:public_markers": " Marqueurs Publique", + "menu:statistics": " Statistiques", + "menu:settings": " Réglages", + + "menu:create_new_job": "Créer un nouvel emploi", + + "menu:job_label": "Libellé de l'emploi", + "menu:job_id": "ID de tâche", + "menu:ranks": "Rangs", + + "menu:create_new_marker": "Créer un nouveau marqueur", + + "menu:marker:id": "ID", + "menu:marker:label": "Étiqueter", + "menu:marker:type": "Type", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "grade Minimum", + + "menu:online_players": "Joueurs en ligne", + "menu:total_players": "Nombre total de joueurs", + "menu:society_money": "L'argent de la société", + + "menu:job:ranks": " Rangs", + "menu:job:markers": " Marqueurs", + "menu:job:statistics": " Statistiques", + "menu:job:settings": " Réglages", + + "menu:create_new_rank": "Créer un nouveau rang", + + "menu:rank:id": "ID", + "menu:rank:label": "Étiqueter", + "menu:rank:name": "Nom", + "menu:rank:grade": "Grade", + "menu:rank:salary": "Un salaire", + + "menu:job_settings:whitelisted": "Whitelisted", + "menu:job_settings:enable_billing": "Activer la facturation", + "menu:job_settings:enable_search_players": "Activer le vol/la recherche de joueurs", + "menu:job_settings:enable_handcuff_players": "Activer les joueurs menottes", + "menu:job_settings:enable_lockpick_players": "Activer les voitures de crochetage", + "menu:job_settings:enable_wash_vehicles": "Activer les véhicules de lavage", + "menu:job_settings:enable_repair_vehicles": "Activer les véhicules de réparation", + "menu:job_settings:enable_impound_vehicles": "Autoriser les véhicules en fourrière", + "menu:job_settings:enable_check_identities": "Activer la vérification des identités", + "menu:job_settings:enable_check_vehicle_owner": "Activer la vérification du propriétaire du véhicule", + "menu:job_settings:enable_check_driving_license": "Activer la vérification du permis de conduire", + "menu:job_settings:enable_check_weapon_license": "Activer la vérification de la licence d'arme", + "menu:job_settings:enable_heal": "Activer la guérison", + "menu:job_settings:enable_revive": "Activer la réanimation", + + "menu:job_settings:delete_job": "Supprimer le travail", + "menu:job_settings:save_changes": "Sauvegarder les modifications", + + "menu:rank_creation:create_rank": "Créer un classement", + "menu:rank_creation:label": "Étiqueter", + "menu:rank_creation:name": "Nom (identifiant)", + "menu:rank_creation:grade": "Grade", + "menu:rank_creation:salary": "Un salaire", + "menu:rank_creation:close": "Fermé", + "menu:rank_creation:create": "Créer", + + "menu:rank_edit:edit": "Modifier le classement", + "menu:rank_edit:label": "Étiqueter", + "menu:rank_edit:name_id": "Nom (identifiant)", + "menu:rank_edit:grade": "Grade", + "menu:rank_edit:salary": "Un salaire", + "menu:rank_edit:delete": "Effacer", + "menu:rank_edit:close": "Fermé", + "menu:rank_edit:save": "Sauvegarder", + + "menu:delete_dialog:delete": "Effacer", + "menu:delete_dialog:close": "fermé", + + "menu:edit_marker:edit_marker": "Modifier le marqueur", + "menu:edit_marker:label": "Étiqueter", + "menu:edit_marker:marker_type": "Type de marqueur", + "menu:edit_marker:minimum_grade": "Minimum Grade", + "menu:edit_marker:specific_grades": "Grades spécifiques", + "menu:edit_marker:choose_grades": "Choisissez les Grades", + "menu:edit_marker:use_minimum_grade": "Utiliser le Grades minimale", + "menu:edit_marker:use_specific_grades": "Utiliser des Grades spécifiques", + "menu:edit_marker:marker_size": "Taille du marqueur", + "menu:edit_marker:scale_x": "Scale X", + "menu:edit_marker:scale_y": "Scale Y", + "menu:edit_marker:scale_z": "Scale Z", + "menu:edit_marker:marker_coordinates": "Coordonnées du marqueur", + "menu:edit_marker:coord_x": "Coord X", + "menu:edit_marker:coord_y": "Coord Y", + "menu:edit_marker:coord_z": "Coord Z", + "menu:edit_marker:current_coords": "Coordonnées actuelles", + "menu:edit_marker:marker_color": "Couleur du marqueur", + "menu:edit_marker:marker_opacity": "Opacité du marqueur", + "menu:edit_marker:map_blip": "Blip de carte", + "menu:edit_marker:blip_sprite": "Sprite", + "menu:edit_marker:blip_color": "Couleur", + "menu:edit_marker:blip_scale": "Escalader", + "menu:edit_marker:standing_npc": "PNJ debout", + "menu:edit_marker:npc_model": "Modèle", + "menu:edit_marker:npc_heading": "Titre", + "menu:edit_marker:object": "Objet", + "menu:edit_marker:object_model": "Modèle", + "menu:edit_marker:object_rotation_pitch": "Terrain", + "menu:edit_marker:object_rotation_roll": "Rouler", + "menu:edit_marker:object_rotation_yaw": "Embardée", + + "menu:grades_dialog:title": "Niveaux d'emploi", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Point d'apparition du véhicule", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "En-tête du point d'apparition", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Coordonnées actuelles et cap", + "menu:edit_marker:temporary_garage:vehicle_model": "Modèle de véhicule", + "menu:edit_marker:temporary_garage:vehicle_name": "Nom du véhicule", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Couleur primaire", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Couleur secondaire", + "menu:edit_marker:temporary_garage:vehicle_plate": "Plaque", + "menu:edit_marker:temporary_garage:delete": "Effacer", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Nouveau modèle de véhicule", + "menu:edit_marker:temporary_garage:cant_be_empty": "Ne peut pas être vide", + "menu:edit_marker:temporary_garage:add_vehicle": "Ajouter un véhicule", + + "menu:edit_marker:boss:can_wash_money": "Peut laver l'argent?", + "menu:edit_marker:boss:return_percentage_after_wash": "Pourcentage de retour après lavage", + "menu:edit_marker:boss:add_money_to_society_account": "Ajouter de l'argent au compte de la société", + "menu:edit_marker:boss:can_withdraw_money": "Peut retirer de l'argent?", + "menu:edit_marker:boss:can_deposit_money": "Peut-on déposer de l'argent ?", + "menu:edit_marker:boss:can_manage_employees": "Peut gérer les employés?", + "menu:edit_marker:boss:can_manage_wages": "Peut gérer les salaires/grades?", + + "menu:edit_marker:shop:add_to_shop": "Ajouter à la boutique", + "menu:edit_marker:shop:item_id": "ID de l'article", + "menu:edit_marker:shop:item_price": "Prix de l'article", + "menu:edit_marker:shop:black_money": "Argent sale", + "menu:edit_marker:shop:remove_item": "Retirer l'objet", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Point d'apparition du véhicule", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "En-tête du point d'apparition", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Coordonnées actuelles et cap", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Nouveau modèle de véhicule", + "menu:edit_marker:garage_buyable:add_vehicle": "Ajouter un véhicule", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Point d'apparition du véhicule", + "menu:edit_marker:garage_owned:spawnpoint_heading": "En-tête du point d'apparition", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Coordonnées actuelles et cap", + + "menu:edit_marker:crafting_table:create_new_craft": "Créer un nouveau métier", + + "menu:edit_marker:armory:is_armory_shared": "L'armurerie est-elle partagée ?", + "menu:edit_marker:armory:max_ammo_when_take": "Munitions max quand prendre?", + "menu:edit_marker:armory:delete_armory_content": "Supprimer le contenu de l'armurerie", + + "menu:edit_marker:stash:delete_stash_content": "Supprimer le contenu de la cachette", + + "menu:edit_marker:job_outfit:create_new_outfit": "Créer une nouvelle tenue", + + "menu:edit_marker:teleport:teleport_to": "Se téléporter vers", + "menu:edit_marker:teleport:current_coords": "Coordonnées actuelles", + + "menu:edit_marker:market:item_id": "ID de l'article", + "menu:edit_marker:market:item_min_price": "Prix minimum de l'article", + "menu:edit_marker:market:item_max_price": "Prix maximum de l'article", + "menu:edit_marker:market:black_money": "Argent noir?", + "menu:edit_marker:market:time_to_sell": "Il est temps de vendre", + "menu:edit_marker:market:remove": "Supprimer", + "menu:edit_marker:market:add_item": "Ajouter un item", + + "menu:edit_marker:harvest:requires_a_tool": "Besoin d'un outil ?", + "menu:edit_marker:harvest:tool_to_harvest": "Outil pour récolter", + "menu:edit_marker:harvest:lose_on_use": "Perdre à l'usage", + "menu:edit_marker:harvest:quantity_to_lose": "Quantité à perdre", + "menu:edit_marker:harvest:probability_to_lose": "Probabilité de perdre", + "menu:edit_marker:harvest:disappear_after_use": "Disparaître après utilisation", + "menu:edit_marker:harvest:disappear_seconds": "Disparaître secondes", + "menu:edit_marker:harvest:animations": "Animations", + "menu:edit_marker:harvest:add_item": "Ajouter un item", + + "menu:edit_marker:process:remove_item": "Retirer l'objet", + "menu:edit_marker:process:give_item": "Donner l'article", + "menu:edit_marker:process:time_to_process": "Temps de traitement", + "menu:edit_marker:process:animations": "Animations", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Clip prolongé", + "menu:edit_marker:weapon_upgrader:drum_clip": "Clip de batterie", + "menu:edit_marker:weapon_upgrader:flashlight": "Lampe de poche", + "menu:edit_marker:weapon_upgrader:suppressor": "Suppresseur", + "menu:edit_marker:weapon_upgrader:scope": "Porté", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Portée avancée", + "menu:edit_marker:weapon_upgrader:grip": "Saisir", + "menu:edit_marker:weapon_upgrader:box_clip": "Clip de boîte", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Finition de luxe", + "menu:edit_marker:weapon_upgrader:default_tint": "Teinte par défaut", + "menu:edit_marker:weapon_upgrader:green_tint": "Teinte verte", + "menu:edit_marker:weapon_upgrader:gold_tint": "Teinte dorée", + "menu:edit_marker:weapon_upgrader:pink_tint": "Teinte rose", + "menu:edit_marker:weapon_upgrader:army_tint": "teinte armée", + "menu:edit_marker:weapon_upgrader:lspd_tint": "teinte LSPD", + "menu:edit_marker:weapon_upgrader:orange_tint": "Teinte orangée", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Teinte platine", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Emploi pouvant mettre en vente des objets", + "menu:edit_marker:job_shop:allowed_job": "Emploi autorisé à vendre", + "menu:edit_marker:job_shop:minimum_grade": "Grade minimum autorisé à vendre", + + "menu:edit_marker:delete_marker": "Supprimer le marqueur", + "menu:edit_marker:close": "Fermé", + "menu:edit_marker:save": "Sauvegarder", + + "menu:input_text:close": "Fermé", + "menu:input_text:confirm": "Confirmer", + + "menu:notification:notification": "Notification", + "menu:notification:close": "Fermé", + + "menu:not_allowed:you_are_not_allowed": "Vous n'êtes pas autorisé à utiliser ce menu", + "menu:not_allowed:if_you_are_admin": "Si vous êtes un administrateur de serveur, vous devez ajouter l'autorisation ACE à votre server.cfg", + + "menu:animations:animations": "Animations", + "menu:animations:add_animation": "Ajouter une animation", + "menu:animations:close": "fermé", + "menu:animations:save": "sauvegarder", + + "menu:dynamic:create_new_job": "Créer un nouvel emploi", + "menu:dynamic:new_job_label": "Nouvelle étiquette d'emploi :", + "menu:dynamic:new_job_name": "Nom du nouveau travail (identifiant) :", + + "menu:dynamic:delete_job_confirm": "Êtes-vous sûr de vouloir supprimer ce travail?", + + "menu:dynamic:job_markers:create_marker": "Étiqueter", + "menu:dynamic:job_markers:label": "Étiqueter", + "menu:dynamic:job_markers:coord_x": "Coord X", + "menu:dynamic:job_markers:coord_y": "Coord Y", + "menu:dynamic:job_markers:coord_z": "Coord Z", + "menu:dynamic:job_markers:current_coords": "Coordonnées actuelles", + "menu:dynamic:job_markers:min_grade": "Note minimale", + + "menu:dynamic:public_markers:create_public_marker": "Créer un marqueur public", + "menu:dynamic:public_markers:label": "Étiqueter", + "menu:dynamic:public_markers:coord_x": "Coord X", + "menu:dynamic:public_markers:coord_y": "Coord Y", + "menu:dynamic:public_markers:coord_z": "Coord Z", + "menu:dynamic:public_markers:current_coords": "Coordonnées actuelles", + + "menu:dynamic:harvest:name": "Nom (ID)", + "menu:dynamic:harvest:min_quantity": "Quantité minimum", + "menu:dynamic:harvest:max_quantity": "Quantité maximale", + "menu:dynamic:harvest:time_to_harvest": "Temps de récolte (secondes)", + "menu:dynamic:harvest:probabilty": "Probabilité de trouver", + + "menu:dynamic:default": "Défaut", + + "menu:dynamic:animations:animation_dictionary": "Dictionnaire d'animations :", + "menu:dynamic:animations:animation_name": "Nom de l'animation :", + "menu:dynamic:animations:animation_duration": "Durée de l'animation (secondes) :", + "menu:dynamic:animations:scenario_name": "Nom du scénario", + "menu:dynamic:animations:scenario_duration": "Durée du scénario (secondes) :", + "menu:dynamic:animations:remove": "Supprimer", + + "menu:dynamic:marker_info:stash": "Cache", + "menu:dynamic:marker_info:stash_settings": "Paramètres de cache", + "menu:dynamic:marker_info:armory": "Armurerie", + "menu:dynamic:marker_info:armory_settings": "Paramètres de l'armurerie", + "menu:dynamic:marker_info:safe": "En sécurité", + "menu:dynamic:marker_info:temporary_garage": "Garage - Véhicules temporaires", + "menu:dynamic:marker_info:temporary_garage_settings": "Paramètres du garage", + "menu:dynamic:marker_info:garage_buyable": "Garage - Véhicules achetables", + "menu:dynamic:marker_info:garage_buyable_settings": "Paramètres du garage", + "menu:dynamic:marker_info:garage_owned": "Véhicules possédés", + "menu:dynamic:marker_info:garage_owned_settings": "Paramètres du garage", + "menu:dynamic:marker_info:boss": "Patron", + "menu:dynamic:marker_info:boss_settings": "Paramètres du patron", + "menu:dynamic:marker_info:wardrobe": "Garde-robe - Tenues enregistrées par le joueur", + "menu:dynamic:marker_info:job_outfit": "Tenue de travail", + "menu:dynamic:marker_info:job_outfit_settings": "Tenues", + "menu:dynamic:marker_info:shop": "Boutique (acheter des articles)", + "menu:dynamic:marker_info:shop_settings": "Articles de la boutique", + "menu:dynamic:marker_info:market": "Marché (vendre des objets)", + "menu:dynamic:marker_info:market_settings": "Articles du marché", + "menu:dynamic:marker_info:harvest": "Point de récolte", + "menu:dynamic:marker_info:harvest_settings": "Objets récoltables", + "menu:dynamic:marker_info:process": "Point de traitement", + "menu:dynamic:marker_info:process_settings": "Article traitable", + "menu:dynamic:marker_info:crafting_table": "Table d'artisanat", + "menu:dynamic:marker_info:crafting_table_settings": "Recettes d'artisanat", + "menu:dynamic:marker_info:teleport": "Point de téléportation", + "menu:dynamic:marker_info:teleport_settings": "Paramètres de téléportation", + "menu:dynamic:marker_info:weapon_upgrader": "Améliorateur d'armes", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Prix des composants/teintes", + "menu:dynamic:marker_info:duty": "Marche/Arrêt", + "menu:dynamic:marker_info:job_shop": "Atelier d'emploi", + "menu:dynamic:marker_info:job_shop_settings": "Paramètres de la boutique", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Temps de fabrication (secondes)", + "menu:dynamic:marker:crafting_table:result_item": "Élément de résultat", + "menu:dynamic:marker:crafting_table:quantity": "Quantité", + "menu:dynamic:marker:crafting_table:item_id": "ID de l'article", + "menu:dynamic:marker:crafting_table:item_quantity": "Quantité d'article", + "menu:dynamic:marker:crafting_table:lose_on_use": "Perdre à l'usage", + "menu:dynamic:marker:crafting_table:remove": "Supprimer", + "menu:dynamic:marker:crafting_table:animations": "Animations", + "menu:dynamic:marker:crafting_table:add_to_craft": "Ajouter à l'artisanat", + "menu:dynamic:marker:crafting_table:remove_craft": "Supprimer l'artisanat", + + "menu:dynamic:marker:temporary_garage:delete": "Effacer", + "menu:dynamic:marker:temporary_garage:random_plate": "Plaque aléatoire", + + "menu:datatable:lengthMenu": "Afficher les résultats de _MENU_", + "menu:datatable:zeroRecords": "Aucun résultat", + "menu:datatable:info": "Affichage de _PAGE_ sur _PAGES_", + "menu:datatable:infoEmpty": "Aucun résultat disponible", + "menu:datatable:infoFiltered": "(filtré à partir des résultats MAX)", + "menu:datatable:search": "Chercher:", + "menu:datatable:next": "Suivant", + "menu:datatable:previous": "Précédent", + + "menu:chart:players_in_rank": "Joueurs classés", + + "menu:settings:player_menu_position": "Position du menu du lecteur", + "menu:settings:player_menu_position:bottom_right": "En bas à droite", + "menu:settings:player_menu_position:top_right": "En haut à droite", + "menu:settings:player_menu_position:bottom_left": "En bas à gauche", + "menu:settings:player_menu_position:top_left": "En haut à gauche", + "menu:settings:max_distance_marker": "Distance maximale où le marqueur peut être vu", + "menu:settings:use3Dtext": "Utilisez du texte 3D au lieu de marqueurs", + "menu:settings:text_size": "Taille du texte", + "menu:settings:font_to_use": "Police à utiliser", + "menu:settings:seconds_to_lockpick_car": "Secondes pour crocheter une voiture", + "menu:settings:vehicle_alarm": "Le véhicule doit-il avoir une alarme pendant le crochetage ?", + "menu:settings:jsfour_idcard": "Utilisez le script jsfour-idcard (si vous l'avez) pour afficher la carte d'identité cible dans l'action de vérification d'identité/licence de véhicule/licence d'arme", + "menu:settings:can_use_actions_off_duty": "Le joueur peut-il utiliser le menu d'actions F6 lorsqu'il n'est pas en service ?", + "menu:settings:car_driving_licenses_ids": "Identifiants de permis de conduire", + "menu:settings:weapon_licenses_ids": "Identifiants des licences d'armes", + "menu:settings:new_driving_license": "Nouveau permis de conduire", + "menu:settings:add": "Ajouter", + "menu:settings:new_weapon_license": "Nouveau permis d'armes", + "menu:settings:can_sell_multiple_items": "Peut-on vendre plusieurs objets à la fois sur le marché ?", + "menu:settings:language": "Langue", + "menu:settings:allow_afk_farming": "Activer la récolte automatique et l'agriculture de marqueur de processus", + "menu:settings:unemployed_job_id": "ID de l'emploi au chômage", + "menu:settings:unemployed_job_grade": "Niveau d'emploi au chômage", + "menu:settings:ace_permission": "Autorisation ACE", + + "menu:settings:enable_discord_logs": "Activer les journaux de discorde", + "menu:settings:discord_webhooks": "lien vers discord", + "menu:settings:main_webhook": "lien principal", + "menu:settings:separated_webhooks": "Separated lien", + + "menu:settings:handcuffs_requires_item": "Les menottes nécessitent un article", + "menu:settings:handcuffs_item_name": "Nom de l'article menottes", + + "menu:settings:lockpick_requires_item": "Le véhicule de crochetage nécessite un élément", + "menu:settings:lockpick_item_name": "Nom de l'élément de Lockpick", + "menu:settings:lockpickRemoveOnUse": "Perdre le Lockpick à l'utilisation", + + "menu:settings:robbable_accounts": "Comptes piratables", + "menu:settings:new_robbable_account": "Nouveau compte", + "menu:settings:canAlwaysCarryItem": "Peut toujours transporter des objets", + "menu:settings:accounts_depositable_in_safe": "Comptes déposables en coffre-fort", + "menu:settings:enable_cash_in_safes_old_esx": "Activer les espèces en coffre-fort pour l'ancienne version d'ESX", + + "menu:settings:vehicle_reparation": "Réparation de véhicule", + "menu:settings:repair_vehicle_requires_item": "Le véhicule de réparation nécessite un élément", + "menu:settings:repair_vehicle_item_name": "Nom de l'élément du kit de réparation", + "menu:settings:lose_fixkit_on_use": "Perdre le kit de réparation à l'utilisation", + + "menu:settings:vehicle_cleaning": "Nettoyage de véhicule", + "menu:settings:clean_vehicle_requires_item": "Véhicule propre nécessite un article", + "menu:settings:clean_vehicle_item_name": "Nom de l'élément éponge", + "menu:settings:lose_sponge_on_use": "Perdre l'éponge à l'utilisation", + + "menu:settings:healing": "Guérison", + "menu:settings:healing_requires_item": "La guérison nécessite un objet", + "menu:settings:healing_item_name": "Nom de l'article de pansement", + "menu:settings:lose_bandage_on_use": "Perdre le bandage à l'utilisation", + + "menu:settings:reviving": "Faire revivre", + "menu:settings:reviving_requires_item": "La réanimation nécessite un élément", + "menu:settings:reviving_item_name": "Nom de l'élément Medikit", + "menu:settings:lose_medikit_on_use": "Perdre le medikit à l'utilisation", + + "menu:settings:enable_property_outfits": "Activer les tenues du magasin de données de propriété dans le marqueur de garde-robe", + + "menu:settings:apply_changes": "Appliquer les modifications", + "menu:settings:restore_default_config": "Restaurer la configuration par défaut", + "menu:are_you_sure_to_restore_settings": "Êtes-vous sûr de restaurer les paramètres par défaut?", + + "menu:items_dialog:title": "Liste d'articles", + "menu:items_dialog:search_item": "Recherche article", + + "menu:weapons_dialog:title": "Liste des armes", + "menu:weapons_dialog:search_weapon": "Rechercher une arme", + + "menu:dialog:choose_item": "Choisir l'article", + "menu:dialog:choose_weapon": "Choisir l'arme" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/hu.json b/resources/[creators]/jobs_creator/html/menu_translations/hu.json new file mode 100644 index 0000000..1c00bcc --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/hu.json @@ -0,0 +1,424 @@ +{ + "menu:jobs": " Munkák", + "menu:public_markers": " Nyilvános jelzök", + "menu:statistics": " Statisztikák", + "menu:settings": " Beállítások", + + "menu:create_new_job": "Új munka létrehozása", + + "menu:job_label": "Munka neve", + "menu:job_id": "Munka ID", + "menu:ranks": "Rang", + + "menu:create_new_marker": "Új marker létrehozása", + + "menu:marker:id": "ID", + "menu:marker:label": "Felirat:", + "menu:marker:type": "Típus", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Minimális fokozat", + + "menu:online_players": "Online játékosok", + "menu:total_players": "Összes játékos", + "menu:society_money": "Társadalmi pénz", + + "menu:job:ranks": " Rangok", + "menu:job:markers": " Jelzők", + "menu:job:statistics": " Statisztikák", + "menu:job:settings": " Beállítások", + + "menu:create_new_rank": "Új rang létrehozása", + + "menu:rank:id": "ID", + "menu:rank:label": "Felirat:", + "menu:rank:name": "Név", + "menu:rank:grade": "Fokozat", + "menu:rank:salary": "Fizetés", + + "menu:job_settings:whitelisted": "Fehérlistás", + "menu:job_settings:enable_billing": "Számlázás aktiválása", + "menu:job_settings:enable_search_players": "Engedélyezze a rablást/keresést", + "menu:job_settings:enable_handcuff_players": "Engedélyezze a bilincs használatát", + "menu:job_settings:enable_lockpick_players": "Engedélyezze a zárfeltörö autókat", + "menu:job_settings:enable_wash_vehicles": "A jármüvek mosásának engedélyezése", + "menu:job_settings:enable_repair_vehicles": "Jármüvek javításának engedélyezése", + "menu:job_settings:enable_impound_vehicles": "Engedélyezze a jármüvek lefoglalását", + "menu:job_settings:enable_check_identities": "Az identitások ellenörzésének engedélyezése", + "menu:job_settings:enable_check_vehicle_owner": "Engedélyezze a jármü tulajdonosának ellenörzését", + "menu:job_settings:enable_check_driving_license": "Engedélyezze a jogosítvány ellenörzését", + "menu:job_settings:enable_check_weapon_license": "Fegyverengedély ellenörzésének engedélyezése", + "menu:job_settings:enable_heal": "Engedélyezze a gyógyulást", + "menu:job_settings:enable_revive": "Engedélyezze a felélesztést", + + "menu:job_settings:delete_job": "Munka törlése", + "menu:job_settings:save_changes": "Változtatások mentése", + + "menu:rank_creation:create_rank": "Hozzon létre rangot", + "menu:rank_creation:label": "Címke", + "menu:rank_creation:name": "Név (id)", + "menu:rank_creation:grade": "Fokozat", + "menu:rank_creation:salary": "Fizetés", + "menu:rank_creation:close": "Bezárás", + "menu:rank_creation:create": "létrehoz", + + "menu:rank_edit:edit": "Rang szerkesztése", + "menu:rank_edit:label": "Címke", + "menu:rank_edit:name_id": "Név(id)", + "menu:rank_edit:grade": "Fokozat", + "menu:rank_edit:salary": "Fizetés", + "menu:rank_edit:delete": "Töröl", + "menu:rank_edit:close": "Bezárás", + "menu:rank_edit:save": "Mentés", + + "menu:delete_dialog:delete": "Töröl", + "menu:delete_dialog:close": "Bezárás", + + "menu:edit_marker:edit_marker": "Jelzö szerkesztés", + "menu:edit_marker:label": "Címke", + "menu:edit_marker:marker_type": "Jelölö típusa", + "menu:edit_marker:minimum_grade": "Minimum fokozat", + "menu:edit_marker:specific_grades": "Konkrét fokozatok", + "menu:edit_marker:choose_grades": "Válasszon fokozatot", + "menu:edit_marker:use_minimum_grade": "Használjon minimális fokozatot", + "menu:edit_marker:use_specific_grades": "Használjon speciális fokozatot", + "menu:edit_marker:marker_size": "Jelzö mérete", + "menu:edit_marker:scale_x": "Scale X", + "menu:edit_marker:scale_y": "Scale Y", + "menu:edit_marker:scale_z": "Scale Z", + "menu:edit_marker:marker_coordinates": "Jelzö kordináta", + "menu:edit_marker:coord_x": "Coord X", + "menu:edit_marker:coord_y": "Coord Y", + "menu:edit_marker:coord_z": "Coord Z", + "menu:edit_marker:current_coords": "Aktuális koordináták", + "menu:edit_marker:marker_color": "Jelzöszíne", + "menu:edit_marker:marker_opacity": "Jelzö átlátszatlanság", + "menu:edit_marker:map_blip": "Térkép radar", + "menu:edit_marker:blip_sprite": "Sprite", + "menu:edit_marker:blip_color": "Szine", + "menu:edit_marker:blip_scale": "Skála", + "menu:edit_marker:standing_npc": "Álló NPC", + "menu:edit_marker:npc_model": "Model", + "menu:edit_marker:npc_heading": "Cím", + "menu:edit_marker:object": "Objekt", + "menu:edit_marker:object_model": "Model", + "menu:edit_marker:object_rotation_pitch": "Hangmagasság", + "menu:edit_marker:object_rotation_roll": "Tekercs", + "menu:edit_marker:object_rotation_yaw": "Legyezömozgás", + + "menu:grades_dialog:title": "Munka fokozatai", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Jármü Spawnpoint", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Spawnpoint cím", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Aktuális koordináták és irányvonal", + "menu:edit_marker:temporary_garage:vehicle_model": "Jármü Model", + "menu:edit_marker:temporary_garage:vehicle_name": "Jármü Név", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Elsödleges szín", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Másodlagos szín", + "menu:edit_marker:temporary_garage:vehicle_plate": "Lemez", + "menu:edit_marker:temporary_garage:delete": "Töröl", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Új jármümodell", + "menu:edit_marker:temporary_garage:cant_be_empty": "Nem lehet üres", + "menu:edit_marker:temporary_garage:add_vehicle": "Jármü hozzáadása", + + "menu:edit_marker:boss:can_wash_money": "Lehet pénzt mosni?", + "menu:edit_marker:boss:return_percentage_after_wash": "Megtérülési százalék mosás után", + "menu:edit_marker:boss:add_money_to_society_account": "Adjon hozzá pénzt a társadalmi számlához", + "menu:edit_marker:boss:can_withdraw_money": "Lehet pénzt felvenni?", + "menu:edit_marker:boss:can_deposit_money": "Lehet pénzt befizetni?", + "menu:edit_marker:boss:can_manage_employees": "Tudja irányítani az alkalmazottakat?", + "menu:edit_marker:boss:can_manage_wages": "Tudja kezelni a béreket/osztályzatokat?", + "menu:edit_marker:boss:maximum_salary": "Maximális fizetés", + + "menu:edit_marker:shop:add_to_shop": "Hozzáadás a bolthoz", + "menu:edit_marker:shop:item_id": "Tárgy ID", + "menu:edit_marker:shop:item_price": "Darab ár", + "menu:edit_marker:shop:black_money": "Fekete pénz", + "menu:edit_marker:shop:remove_item": "Elem eltávolítása", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Jármü Spawnpoint", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Spawnpoint cím", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Aktuális koordináták és irányvonal", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Új járműmodell", + "menu:edit_marker:garage_buyable:add_vehicle": "Jármü hozzáadása", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Jármü Spawnpoint", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Spawnpoint címsor", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Aktuális koordináták és irányvonal", + + "menu:edit_marker:crafting_table:create_new_craft": "Hozzon létre új mesterséget", + + "menu:edit_marker:armory:is_armory_shared": "A fegyvertár közös?", + "menu:edit_marker:armory:max_ammo_when_take": "Maximális löszer, amikor felveszi?", + "menu:edit_marker:armory:delete_armory_content": "Fegyvertár tartalmának törlése", + + "menu:edit_marker:stash:delete_stash_content": "Rejtekhely tartalmának törlése", + + "menu:edit_marker:job_outfit:create_new_outfit": "Új ruházat létrehozása", + + "menu:edit_marker:teleport:teleport_to": "Teleportálj a", + "menu:edit_marker:teleport:current_coords": "Jelenlegi koordináták", + + "menu:edit_marker:market:item_id": "Tárgy ID", + "menu:edit_marker:market:item_min_price": "Tárgy minimális ár", + "menu:edit_marker:market:item_max_price": "Tárgy maximum ár", + "menu:edit_marker:market:black_money": "Fekete pénz?", + "menu:edit_marker:market:time_to_sell": "Ideje eladni", + "menu:edit_marker:market:remove": "Távolítsa el", + "menu:edit_marker:market:add_item": "Tárgy hozzáadása", + "menu:edit_marker_market:society_percentage": "A társadalomnak juttatott százalékos arány", + + "menu:edit_marker:harvest:requires_a_tool": "Szerszámra van szükség?", + "menu:edit_marker:harvest:tool_to_harvest": "Eszköz a betakarításhoz", + "menu:edit_marker:harvest:lose_on_use": "Veszteség a használat során", + "menu:edit_marker:harvest:quantity_to_lose": "Elveszítendö mennyiség", + "menu:edit_marker:harvest:probability_to_lose": "Vesztés valószünüsége", + "menu:edit_marker:harvest:disappear_after_use": "Használat után eltünik", + "menu:edit_marker:harvest:disappear_seconds": "Másodpercek alatt eltünik", + "menu:edit_marker:harvest:animations": "Animációk", + "menu:edit_marker:harvest:add_item": "Tárgy hozzáadása", + + "menu:edit_marker:process:remove_item": "Eltávolítani az elemet", + "menu:edit_marker:process:give_item": "Adj tárgyat", + "menu:edit_marker:process:time_to_process": "Feldolgozási idő", + "menu:edit_marker:process:animations": "Animációk", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Kiterjesztett klip", + "menu:edit_marker:weapon_upgrader:drum_clip": "Dob Clip", + "menu:edit_marker:weapon_upgrader:flashlight": "Zseblámpa", + "menu:edit_marker:weapon_upgrader:suppressor": "Szörö", + "menu:edit_marker:weapon_upgrader:scope": "Hatókör", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Haladó hatókör", + "menu:edit_marker:weapon_upgrader:grip": "Fogás", + "menu:edit_marker:weapon_upgrader:box_clip": "Box Clip", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Luxus kivitel", + "menu:edit_marker:weapon_upgrader:default_tint": "Alapértelmezett árnyalat", + "menu:edit_marker:weapon_upgrader:green_tint": "Zöld árnyalat", + "menu:edit_marker:weapon_upgrader:gold_tint": "Arany árnyalat", + "menu:edit_marker:weapon_upgrader:pink_tint": "Rózsaszín árnyalat", + "menu:edit_marker:weapon_upgrader:army_tint": "Hadsereg árnyalat", + "menu:edit_marker:weapon_upgrader:lspd_tint": "LSPD árnyalat", + "menu:edit_marker:weapon_upgrader:orange_tint": "narancs árnyalat", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platina árnyalatt", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Munka, amivel árusíthat tárgyakat", + "menu:edit_marker:job_shop:allowed_job": "Eladó engedélyezett állás", + "menu:edit_marker:job_shop:minimum_grade": "Eladható minimális osztályzat", + + "menu:edit_marker:delete_marker": "Jelölö törlése", + "menu:edit_marker:close": "Bezárás", + "menu:edit_marker:save": "Mentés", + + "menu:input_text:close": "Bezárás", + "menu:input_text:confirm": "Megerösít", + + "menu:notification:notification": "Értesítés", + "menu:notification:close": "Bezárás", + + "menu:not_allowed:you_are_not_allowed": "Ezt a menüt nem használhatod", + "menu:not_allowed:if_you_are_admin": "Ha te szerveradminisztrátor, ACE-engedélyt kell adnia a server.cfg fájlhoz", + + "menu:animations:animations": "Animációk", + "menu:animations:add_animation": "Animáció hozzáadása", + "menu:animations:close": "Bezárás", + "menu:animations:save": "Mentés", + + "menu:dynamic:create_new_job": "Hozzon létre új munkát", + "menu:dynamic:new_job_label": "Új munkacímke:", + "menu:dynamic:new_job_name": "Új munkanév(id):", + + "menu:dynamic:delete_job_confirm": "Biztosan törlöd ezt a munkát?", + + "menu:dynamic:job_markers:create_marker": "Jelzö létrehozása", + "menu:dynamic:job_markers:label": "Címke", + "menu:dynamic:job_markers:coord_x": "Coord X", + "menu:dynamic:job_markers:coord_y": "Coord Y", + "menu:dynamic:job_markers:coord_z": "Coord Z", + "menu:dynamic:job_markers:current_coords": "Aktuális koordináták", + "menu:dynamic:job_markers:min_grade": "Minimum fokozat", + + "menu:dynamic:public_markers:create_public_marker": "Nyilvános jelölö létrehozása", + "menu:dynamic:public_markers:label": "Címke", + "menu:dynamic:public_markers:coord_x": "koordináta X", + "menu:dynamic:public_markers:coord_y": "koordináta Y", + "menu:dynamic:public_markers:coord_z": "koordináta Z", + "menu:dynamic:public_markers:current_coords": "Aktuális koordináták", + + "menu:dynamic:harvest:name": "Név (ID)", + "menu:dynamic:harvest:min_quantity": "Minimális mennyiség", + "menu:dynamic:harvest:max_quantity": "Maximális mennyiség", + "menu:dynamic:harvest:time_to_harvest": "A betakarítás ideje (másodperc)", + "menu:dynamic:harvest:probabilty": "A megtalálás valószínüsége", + + "menu:dynamic:default": "Alapértelmezett", + + "menu:dynamic:animations:animation_dictionary": "Animációs szótár:", + "menu:dynamic:animations:animation_name": "Animáció neve:", + "menu:dynamic:animations:animation_duration": "Animáció időtartama (másodperc):", + "menu:dynamic:animations:scenario_name": "Forgatókönyv neve:", + "menu:dynamic:animations:scenario_duration": "A forgatókönyv időtartama (másodperc):", + "menu:dynamic:animations:remove": "Távolítsa el", + + "menu:dynamic:marker_info:stash": "Rejtekhelyre eltesz", + "menu:dynamic:marker_info:stash_settings": "Rejtekhely beállítások", + "menu:dynamic:marker_info:armory": "Fegyvertár", + "menu:dynamic:marker_info:armory_settings": "Fegyvertár beállítások", + "menu:dynamic:marker_info:safe": "Biztonságos", + "menu:dynamic:marker_info:temporary_garage": "Garázs - Átmeneti jármüvek", + "menu:dynamic:marker_info:temporary_garage_settings": "Garázs beállítások", + "menu:dynamic:marker_info:garage_buyable": "Garázs - Megvásárolható jármüvek", + "menu:dynamic:marker_info:garage_buyable_settings": "Garázs beállítások", + "menu:dynamic:marker_info:garage_owned": "Saját tulajdonú járművek", + "menu:dynamic:marker_info:garage_owned_settings": "Garázs beállítások", + "menu:dynamic:marker_info:boss": "Fönök", + "menu:dynamic:marker_info:boss_settings": "Fünöki beállítások", + "menu:dynamic:marker_info:wardrobe": "Ruhatár - A játékos által elmentett ruhák", + "menu:dynamic:marker_info:job_outfit": "Munkaruha", + "menu:dynamic:marker_info:job_outfit_settings": "Ruházat", + "menu:dynamic:marker_info:shop": "Bolt (tárgyak vásárlása)", + "menu:dynamic:marker_info:shop_settings": "Bolti tárgyak", + "menu:dynamic:marker_info:market": "Piac (tárgyak eladása)", + "menu:dynamic:marker_info:market_settings": "Piaci termékek", + "menu:dynamic:marker_info:harvest": "A betakarítási pont", + "menu:dynamic:marker_info:harvest_settings": "Betakarítható tárgyak", + "menu:dynamic:marker_info:process": "Feldolgozási pont", + "menu:dynamic:marker_info:process_settings": "Feldolgozható termék", + "menu:dynamic:marker_info:crafting_table": "Kézmüves asztal", + "menu:dynamic:marker_info:crafting_table_settings": "Receptek készítése", + "menu:dynamic:marker_info:teleport": "Teleport pont", + "menu:dynamic:marker_info:teleport_settings": "Teleport beálitás", + "menu:dynamic:marker_info:weapon_upgrader": "Fegyver fejlesztö", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Alkatrészek/árnyalatok árai", + "menu:dynamic:marker_info:duty": "Be/ki szolgálat", + "menu:dynamic:marker_info:job_shop": "Munkabolt", + "menu:dynamic:marker_info:job_shop_settings": "Bolt beállításai", + + "menu:dynamic:marker:crafting_table:time_to_craft": "A kézmüvességig eltelt idö (másodpercek)", + "menu:dynamic:marker:crafting_table:result_item": "Eredmény elem", + "menu:dynamic:marker:crafting_table:quantity": "Mennyiség", + "menu:dynamic:marker:crafting_table:item_id": "Tárgy ID", + "menu:dynamic:marker:crafting_table:item_quantity": "Cikk mennyisége", + "menu:dynamic:marker:crafting_table:lose_on_use": "Veszteség a használat során", + "menu:dynamic:marker:crafting_table:remove": "Távolítsa el a", + "menu:dynamic:marker:crafting_table:animations": "Animációk", + "menu:dynamic:marker:crafting_table:add_to_craft": "Hozzáadás a kézművességhez", + "menu:dynamic:marker:crafting_table:remove_craft": "Kézmüvesség eltávolítása", + + "menu:dynamic:marker:temporary_garage:delete": "Törlés", + "menu:dynamic:marker:temporary_garage:random_plate": "Véletlenszerű tányér", + + "menu:datatable:lengthMenu": "Menü eredmények mutatása", + "menu:datatable:zeroRecords": "Nincs eredmény", + "menu:datatable:info": "Az oldal oldalának megjelenítése", + "menu:datatable:infoEmpty": "Nem állnak rendelkezésre eredmények", + "menu:datatable:infoFiltered": "(_MAX_ eredményekből kiszürve)", + "menu:datatable:search": "Keresés:", + "menu:datatable:next": "Következő", + "menu:datatable:previous": "Előző", + + "menu:chart:players_in_rank": "A rangsorban szereplö játékosok", + + "menu:settings:player_menu_position": "Játékos menü pozíciója", + "menu:settings:player_menu_position:bottom_right": "Jobbra lent", + "menu:settings:player_menu_position:top_right": "Jobbra fent", + "menu:settings:player_menu_position:right": "Jobbra", + "menu:settings:player_menu_position:bottom_left": "Balra lent", + "menu:settings:player_menu_position:top_left": "Balra fent", + "menu:settings:player_menu_position:left": "Balra", + "menu:settings:max_distance_marker": "Maximális távolság, ahol a jelölö látható", + "menu:settings:use3Dtext": " 3D szöveg használata jelölök helyett", + "menu:settings:text_size": "Szöveg mérete", + "menu:settings:font_to_use": "Használható betütípus", + "menu:settings:seconds_to_lockpick_car": "Másodpercek az autó feltöréséhez", + "menu:settings:vehicle_alarm": "Kell-e a jármünek riasztóval rendelkeznie a zárfeltárás során?", + "menu:settings:jsfour_idcard": "Használja a jsfour-idcard szkriptet (ha rendelkezik vele) a személyazonosság/jogosítvány/fegyvertartási engedély ellenőrzése müveletben a célszemélyi igazolvány megtekintéséhez.", + "menu:settings:can_use_actions_off_duty": "Használhatja a játékos az F6 akciók menüt, amikor nincs szolgálatban?", + "menu:settings:car_driving_licenses_ids": "Gépjármű-vezetői engedélyek ID", + "menu:settings:weapon_licenses_ids": "Fegyvertartási engedélyek ID", + "menu:settings:new_driving_license": "Új vezetöi engedély", + "menu:settings:add": "Add", + "menu:settings:new_weapon_license": "Új fegyvertartási engedély", + "menu:settings:can_sell_multiple_items": "Egyszerre több terméket is eladhatok a piacon?", + "menu:settings:language": "Nyelv", + "menu:settings:allow_afk_farming": "Automatikus betakarítás és folyamatjelölö gazdálkodás lehetövé tétele", + "menu:settings:unemployed_job_id": "Munkanélküli állás ID", + "menu:settings:unemployed_job_grade": "Munkanélküliségi besorolás", + "menu:settings:ace_permission": "ACE engedély", + + "menu:settings:enable_discord_logs": "Discord naplók engedélyezése", + "menu:settings:discord_webhooks": "Discord webhooks", + "menu:settings:main_webhook": "Fö webhook", + "menu:settings:separated_webhooks": "Elkülönített webhooks", + + "menu:settings:handcuffs_requires_item": "Kézbilincs tételre van szükség", + "menu:settings:handcuffs_item_name": "Bilincs termék neve", + + "menu:settings:lockpick_requires_item": "Jármö feltörö tárgyat igányel", + "menu:settings:lockpick_item_name": "Zárfeltoro neve", + "menu:settings:lockpickRemoveOnUse": "Elveszíted a lakatpálcát használatakor", + + "menu:settings:robbable_accounts": "Kirabolható számlák", + "menu:settings:new_robbable_account": "Új fiók", + "menu:settings:canAlwaysCarryItem": "Mindig szállíthat tárgyakat", + "menu:settings:accounts_depositable_in_safe": "Széfben elhelyezett számlák", + "menu:settings:enable_cash_in_safes_old_esx": "A régi ESX-verzióban a széfben lévő készpénz engedélyezése", + + "menu:settings:vehicle_reparation": "Jármüjavítás", + "menu:settings:repair_vehicle_requires_item": "A jármü javításához tárgyra van szükség", + "menu:settings:repair_vehicle_item_name": "javítási készlet neve", + "menu:settings:lose_fixkit_on_use": "A javítási készlet elvesztése használat közben", + + "menu:settings:vehicle_cleaning": "Jármütisztítás", + "menu:settings:clean_vehicle_requires_item": "Tiszta jármüvet igényel", + "menu:settings:clean_vehicle_item_name": "Szivacs elem neve", + "menu:settings:lose_sponge_on_use": "Használat közben veszítse el a szivacsot", + + "menu:settings:healing": "Gyógyulás", + "menu:settings:healing_requires_item": "A gyógyuláshoz tétel kell", + "menu:settings:healing_item_name": "A kötszer elem neve", + "menu:settings:lose_bandage_on_use": "Használat közben veszítse el a kötszert", + + "menu:settings:reviving": "Újraélesztés", + "menu:settings:reviving_requires_item": "Az újraélesztéshez elem szükséges", + "menu:settings:reviving_item_name": "Medkit termék neve", + "menu:settings:lose_medikit_on_use": "Használat közben elveszíti a medikitet", + + "menu:settings:enable_property_outfits": "Az ingatlan adattár ruházatának engedélyezése a gardrób jelölönen", + + "menu:settings:apply_changes": "Módosítások elfogadása", + "menu:settings:restore_default_config": "Az alapértelmezett konfiguráció visszaállítása", + "menu:are_you_sure_to_restore_settings": "Biztosan visszaállítja az alapértelmezett beállításokat?", + + "menu:items_dialog:title": "Tétellista", + "menu:items_dialog:search_item": "Elem keresése", + + "menu:weapons_dialog:title": "Fegyverlista", + "menu:weapons_dialog:search_weapon": "Fegyver keresés", + + "menu:dialog:choose_item": "Válasszon tárgyat", + "menu:dialog:choose_weapon": "Válasszon fegyvert", + + "menu:settings:actions_menu_key": "Kulcs a müveletek menü megnyitásához", + + "menu:settings:park_all_owned_vehicles_on_restart": "Az újraindításkor parkolja le az összes saját járművét", + + "menu:account_name": "Felhasználónév", + "menu:accounts_dialog:title": "Fiók lista", + "menu:minimum_amount": "Minimális mennyiség", + + "menu:edit_marker:requires_minimum_account_money": "Minimum pénz szükséges a számlára?", + + "menu:actions": "Tevékenységek", + + "menu:settings:freeze_when_soft_handcuffed": "Állj meg, ha puha bilincset viselsz", + "menu:settings:freeze_when_hard_handcuffed": "Állj meg, ha kemény bilincset viselsz", + + "menu:coords": "Koordináták", + "menu:heading": "Cím", + "menu:add_spawnpoint": "Add spawnpoint", + "menu:spawnpoints": "Spawnpoints", + "menu:radius": "Sugár", + + "menu:settings:target_must_be_handcuffed_for_search": "Target must be handcuffed for search/rob" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/it.json b/resources/[creators]/jobs_creator/html/menu_translations/it.json new file mode 100644 index 0000000..8e5f211 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/it.json @@ -0,0 +1,393 @@ +{ + "menu:jobs": " Lavori", + "menu:public_markers": " Markers pubblici", + "menu:statistics": " Statistiche", + "menu:settings": " Impostazioni", + + "menu:create_new_job": "Crea nuovo lavoro", + + "menu:job_label": "Nome lavoro", + "menu:job_id": "ID lavoro", + "menu:ranks": "Ranghi", + + "menu:create_new_marker": "Crea nuovo marker", + + "menu:marker:id": "ID", + "menu:marker:label": "Nome", + "menu:marker:type": "Tipo", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Grado minimo", + + "menu:online_players": "Giocatori online", + "menu:total_players": "Tutti i giocatori", + "menu:society_money": "Soldi società", + + "menu:job:ranks": " Ranghi", + "menu:job:markers": " Markers", + "menu:job:statistics": " Statistiche", + "menu:job:settings": " Impostazioni", + + "menu:create_new_rank": "Crea nuovo rango", + + "menu:rank:id": "ID", + "menu:rank:label": "Nome mostrato", + "menu:rank:name": "Nome", + "menu:rank:grade": "Grado", + "menu:rank:salary": "Salario", + + "menu:job_settings:whitelisted": "Whitelistato", + "menu:job_settings:enable_billing": "Abilita fatture", + "menu:job_settings:enable_search_players": "Abilita perquisizione", + "menu:job_settings:enable_handcuff_players": "Abilita ammanettamento", + "menu:job_settings:enable_lockpick_players": "Abilita scassinamento veicoli", + "menu:job_settings:enable_wash_vehicles": "Abilita pulizia veicoli", + "menu:job_settings:enable_repair_vehicles": "Abilita riparazione veicoli", + "menu:job_settings:enable_impound_vehicles": "Abilita sequestro veicoli", + "menu:job_settings:enable_check_identities": "Abilita check identities", + "menu:job_settings:enable_check_vehicle_owner": "Abilita controllo proprietario veicolo", + "menu:job_settings:enable_check_driving_license": "Abilita controllo patente", + "menu:job_settings:enable_check_weapon_license": "Abilita controllo porto d'armi", + + "menu:job_settings:delete_job": "Cancella lavoro", + "menu:job_settings:save_changes": "Applica modifiche", + + "menu:rank_creation:create_rank": "Crea rango", + "menu:rank_creation:label": "Nome", + "menu:rank_creation:name": "Nome (id)", + "menu:rank_creation:grade": "Grado", + "menu:rank_creation:salary": "Salario", + "menu:rank_creation:close": "Chiudi", + "menu:rank_creation:create": "Crea", + + "menu:rank_edit:edit": "Modifica rango", + "menu:rank_edit:label": "Nome", + "menu:rank_edit:name_id": "Nome (id)", + "menu:rank_edit:grade": "Grado", + "menu:rank_edit:salary": "Salario", + "menu:rank_edit:delete": "Cancella", + "menu:rank_edit:close": "Chiudi", + "menu:rank_edit:save": "Salva", + + "menu:delete_dialog:delete": "Cancella", + "menu:delete_dialog:close": "Chiudi", + + "menu:edit_marker:edit_marker": "Modifica marker", + "menu:edit_marker:label": "Nome", + "menu:edit_marker:marker_type": "Tipo marker", + "menu:edit_marker:minimum_grade": "Grado minimo", + "menu:edit_marker:specific_grades": "Gradi specifici", + "menu:edit_marker:choose_grades": "Scegli gradi", + "menu:edit_marker:use_minimum_grade": "Usa grado minimo", + "menu:edit_marker:use_specific_grades": "Usa gradi specifici", + "menu:edit_marker:marker_size": "Dimensioni marker", + "menu:edit_marker:scale_x": "Scala X", + "menu:edit_marker:scale_y": "Scala Y", + "menu:edit_marker:scale_z": "Scala Z", + "menu:edit_marker:marker_coordinates": "Coordinate marker", + "menu:edit_marker:coord_x": "Coordinata X", + "menu:edit_marker:coord_y": "Coordinata Y", + "menu:edit_marker:coord_z": "Coordinata Z", + "menu:edit_marker:current_coords": "Coordinate attuali", + "menu:edit_marker:marker_color": "Colore marker", + "menu:edit_marker:marker_opacity": "Trasparenza marker", + "menu:edit_marker:map_blip": "Blip mappa", + "menu:edit_marker:blip_sprite": "Sprite", + "menu:edit_marker:blip_color": "Colore", + "menu:edit_marker:blip_scale": "Scala", + "menu:edit_marker:standing_npc": "NPC immobile", + "menu:edit_marker:npc_model": "Modello", + "menu:edit_marker:npc_heading": "Heading", + "menu:edit_marker:object": "Oggetto", + "menu:edit_marker:object_model": "Modello", + "menu:edit_marker:object_rotation_pitch": "Pitch", + "menu:edit_marker:object_rotation_roll": "Roll", + "menu:edit_marker:object_rotation_yaw": "Yaw", + + "menu:grades_dialog:title": "Gradi lavoro", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Punto di spawn veicolo", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Heading punto di spawn", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Coordinate e heading attuali", + "menu:edit_marker:temporary_garage:vehicle_model": "Modello veicolo", + "menu:edit_marker:temporary_garage:vehicle_name": "Nome veicolo", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Colore Primario", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Colore Secondario", + "menu:edit_marker:temporary_garage:vehicle_plate": "Targa", + "menu:edit_marker:temporary_garage:delete": "Cancella", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Nuovo modello veicolo", + "menu:edit_marker:temporary_garage:cant_be_empty": "Non può essere vuoto", + "menu:edit_marker:temporary_garage:add_vehicle": "Aggiungi veicolo", + + "menu:edit_marker:boss:can_wash_money": "Può pulire i soldi?", + "menu:edit_marker:boss:return_percentage_after_wash": "Percentuale di ritorno dopo la pulizia", + "menu:edit_marker:boss:add_money_to_society_account": "Aggiungi i soldi al conto della società", + "menu:edit_marker:boss:can_withdraw_money": "Può ritirare i soldi?", + "menu:edit_marker:boss:can_deposit_money": "Può depositare i soldi?", + "menu:edit_marker:boss:can_manage_employees": "Può gestire i dipendenti?", + "menu:edit_marker:boss:can_manage_wages": "Può gestire i salari dei ranghi?", + + "menu:edit_marker:shop:add_to_shop": "Aggiungi al negozio", + "menu:edit_marker:shop:item_id": "ID item", + "menu:edit_marker:shop:item_price": "Prezzo item", + "menu:edit_marker:shop:black_money": "Soldi sporchi", + "menu:edit_marker:shop:remove_item": "Rimuovi item", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Punto di spawn veicolo", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Heading punto di spawn", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Coordinate e heading attuali", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Nuovo modello veicolo", + "menu:edit_marker:garage_buyable:add_vehicle": "Aggiungi veicolo", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Punto di spawn veicolo", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Heading punto di spawn", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Coordinate e heading attuali", + + "menu:edit_marker:crafting_table:create_new_craft": "Crea nuovo craft", + + "menu:edit_marker:armory:is_armory_shared": "L'armeria è condivisa?", + "menu:edit_marker:armory:max_ammo_when_take": "Massimo munizioni quando si ritira l'arma?", + "menu:edit_marker:armory:delete_armory_content": "Cancella contenuto armeria", + + "menu:edit_marker:stash:delete_stash_content": "Cancella contenuto inventario", + + "menu:edit_marker:job_outfit:create_new_outfit": "Crea nuovo outfit", + + "menu:edit_marker:teleport:teleport_to": "Teletrasporto a", + "menu:edit_marker:teleport:current_coords": "Coordinate attuali", + + "menu:edit_marker:market:item_id": "ID item", + "menu:edit_marker:market:item_price": "Prezzo item", + "menu:edit_marker:market:black_money": "Soldi sporchi?", + "menu:edit_marker:market:time_to_sell": "Tempo per vendere", + "menu:edit_marker:market:remove": "Rimuovi", + "menu:edit_marker:market:add_item": "Aggiungi item", + + "menu:edit_marker:harvest:requires_a_tool": "Richiede uno strumento?", + "menu:edit_marker:harvest:tool_to_harvest": "Strumento per raccogliere", + "menu:edit_marker:harvest:lose_on_use": "Perdi all'utilizzo", + "menu:edit_marker:harvest:quantity_to_lose": "Quantità da perdere", + "menu:edit_marker:harvest:animations": "Animazioni", + "menu:edit_marker:harvest:add_item": "Aggiungi oggetto", + + "menu:edit_marker:process:remove_item": "Rimuovi item", + "menu:edit_marker:process:give_item": "Dai item", + "menu:edit_marker:process:time_to_process": "Tempo per processare", + "menu:edit_marker:process:animations": "Animazioni", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Caricatore esteso", + "menu:edit_marker:weapon_upgrader:drum_clip": "Caricatore a tamburo", + "menu:edit_marker:weapon_upgrader:flashlight": "Torcia", + "menu:edit_marker:weapon_upgrader:suppressor": "Silenziatore", + "menu:edit_marker:weapon_upgrader:scope": "Mirino", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Mirino avanzato", + "menu:edit_marker:weapon_upgrader:grip": "Impugnatura", + "menu:edit_marker:weapon_upgrader:box_clip": "Caricatore a scatola", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Finitura di lusso", + "menu:edit_marker:weapon_upgrader:default_tint": "Vernice predefinita", + "menu:edit_marker:weapon_upgrader:green_tint": "Vernice verde", + "menu:edit_marker:weapon_upgrader:gold_tint": "Vernice oro", + "menu:edit_marker:weapon_upgrader:pink_tint": "Vernice rosa", + "menu:edit_marker:weapon_upgrader:army_tint": "Vernice militare", + "menu:edit_marker:weapon_upgrader:lspd_tint": "Vernice LSPD", + "menu:edit_marker:weapon_upgrader:orange_tint": "Vernice arancione", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Vernice platino", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Lavoro che può vendere oggetti", + "menu:edit_marker:job_shop:allowed_job": "Lavoro abilitato alla vendita", + "menu:edit_marker:job_shop:minimum_grade": "Grado minimo per poter vendere", + + "menu:edit_marker:delete_marker": "Elimina marker", + "menu:edit_marker:close": "Chiudi", + "menu:edit_marker:save": "Salva", + + "menu:input_text:close": "Chiudi", + "menu:input_text:confirm": "Conferma", + + "menu:notification:notification": "Notifica", + "menu:notification:close": "Chiudi", + + "menu:not_allowed:you_are_not_allowed": "Non sei autorizzato ad usare questo menù", + "menu:not_allowed:if_you_are_admin": "Se sei un admin, devi aggiungere il permesso ACE al tuo server.cfg", + + "menu:animations:animations": "Animazioni", + "menu:animations:add_animation": "Aggiungi animazione", + "menu:animations:close": "Chiudi", + "menu:animations:save": "Salva", + + "menu:dynamic:create_new_job": "Crea nuovo lavoro", + "menu:dynamic:new_job_label": "Nome nuovo lavoro:", + "menu:dynamic:new_job_name": "ID nuovo lavoro:", + + "menu:dynamic:delete_job_confirm": "Sei sicuro di voler eliminare questo lavoro?", + + "menu:dynamic:job_markers:create_marker": "Crea marker", + "menu:dynamic:job_markers:label": "Nome", + "menu:dynamic:job_markers:coord_x": "Coordinata X", + "menu:dynamic:job_markers:coord_y": "Coordinata Y", + "menu:dynamic:job_markers:coord_z": "Coordinata Z", + "menu:dynamic:job_markers:current_coords": "Coordinate attuali", + "menu:dynamic:job_markers:min_grade": "Grado minimo", + + "menu:dynamic:public_markers:create_public_marker": "Crea marker pubblico", + "menu:dynamic:public_markers:label": "Nome", + "menu:dynamic:public_markers:coord_x": "Coordinata X", + "menu:dynamic:public_markers:coord_y": "Coordinata Y", + "menu:dynamic:public_markers:coord_z": "Coordinata Z", + "menu:dynamic:public_markers:current_coords": "Coordinate attuali", + + "menu:dynamic:harvest:name": "Nome (ID)", + "menu:dynamic:harvest:min_quantity": "Quantità minima", + "menu:dynamic:harvest:max_quantity": "Quantità massima", + "menu:dynamic:harvest:time_to_harvest": "Tempo per raccogliere (secondi)", + "menu:dynamic:harvest:probabilty": "Probabilità di trovarlo", + + "menu:dynamic:default": "Predefinito", + + "menu:dynamic:animations:animation_dictionary": "Dizionario animazione:", + "menu:dynamic:animations:animation_name": "Nome animazione:", + "menu:dynamic:animations:animation_duration": "Durata animazione (secondi):", + "menu:dynamic:animations:scenario_name": "Nome scenario", + "menu:dynamic:animations:scenario_duration": "Durata scenario (secondi):", + "menu:dynamic:animations:remove": "Rimuovi", + + "menu:dynamic:marker_info:stash": "Inventario", + "menu:dynamic:marker_info:stash_settings": "Impostazioni inventario", + "menu:dynamic:marker_info:armory": "Armeria", + "menu:dynamic:marker_info:armory_settings": "Impostazioni armeria", + "menu:dynamic:marker_info:safe": "Cassaforte", + "menu:dynamic:marker_info:temporary_garage": "Garage temporaneo", + "menu:dynamic:marker_info:temporary_garage_settings": "Impostazioni garage", + "menu:dynamic:marker_info:garage_buyable": "Garage veicoli acquistabili", + "menu:dynamic:marker_info:garage_buyable_settings": "Impostazioni garage", + "menu:dynamic:marker_info:garage_owned": "Garage veicoli posseduti", + "menu:dynamic:marker_info:garage_owned_settings": "Impostazioni garage", + "menu:dynamic:marker_info:boss": "Boss", + "menu:dynamic:marker_info:boss_settings": "Impostazioni boss", + "menu:dynamic:marker_info:wardrobe": "Guardaroba - Outfit salvati dei giocatori", + "menu:dynamic:marker_info:job_outfit": "Outfit lavoro", + "menu:dynamic:marker_info:job_outfit_settings": "Outfits", + "menu:dynamic:marker_info:shop": "Negozio (compra items)", + "menu:dynamic:marker_info:shop_settings": "Items negozio", + "menu:dynamic:marker_info:market": "Mercato (vendi items)", + "menu:dynamic:marker_info:market_settings": "Items mercato", + "menu:dynamic:marker_info:harvest": "Raccolta", + "menu:dynamic:marker_info:harvest_settings": "Oggetti raccoglibili", + "menu:dynamic:marker_info:process": "Processo", + "menu:dynamic:marker_info:process_settings": "Oggetto processabile", + "menu:dynamic:marker_info:crafting_table": "Tavola da lavoro", + "menu:dynamic:marker_info:crafting_table_settings": "Ricette tavola da lavoro", + "menu:dynamic:marker_info:teleport": "Punto teletrasporto", + "menu:dynamic:marker_info:teleport_settings": "Impostazioni teletrasporto", + "menu:dynamic:marker_info:weapon_upgrader": "Accessori armi", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Prezzi accessori/vernici", + "menu:dynamic:marker_info:duty": "Dentro/Fuori servizio", + "menu:dynamic:marker_info:job_shop": "Negozio del lavoro", + "menu:dynamic:marker_info:job_shop_settings": "Impostazioni negozio", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Tempo per craftare (secondi)", + "menu:dynamic:marker:crafting_table:result_item": "Item da ottenere", + "menu:dynamic:marker:crafting_table:quantity": "Quantità", + "menu:dynamic:marker:crafting_table:item_id": "ID item", + "menu:dynamic:marker:crafting_table:item_quantity": "Quantità item", + "menu:dynamic:marker:crafting_table:lose_on_use": "Perdi con l'utilizzo", + "menu:dynamic:marker:crafting_table:remove": "Rimuovi", + "menu:dynamic:marker:crafting_table:animations": "Animazioni", + "menu:dynamic:marker:crafting_table:add_to_craft": "Aggiungi alla ricetta", + "menu:dynamic:marker:crafting_table:remove_craft": "Rimuovi ricetta", + + "menu:dynamic:marker:temporary_garage:delete": "Elimina", + "menu:dynamic:marker:temporary_garage:random_plate": "Targa casuale", + + "menu:datatable:lengthMenu": "Mostra _MENU_ risultati", + "menu:datatable:zeroRecords": "Nessun risultato", + "menu:datatable:info": "Mostrando _PAGE_ di _PAGES_", + "menu:datatable:infoEmpty": "Nessun risultato disponibile", + "menu:datatable:infoFiltered": "(filtrati da _MAX_ risultati)", + "menu:datatable:search": "Cerca:", + "menu:datatable:next": "Prossimo", + "menu:datatable:previous": "Precedente", + + "menu:chart:players_in_rank": "Giocatori nel rango", + + "menu:settings:player_menu_position": "Posizione menù giocatore", + "menu:settings:player_menu_position:bottom_right": "In basso a destra", + "menu:settings:player_menu_position:top_right": "In alto a destra", + "menu:settings:player_menu_position:bottom_left": "In basso a sinistra", + "menu:settings:player_menu_position:top_left": "In alto a sinistra", + "menu:settings:max_distance_marker": "Distanza massima per vedere un marker", + "menu:settings:use3Dtext": "Usa testo 3D invece dei markers", + "menu:settings:text_size": "Dimensioni testo", + "menu:settings:font_to_use": "Font da usare", + "menu:settings:seconds_to_lockpick_car": "Secondi per scassinare una macchina", + "menu:settings:vehicle_alarm": "Il veicolo dovrebbe avere un allarme quando viene scassinato?", + "menu:settings:jsfour_idcard": "Usa lo script jsfour-idcard (se lo hai) per vedere le azioni controllo identità, veicolo e porto d'armi", + "menu:settings:can_use_actions_off_duty": "Il giocatore può usare le azioni del menù F6 quando è fuori servizio?", + "menu:settings:car_driving_licenses_ids": "ID patenti", + "menu:settings:weapon_licenses_ids": "ID porto d'armi", + "menu:settings:new_driving_license": "Nuova patente", + "menu:settings:add": "Aggiungi", + "menu:settings:new_weapon_license": "Nuovo porto d'armi", + "menu:settings:can_sell_multiple_items": "Si possono vendere più oggetti contemporaneamente nel mercato?", + "menu:settings:language": "Lingua", + "menu:settings:allow_afk_farming": "Abilita raccolta e processo automatico", + "menu:settings:unemployed_job_id": "ID lavoro disoccupato", + "menu:settings:unemployed_job_grade": "Grado lavoro disoccupato", + "menu:settings:ace_permission": "Permesso ACE", + + "menu:settings:enable_discord_logs": "Abilita logs su discord", + "menu:settings:discord_webhooks": "Discord webhooks", + "menu:settings:main_webhook": "Webhook principale", + "menu:settings:separated_webhooks": "Webhooks separati", + + "menu:settings:handcuffs_requires_item": "Le manette richiedono l'item", + "menu:settings:handcuffs_item_name": "ID item manette", + + "menu:settings:lockpick_requires_item": "Scassinare un veicolo richiede l'item", + "menu:settings:lockpick_item_name": "ID item grimaldello", + "menu:settings:lockpickRemoveOnUse": "Perdi grimaldello con l'utilizzo", + + "menu:settings:robbable_accounts": "Account derubabili", + "menu:settings:new_robbable_account": "Nuovo account", + "menu:settings:canAlwaysCarryItem": "Può sempre trasportare oggetti", + "menu:settings:accounts_depositable_in_safe": "Accounts depositabili nella cassaforte", + "menu:settings:enable_cash_in_safes_old_esx": "Abilita contante nella cassaforte per le vecchie versioni di ESX", + + "menu:settings:vehicle_reparation": "Riparazione veicolo", + "menu:settings:repair_vehicle_requires_item": "Repair vehicle requires item", + "menu:settings:repair_vehicle_item_name": "Fixkit item name", + "menu:settings:lose_fixkit_on_use": "Lose fixkit on use", + + "menu:settings:vehicle_cleaning": "Pulizia veicolo", + "menu:settings:clean_vehicle_requires_item": "Pulire un veicolo richiede l'item", + "menu:settings:clean_vehicle_item_name": "ID item spugna", + "menu:settings:lose_sponge_on_use": "Perdi spugna con l'utilizzo", + + "menu:settings:healing": "Cura", + "menu:settings:healing_requires_item": "Curare richiede l'item", + "menu:settings:healing_item_name": "ID item benda", + "menu:settings:lose_bandage_on_use": "Perdi benda con l'utilizzo", + + "menu:settings:reviving": "Rianimazione", + "menu:settings:reviving_requires_item": "Rianimare richiede l'item", + "menu:settings:reviving_item_name": "ID item medikit", + "menu:settings:lose_medikit_on_use": "Perdi medikit con l'utilizzo", + + "menu:settings:enable_property_outfits": "Abilita gli outifts delle proprietà", + + "menu:settings:apply_changes": "Applica modifiche", + "menu:settings:restore_default_config": "Reimposta impostazioni predefinite", + "menu:are_you_sure_to_restore_settings": "Sei sicuro di voler reimpostare le impostazioni predefinite?", + + "menu:items_dialog:title": "Lista items", + "menu:items_dialog:search_item": "Cerca item", + + "menu:weapons_dialog:title": "Lista armi", + "menu:weapons_dialog:search_weapon": "Cerca arma", + + "menu:dialog:choose_item": "Scegli item", + "menu:dialog:choose_weapon": "Scegli weapon", + + "menu:settings:actions_menu_key": "Tasto per aprire menù azioni" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/pl.json b/resources/[creators]/jobs_creator/html/menu_translations/pl.json new file mode 100644 index 0000000..560bda2 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/pl.json @@ -0,0 +1,414 @@ +{ + "menu:jobs": " Prace", + "menu:public_markers": " Publiczne znaczniki", + "menu:statistics": " Statystyki", + "menu:settings": " Ustawienia", + + "menu:create_new_job": "Stwórz nową prace", + + "menu:job_label": "Nazwa pracy", + "menu:job_id": "ID pracy", + "menu:ranks": "Rangi", + + "menu:create_new_marker": "Stwórz nowy znacznik", + + "menu:marker:id": "ID", + "menu:marker:label": "Nazwa", + "menu:marker:type": "Typ", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Minimalna ranga", + + "menu:online_players": "Gracze online", + "menu:total_players": "Ogólna liczba graczy", + "menu:society_money": "Pieniądze z salda", + + "menu:job:ranks": " Rangi", + "menu:job:markers": " Znaczniki", + "menu:job:statistics": " Statystyki", + "menu:job:settings": " Ustawienia", + + "menu:create_new_rank": "Stwórz nową range", + + "menu:rank:id": "ID", + "menu:rank:label": "Oznakowanie", + "menu:rank:name": "Nazwa", + "menu:rank:grade": "Stopień", + "menu:rank:salary": "Wynagrodzenie", + + "menu:job_settings:whitelisted": "Dodany", + "menu:job_settings:enable_billing": "Włącz rozliczanie", + "menu:job_settings:enable_search_players": "Włącz okradanie/przeszukiwanie graczy", + "menu:job_settings:enable_handcuff_players": "Włącz zakuwanie graczy", + "menu:job_settings:enable_lockpick_players": "Włącz otwieranie za pomocą wytrycha pojazdów", + "menu:job_settings:enable_wash_vehicles": "Włącz mycie pojazdów", + "menu:job_settings:enable_repair_vehicles": "Włącz naprawianie pojazdów", + "menu:job_settings:enable_impound_vehicles": "Włącz odholowanie pojazdów", + "menu:job_settings:enable_check_identities": "Włącz identyfikatory kontrolne", + "menu:job_settings:enable_check_vehicle_owner": "Włącz sprawdzanie właściciela pojazdów", + "menu:job_settings:enable_check_driving_license": "Włącz sprawdzanie prawa jazdy", + "menu:job_settings:enable_check_weapon_license": "Włącz sprawdzanie licencji na broń", + "menu:job_settings:enable_heal": "Włącz leczenie", + "menu:job_settings:enable_revive": "Włącz podnoszenie", + + "menu:job_settings:delete_job": "Usuń prace", + "menu:job_settings:save_changes": "Zapisz zmiany", + + "menu:rank_creation:create_rank": "Stwórz range", + "menu:rank_creation:label": "Oznakowanie", + "menu:rank_creation:name": "Nazwa (id)", + "menu:rank_creation:grade": "Stopień", + "menu:rank_creation:salary": "Wynagrodzenie", + "menu:rank_creation:close": "Zamknij", + "menu:rank_creation:create": "Otwórz", + + "menu:rank_edit:edit": "Zmień range", + "menu:rank_edit:label": "Oznakowanie", + "menu:rank_edit:name_id": "Nazwa (id)", + "menu:rank_edit:grade": "Stopień", + "menu:rank_edit:salary": "Wynagrodzenie", + "menu:rank_edit:delete": "Usuń", + "menu:rank_edit:close": "Zamknij", + "menu:rank_edit:save": "Zapisz", + + "menu:delete_dialog:delete": "Usuń", + "menu:delete_dialog:close": "Zamknij", + + "menu:edit_marker:edit_marker": "Zmień znacznik", + "menu:edit_marker:label": "Oznakowanie", + "menu:edit_marker:marker_type": "Typ znacznika", + "menu:edit_marker:minimum_grade": "Minimalny stopień", + "menu:edit_marker:specific_grades": "Specificzne stopnie", + "menu:edit_marker:choose_grades": "Wybierz stopnie", + "menu:edit_marker:use_minimum_grade": "Użyj minimalny stopień", + "menu:edit_marker:use_specific_grades": "Użyj specyficznych stopni", + "menu:edit_marker:marker_size": "Wielkość znacznika", + "menu:edit_marker:scale_x": "Skala X", + "menu:edit_marker:scale_y": "Skala Y", + "menu:edit_marker:scale_z": "Skala Z", + "menu:edit_marker:marker_coordinates": "Koordynaty znacznika", + "menu:edit_marker:coord_x": "Koordynat X", + "menu:edit_marker:coord_y": "Koordynat Y", + "menu:edit_marker:coord_z": "Koordynat Z", + "menu:edit_marker:current_coords": "Aktualne koordynaty", + "menu:edit_marker:marker_color": "Kolor znacznika", + "menu:edit_marker:marker_opacity": "Przejrzystość znacznika", + "menu:edit_marker:map_blip": "Blip na mapie", + "menu:edit_marker:blip_sprite": "Ikona", + "menu:edit_marker:blip_color": "Kolor", + "menu:edit_marker:blip_scale": "Skala", + "menu:edit_marker:standing_npc": "Stojący NPC", + "menu:edit_marker:npc_model": "Model", + "menu:edit_marker:npc_heading": "Skierowanie", + "menu:edit_marker:object": "Obiekt", + "menu:edit_marker:object_model": "Model", + "menu:edit_marker:object_rotation_pitch": "Nachylenie", + "menu:edit_marker:object_rotation_roll": "Przechylenie", + "menu:edit_marker:object_rotation_yaw": "Odchylenie", + + "menu:grades_dialog:title": "Stopnie pracy", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Miejsce spawnu pojazdu", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Skierowanie miejsca spawna", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Aktualne koordynaty i skierowanie", + "menu:edit_marker:temporary_garage:vehicle_model": "Model pojazdu", + "menu:edit_marker:temporary_garage:vehicle_name": "Nazwa pojazdu", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Kolor podstawowy", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Kolor dodatkowy", + "menu:edit_marker:temporary_garage:vehicle_plate": "Rejestracja", + "menu:edit_marker:temporary_garage:delete": "Usuń", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Nowy model pojazdu", + "menu:edit_marker:temporary_garage:cant_be_empty": "Nie może być puste", + "menu:edit_marker:temporary_garage:add_vehicle": "Dodaj pojazd", + + "menu:edit_marker:boss:can_wash_money": "Może prać pieniądze?", + "menu:edit_marker:boss:return_percentage_after_wash": "Zwróć procent po wypraniu", + "menu:edit_marker:boss:add_money_to_society_account": "Dodaj pieniądze do salda konta", + "menu:edit_marker:boss:can_withdraw_money": "Może wypłacać pieniądze?", + "menu:edit_marker:boss:can_deposit_money": "Może wpłacać pieniądze?", + "menu:edit_marker:boss:can_manage_employees": "Może zarządzać pracownikami?", + "menu:edit_marker:boss:can_manage_wages": "Może zarządzać wynagrodzeniami/stopniami?", + "menu:edit_marker:boss:maximum_salary": "Maksymalne wynagrodzenie", + + "menu:edit_marker:shop:add_to_shop": "Dodaj do sklepu", + "menu:edit_marker:shop:item_id": "ID przedmiotu", + "menu:edit_marker:shop:item_price": "Cena przedmiotu", + "menu:edit_marker:shop:black_money": "Brudna gotówka", + "menu:edit_marker:shop:remove_item": "Usuń przedmiot", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Miejsce spawnu pojazdu", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Skierowanie miejsca spawnu", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Aktualne koordynaty i skierowanie", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Nowy model pojazdu", + "menu:edit_marker:garage_buyable:add_vehicle": "Dodaj pojazd", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Miejsce spawnu pojazdu", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Skierowanie miejsca spawnu", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Aktualne koordynaty i skierowanie", + + "menu:edit_marker:crafting_table:create_new_craft": "Stwórz nowy rzemiosło", + + "menu:edit_marker:armory:is_armory_shared": "Czy zbrojownia jest wspólna?", + "menu:edit_marker:armory:max_ammo_when_take": "Maksymalna amunicja przy wyciąganiu?", + "menu:edit_marker:armory:delete_armory_content": "Usuń zawartość zbrojowni", + + "menu:edit_marker:stash:delete_stash_content": "Usuń zawartość szafki", + + "menu:edit_marker:job_outfit:create_new_outfit": "Stwórz nowy strój", + + "menu:edit_marker:teleport:teleport_to": "Teleportuj do", + "menu:edit_marker:teleport:current_coords": "Aktualne koordynaty", + + "menu:edit_marker:market:item_id": "ID przedmiotu", + "menu:edit_marker:market:item_min_price": "Minimalna cena przedmiotu", + "menu:edit_marker:market:item_max_price": "Maksymalna cena przedmiotu", + "menu:edit_marker:market:black_money": "Brudna gotówka?", + "menu:edit_marker:market:time_to_sell": "Czas na sprzedaż", + "menu:edit_marker:market:remove": "Usuń", + "menu:edit_marker:market:add_item": "Dodaj przedmiot", + "menu:edit_marker_market:society_percentage": "Procent, który otrzyma praca", + + "menu:edit_marker:harvest:requires_a_tool": "Potrzebne narzędzie?", + "menu:edit_marker:harvest:tool_to_harvest": "Narzędzie do zbierania", + "menu:edit_marker:harvest:lose_on_use": "Strać przy użyciu", + "menu:edit_marker:harvest:quantity_to_lose": "Ilość do stracenia", + "menu:edit_marker:harvest:probability_to_lose": "Prawdopodobieństwo stracenia", + "menu:edit_marker:harvest:disappear_after_use": "Zniknij po użyciu", + "menu:edit_marker:harvest:disappear_seconds": "Znikanie sekund", + "menu:edit_marker:harvest:animations": "Animacje", + "menu:edit_marker:harvest:add_item": "Dodaj przedmiot", + + "menu:edit_marker:process:remove_item": "Usuń przedmiot", + "menu:edit_marker:process:give_item": "Daj przedmiot", + "menu:edit_marker:process:time_to_process": "Czas do produkcji", + "menu:edit_marker:process:animations": "Animacje", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Powiększony magazynek", + "menu:edit_marker:weapon_upgrader:drum_clip": "Magazynek bębenkowy", + "menu:edit_marker:weapon_upgrader:flashlight": "Latarka", + "menu:edit_marker:weapon_upgrader:suppressor": "Tłumik", + "menu:edit_marker:weapon_upgrader:scope": "Celownik", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Zaawansowany celownik", + "menu:edit_marker:weapon_upgrader:grip": "Uchwyt", + "menu:edit_marker:weapon_upgrader:box_clip": "Magazynek pudełkowy", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Wykończenie luksusowe", + "menu:edit_marker:weapon_upgrader:default_tint": "Podstawowa barwa", + "menu:edit_marker:weapon_upgrader:green_tint": "Zielona barwa", + "menu:edit_marker:weapon_upgrader:gold_tint": "Złota barwa", + "menu:edit_marker:weapon_upgrader:pink_tint": "Różowa barwa", + "menu:edit_marker:weapon_upgrader:army_tint": "Wojskowa barwa", + "menu:edit_marker:weapon_upgrader:lspd_tint": "Policyjna barwa", + "menu:edit_marker:weapon_upgrader:orange_tint": "Pomarańczowa barwa", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platinowa barwa", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Praca, w której można wystawiać produkty na sprzedaż", + "menu:edit_marker:job_shop:allowed_job": "Pozwolenie na sprzedaż pracy", + "menu:edit_marker:job_shop:minimum_grade": "Minimalny stopień dopuszczony do sprzedaży", + + "menu:edit_marker:delete_marker": "Usuń znacznik", + "menu:edit_marker:close": "Zamknij", + "menu:edit_marker:save": "Zapisz", + + "menu:input_text:close": "Zamknij", + "menu:input_text:confirm": "Akceptuj", + + "menu:notification:notification": "Powiadomienie", + "menu:notification:close": "Zamknij", + + "menu:not_allowed:you_are_not_allowed": "Nie jesteś upoważniony by używać tego menu", + "menu:not_allowed:if_you_are_admin": "Jeśli jesteś administratorem serwera, musisz dodać uprawnienie ACE do pliku server.cfg", + + "menu:animations:animations": "Animacje", + "menu:animations:add_animation": "Dodaj animacje", + "menu:animations:close": "Zamknij", + "menu:animations:save": "Zapisz", + + "menu:dynamic:create_new_job": "Stwórz nową prace", + "menu:dynamic:new_job_label": "Nowe oznakowanie pracy:", + "menu:dynamic:new_job_name": "Nowa nazwa pracy (id):", + + "menu:dynamic:delete_job_confirm": "Czy jesteś pewny, że chcesz usunąć tą pracę?", + + "menu:dynamic:job_markers:create_marker": "Stwórz znacznik", + "menu:dynamic:job_markers:label": "Oznakowanie", + "menu:dynamic:job_markers:coord_x": "Koordynat X", + "menu:dynamic:job_markers:coord_y": "Koordynat Y", + "menu:dynamic:job_markers:coord_z": "Koordynat Z", + "menu:dynamic:job_markers:current_coords": "Aktualne koordynaty", + "menu:dynamic:job_markers:min_grade": "Minimalny stopień", + + "menu:dynamic:public_markers:create_public_marker": "Stwórz znacznik publiczny", + "menu:dynamic:public_markers:label": "Oznakowanie", + "menu:dynamic:public_markers:coord_x": "Koordynat X", + "menu:dynamic:public_markers:coord_y": "Koordynat Y", + "menu:dynamic:public_markers:coord_z": "Koordynat Z", + "menu:dynamic:public_markers:current_coords": "Aktualne koordynaty", + + "menu:dynamic:harvest:name": "Nazwa (ID)", + "menu:dynamic:harvest:min_quantity": "Minimalna ilość", + "menu:dynamic:harvest:max_quantity": "Maximalna ilość", + "menu:dynamic:harvest:time_to_harvest": "Czas do zebrania (sekundy)", + "menu:dynamic:harvest:probabilty": "Prawdopodobieństwo znalezienia", + + "menu:dynamic:default": "Podstawowy", + + "menu:dynamic:animations:animation_dictionary": "Słownik animacji:", + "menu:dynamic:animations:animation_name": "Nazwa animacji:", + "menu:dynamic:animations:animation_duration": "Czas animacji (sekundy):", + "menu:dynamic:animations:scenario_name": "Nazwa scenariusza", + "menu:dynamic:animations:scenario_duration": "Czas scenariusza (sekundy):", + "menu:dynamic:animations:remove": "Usuń", + + "menu:dynamic:marker_info:stash": "Szafka", + "menu:dynamic:marker_info:stash_settings": "Ustawienia szafki", + "menu:dynamic:marker_info:armory": "Zbrojownia", + "menu:dynamic:marker_info:armory_settings": "Ustawienia zbrojowni", + "menu:dynamic:marker_info:safe": "Sejf", + "menu:dynamic:marker_info:temporary_garage": "Garaż - Pojazdy tymczasowe", + "menu:dynamic:marker_info:temporary_garage_settings": "Ustawienia garażu", + "menu:dynamic:marker_info:garage_buyable": "Garaż - Pojazdy do kupienia", + "menu:dynamic:marker_info:garage_buyable_settings": "Ustawienia garażu", + "menu:dynamic:marker_info:garage_owned": "Posiadane pojazdy", + "menu:dynamic:marker_info:garage_owned_settings": "Ustawienia garażu", + "menu:dynamic:marker_info:boss": "Menu szefa", + "menu:dynamic:marker_info:boss_settings": "Ustawienia menu szefa", + "menu:dynamic:marker_info:wardrobe": "Szafa - Zapisane stroje gracza", + "menu:dynamic:marker_info:job_outfit": "Strój roboczy", + "menu:dynamic:marker_info:job_outfit_settings": "Stroje", + "menu:dynamic:marker_info:shop": "Sklep (Kup przedmioty)", + "menu:dynamic:marker_info:shop_settings": "Przedmioty w sklepie", + "menu:dynamic:marker_info:market": "Market (sprzedaj przedmioty)", + "menu:dynamic:marker_info:market_settings": "Przedmioty w markecie", + "menu:dynamic:marker_info:harvest": "Punkt zbierania", + "menu:dynamic:marker_info:harvest_settings": "Przedmioty do zebrania", + "menu:dynamic:marker_info:process": "Punkt przetwarzania", + "menu:dynamic:marker_info:process_settings": "Przedmiot do wytwarzania", + "menu:dynamic:marker_info:crafting_table": "Stół rzemieślniczy", + "menu:dynamic:marker_info:crafting_table_settings": "Receptura tworzenia", + "menu:dynamic:marker_info:teleport": "Punkt teleportacji", + "menu:dynamic:marker_info:teleport_settings": "Ustawienia teleportu", + "menu:dynamic:marker_info:weapon_upgrader": "Ulepszacz broni", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Cena dodatków/barw", + "menu:dynamic:marker_info:duty": "Wejdź/zejdź na/ze służbe/y", + "menu:dynamic:marker_info:job_shop": "Sklep pracy", + "menu:dynamic:marker_info:job_shop_settings": "Ustawienia sklepu", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Czas na stworzenie (sekundy)", + "menu:dynamic:marker:crafting_table:result_item": "Przedmiot wykonany", + "menu:dynamic:marker:crafting_table:quantity": "Ilość", + "menu:dynamic:marker:crafting_table:item_id": "ID przedmiotu", + "menu:dynamic:marker:crafting_table:item_quantity": "Ilość przedmiotów", + "menu:dynamic:marker:crafting_table:lose_on_use": "Strać przy użyciu", + "menu:dynamic:marker:crafting_table:remove": "Usuń", + "menu:dynamic:marker:crafting_table:animations": "Animacje", + "menu:dynamic:marker:crafting_table:add_to_craft": "Dodaj do wytworzenia", + "menu:dynamic:marker:crafting_table:remove_craft": "Usuń wytworzenie", + + "menu:dynamic:marker:temporary_garage:delete": "Usuń", + "menu:dynamic:marker:temporary_garage:random_plate": "Losowe rejestracje", + + "menu:datatable:lengthMenu": "Pokaż _MENU_ wyników", + "menu:datatable:zeroRecords": "Brak wyników", + "menu:datatable:info": "Pokazywanie _PAGE_ z _PAGES_", + "menu:datatable:infoEmpty": "Brak aktualnych wyników", + "menu:datatable:infoFiltered": "(Przefiltrowane z _MAX_ wyników)", + "menu:datatable:search": "Szukaj:", + "menu:datatable:next": "Następny", + "menu:datatable:previous": "Poprzedni", + + "menu:chart:players_in_rank": "Gracze na rangach", + + "menu:settings:player_menu_position": "Menu pozycji gracza", + "menu:settings:player_menu_position:bottom_right": "Prawy róg", + "menu:settings:player_menu_position:top_right": "Prawy górny", + "menu:settings:player_menu_position:right": "Prawy", + "menu:settings:player_menu_position:bottom_left": "Lewy dolny", + "menu:settings:player_menu_position:top_left": "Lewy górny", + "menu:settings:player_menu_position:left": "Lewy", + "menu:settings:max_distance_marker": "Maksymalna odległość, z jakiej widoczny jest znacznik", + "menu:settings:use3Dtext": "Użyj tekstu 3D zamiast znacznika", + "menu:settings:text_size": "Rozmiar tekstu", + "menu:settings:font_to_use": "Czcionka do użycia", + "menu:settings:seconds_to_lockpick_car": "Sekundy na otwarcie wytrychem samochodu", + "menu:settings:vehicle_alarm": "Czy pojazd powinien być wyposażony w alarm podczas otwierania wytrychem?", + "menu:settings:jsfour_idcard": "Użyj skryptu jsfour-idcard (jeśli go posiadasz), aby wyświetlić docelowy dowód osobisty w akcji sprawdzania tożsamości/prawa jazdy/licencji na broń", + "menu:settings:can_use_actions_off_duty": "Czy gracz może korzystać z menu akcji F6, gdy jest poza służbą?", + "menu:settings:car_driving_licenses_ids": "Prawo jazdy ", + "menu:settings:weapon_licenses_ids": "Licencja na broń", + "menu:settings:new_driving_license": "Nowe prawo jazdy", + "menu:settings:add": "Dodaj", + "menu:settings:new_weapon_license": "Nowa licencja na broń", + "menu:settings:can_sell_multiple_items": "Czy na rynku można sprzedawać wiele przedmiotów jednocześnie?", + "menu:settings:language": "Język", + "menu:settings:allow_afk_farming": "Włącz automatyczny zbiór i przetwarzanie znaczników rolniczych", + "menu:settings:unemployed_job_id": "ID bezrobotnego", + "menu:settings:unemployed_job_grade": "Stopień bezrobotnego", + "menu:settings:ace_permission": "ACE permisje", + + "menu:settings:enable_discord_logs": "Włącz logi discord", + "menu:settings:discord_webhooks": "Discord webhooki", + "menu:settings:main_webhook": "Główny webhook", + "menu:settings:separated_webhooks": "Oddzielne webhooki", + + "menu:settings:handcuffs_requires_item": "Przedmiot potrzebny do zakuwania", + "menu:settings:handcuffs_item_name": "Nazwa przedmiotu do zakuwania", + "menu:settings:freeze_when_handcuffed": "Zatrzymaj gdy osoba jest zakuta", + + "menu:settings:lockpick_requires_item": "Przedmiot do włamania się wytrychem do pojazdu", + "menu:settings:lockpick_item_name": "Nazwa przedmiotu do włamywania się wytrychem", + "menu:settings:lockpickRemoveOnUse": "Strać wytrych przy użyciu", + + "menu:settings:robbable_accounts": "Konta do okradania", + "menu:settings:new_robbable_account": "Nowe konto", + "menu:settings:canAlwaysCarryItem": "Może zawsze nosić przedmioty", + "menu:settings:accounts_depositable_in_safe": "Konta zdeponowane do sejfu", + "menu:settings:enable_cash_in_safes_old_esx": "Włączanie sejfu dla starej wersji ESX", + + "menu:settings:vehicle_reparation": "Naprawa pojazdów", + "menu:settings:repair_vehicle_requires_item": "Przedmiot potrzebny do naprawy pojazdu", + "menu:settings:repair_vehicle_item_name": "nazwa zestawu naprawczego", + "menu:settings:lose_fixkit_on_use": "Strać zestaw naprawczy po użyciu", + + "menu:settings:vehicle_cleaning": "Mycie pojazdu", + "menu:settings:clean_vehicle_requires_item": "Przedmiot potrzebny do mycia", + "menu:settings:clean_vehicle_item_name": "Nazwa gąbki", + "menu:settings:lose_sponge_on_use": "Strać gąbkę po użyciu", + + "menu:settings:healing": "Leczenie", + "menu:settings:healing_requires_item": "Przedmiot potrzebny do leczenia", + "menu:settings:healing_item_name": "Nazwa bandaża", + "menu:settings:lose_bandage_on_use": "Strać bandaż po użyciu", + + "menu:settings:reviving": "Podnoszenie", + "menu:settings:reviving_requires_item": "Przedmiot potrzebny do podnoszenia", + "menu:settings:reviving_item_name": "Nazwa zestawu medycznego", + "menu:settings:lose_medikit_on_use": "Strać zestaw medyczny po użyciu", + + "menu:settings:enable_property_outfits": "Włącz stroje z magazynu danych właściwości w znaczniku szafy", + + "menu:settings:apply_changes": "Zaaplikuj zmiany", + "menu:settings:restore_default_config": "Przywróć konfiguracje domyślną", + "menu:are_you_sure_to_restore_settings": "Czy jesteś pewny że chcesz przywrócić konfiguracje domyślną?", + + "menu:items_dialog:title": "Lista przedmiotów", + "menu:items_dialog:search_item": "Szukaj przedmiotu", + + "menu:weapons_dialog:title": "Lista broni", + "menu:weapons_dialog:search_weapon": "Szukaj broni", + + "menu:dialog:choose_item": "Wybierz przedmiot", + "menu:dialog:choose_weapon": "Wybierz broń", + + "menu:settings:actions_menu_key": "Przycisk do otwierania menu akcji", + + "menu:settings:park_all_owned_vehicles_on_restart": "Zaparkuj wszystkie posiadane pojazdy na czas restartu", + + "menu:account_name": "Nazwa konta", + "menu:accounts_dialog:title": "Lista kont", + "menu:minimum_amount": "Minimalna liczba", + + "menu:edit_marker:requires_minimum_account_money": "Potrzebuje minimalną liczbę pieniędzy na koncie?", + + "menu:actions": "Actions" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/pt.json b/resources/[creators]/jobs_creator/html/menu_translations/pt.json new file mode 100644 index 0000000..9da8615 --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/pt.json @@ -0,0 +1,398 @@ +{ + "menu:jobs": " Trabalhos", + "menu:public_markers": " Marcadores publicos", + "menu:statistics": " Estatistica", + "menu:settings": " Definiçoes", + + "menu:create_new_job": "Criar novo trabalho", + + "menu:job_label": "Rotulo Trabalho", + "menu:job_id": "ID Trabalho", + "menu:ranks": "Postos", + + "menu:create_new_marker": "Criar Marcador", + + "menu:marker:id": "ID", + "menu:marker:label": "Posto", + "menu:marker:type": "tipo", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Posto minimo", + + "menu:online_players": "Jogadores", + "menu:total_players": "Total Jogadores", + "menu:society_money": "Dinheiro da sociedade", + + "menu:job:ranks": " Postos", + "menu:job:markers": " mMrcadores", + "menu:job:statistics": " Estatisticas", + "menu:job:settings": " Definicçoes", + + "menu:create_new_rank": "Criar novo ranck", + + "menu:rank:id": "ID", + "menu:rank:label": "posto", + "menu:rank:name": "Nome", + "menu:rank:grade": "Categoria", + "menu:rank:salary": "Salario", + + "menu:job_settings:whitelisted": "Lista Branca", + "menu:job_settings:enable_billing": "Habilitar faturamento", + "menu:job_settings:enable_search_players": "Habilitar roubar / pesquisar jogadores", + "menu:job_settings:enable_handcuff_players": "Habilitar algemas de jogadores", + "menu:job_settings:enable_lockpick_players": "Habilitar carros lockpick", + "menu:job_settings:enable_wash_vehicles": "Habilitar lavar veiculos", + "menu:job_settings:enable_repair_vehicles": "Habilitar reparar veiculos", + "menu:job_settings:enable_impound_vehicles": "Habilitar apreender veiculos", + "menu:job_settings:enable_check_identities": "Habilitar verificar identidade", + "menu:job_settings:enable_check_vehicle_owner": "Habilitar verificar dono veiculo", + "menu:job_settings:enable_check_driving_license": "Habilitar verificar carta conduçao", + "menu:job_settings:enable_check_weapon_license": "Habilitar verificar porte armas", + "menu:job_settings:enable_heal": "Ativar curar", + "menu:job_settings:enable_revive": "Ativar reviver", + + "menu:job_settings:delete_job": "Apagar Trabalho", + "menu:job_settings:save_changes": "Salvar", + + "menu:rank_creation:create_rank": "Criar ranck", + "menu:rank_creation:label": "Posto", + "menu:rank_creation:name": "Nome (id)", + "menu:rank_creation:grade": "Categoria", + "menu:rank_creation:salary": "Salario", + "menu:rank_creation:close": "Fechar", + "menu:rank_creation:create": "Criar", + + "menu:rank_edit:edit": "Editar rack", + "menu:rank_edit:label": "Posto", + "menu:rank_edit:name_id": "Nome (id)", + "menu:rank_edit:grade": "Categoria", + "menu:rank_edit:salary": "Salario", + "menu:rank_edit:delete": "Apagar", + "menu:rank_edit:close": "Fechar", + "menu:rank_edit:save": "Salvar", + + "menu:delete_dialog:delete": "Apagar", + "menu:delete_dialog:close": "Fechar", + + "menu:edit_marker:edit_marker": "Editar Marcado", + "menu:edit_marker:label": "Posto", + "menu:edit_marker:marker_type": "Tipo de marcador", + "menu:edit_marker:minimum_grade": "Posto minimo", + "menu:edit_marker:specific_grades": "Posto espesifico", + "menu:edit_marker:choose_grades": "Escolher posto", + "menu:edit_marker:use_minimum_grade": "Usar posto minimo", + "menu:edit_marker:use_specific_grades": "Usar posto especifico", + "menu:edit_marker:marker_size": "Tamanho marcado", + "menu:edit_marker:scale_x": "tamanho X", + "menu:edit_marker:scale_y": "tamanho Y", + "menu:edit_marker:scale_z": "tamanho Z", + "menu:edit_marker:marker_coordinates": "Cordenadas marcador", + "menu:edit_marker:coord_x": "Coordenada X", + "menu:edit_marker:coord_y": "Coordenada Y", + "menu:edit_marker:coord_z": "Coordedana Z", + "menu:edit_marker:current_coords": "Cordenada atual", + "menu:edit_marker:marker_color": "Cor marcador", + "menu:edit_marker:marker_opacity": "Opacidade marcador", + "menu:edit_marker:map_blip": "Blip mapa", + "menu:edit_marker:blip_sprite": "forma", + "menu:edit_marker:blip_color": "Cor", + "menu:edit_marker:blip_scale": "escala", + "menu:edit_marker:standing_npc": "NPC", + "menu:edit_marker:npc_model": "Modelo", + "menu:edit_marker:npc_heading": "Cabeçalho", + "menu:edit_marker:object": "Objeto", + "menu:edit_marker:object_model": "Modelo", + "menu:edit_marker:object_rotation_pitch": "Pitch", + "menu:edit_marker:object_rotation_roll": "Roll", + "menu:edit_marker:object_rotation_yaw": "Yaw", + "menu:edit_marker:object_current_rotation": "Current rotation", + + "menu:grades_dialog:title": "categorias", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Ponto de Spawn de Veículo", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "ponto de graus", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Coordenadas e cabeçalho atuais", + "menu:edit_marker:temporary_garage:vehicle_model": "Modelo do veículo", + "menu:edit_marker:temporary_garage:vehicle_name": "Nome do veiculo", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "cor primaria", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "cor secundaria", + "menu:edit_marker:temporary_garage:vehicle_plate": "placa", + "menu:edit_marker:temporary_garage:delete": "apagar", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Novo modelo de veículo", + "menu:edit_marker:temporary_garage:cant_be_empty": "Não pode estar vazio", + "menu:edit_marker:temporary_garage:add_vehicle": "Adicionar veículo", + + "menu:edit_marker:boss:can_wash_money": "Pode lavar dinheiro?", + "menu:edit_marker:boss:return_percentage_after_wash": "Percentagem de retorno após lavagem", + "menu:edit_marker:boss:add_money_to_society_account": "Adicione dinheiro à conta da sociedade", + "menu:edit_marker:boss:can_withdraw_money": "Pode retirar dinheiro?", + "menu:edit_marker:boss:can_deposit_money": "Pode depositar dinheiro?", + "menu:edit_marker:boss:can_manage_employees": "Pode gerenciar funcionários?", + "menu:edit_marker:boss:can_manage_wages": "Pode gerenciar salários / notas?", + + "menu:edit_marker:shop:add_to_shop": "Adicionar a loja", + "menu:edit_marker:shop:item_id": "id item", + "menu:edit_marker:shop:item_price": "preço de item", + "menu:edit_marker:shop:black_money": "dinheiro sujo", + "menu:edit_marker:shop:remove_item": "Remover item", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Ponto de Spawn de Veículo", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Título do ponto de desova", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Coords e cabeçalho atuais", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Novo modelo de veículo", + "menu:edit_marker:garage_buyable:add_vehicle": "adicionar veiculo", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Ponto de Spawn de Veículo", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Título do ponto de desova", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Coords e cabeçalho atuais", + + "menu:edit_marker:crafting_table:create_new_craft": "criar novo craft", + + "menu:edit_marker:armory:is_armory_shared": "arsenal partilhado?", + "menu:edit_marker:armory:max_ammo_when_take": "Munição máxima quando pegar?", + "menu:edit_marker:armory:delete_armory_content": "Excluir o conteúdo do arsenal", + + "menu:edit_marker:stash:delete_stash_content": "Excluir conteúdo escondido", + + "menu:edit_marker:job_outfit:create_new_outfit": "Crie uma nova roupa", + + "menu:edit_marker:teleport:teleport_to": "Teleportar para", + "menu:edit_marker:teleport:current_coords": "Coords atuais", + + "menu:edit_marker:market:item_id": "ID item", + "menu:edit_marker:market:item_min_price": "Preço mínimo do item", + "menu:edit_marker:market:item_max_price": "Preço maximo do item", + "menu:edit_marker:market:black_money": "dinheiro sujo?", + "menu:edit_marker:market:time_to_sell": "tempo pra vender", + "menu:edit_marker:market:remove": "Removeer", + "menu:edit_marker:market:add_item": "adicionar item", + + "menu:edit_marker:harvest:requires_a_tool": "precisa ferramente?", + "menu:edit_marker:harvest:tool_to_harvest": "ferramenta para colher", + "menu:edit_marker:harvest:lose_on_use": "perder ao usar", + "menu:edit_marker:harvest:quantity_to_lose": "Quantidade ao perder", + "menu:edit_marker:harvest:probability_to_lose": "Probabilidade de perder", + "menu:edit_marker:harvest:disappear_after_use": "Disaparecer depois de usar", + "menu:edit_marker:harvest:disappear_seconds": "Disappear seconds", + "menu:edit_marker:harvest:animations": "animaçoes", + "menu:edit_marker:harvest:add_item": "Adicionar item", + + "menu:edit_marker:process:remove_item": "Remover item", + "menu:edit_marker:process:give_item": "Dar item", + "menu:edit_marker:process:time_to_process": "tempo de processo", + "menu:edit_marker:process:animations": "Animaçoes", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Extended Clip", + "menu:edit_marker:weapon_upgrader:drum_clip": "Drum Clip", + "menu:edit_marker:weapon_upgrader:flashlight": "Flashlight", + "menu:edit_marker:weapon_upgrader:suppressor": "Suppressor", + "menu:edit_marker:weapon_upgrader:scope": "Scope", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Advanced Scope", + "menu:edit_marker:weapon_upgrader:grip": "Grip", + "menu:edit_marker:weapon_upgrader:box_clip": "Box Clip", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Luxary Finish", + "menu:edit_marker:weapon_upgrader:default_tint": "Default tint", + "menu:edit_marker:weapon_upgrader:green_tint": "Green tint", + "menu:edit_marker:weapon_upgrader:gold_tint": "Gold tint", + "menu:edit_marker:weapon_upgrader:pink_tint": "Pink tint", + "menu:edit_marker:weapon_upgrader:army_tint": "Army tint", + "menu:edit_marker:weapon_upgrader:lspd_tint": "LSPD tint", + "menu:edit_marker:weapon_upgrader:orange_tint": "Orange tint", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platinum tint", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Trabalho que pode colocar itens à venda", + "menu:edit_marker:job_shop:allowed_job": "Trabalho permitido para vender", + "menu:edit_marker:job_shop:minimum_grade": "Categoria mínima permitida para vender", + + "menu:edit_marker:delete_marker": "Apagar marcador", + "menu:edit_marker:close": "fechar", + "menu:edit_marker:save": "salvar", + + "menu:input_text:close": "fechar", + "menu:input_text:confirm": "Confirmar", + + "menu:notification:notification": "Notificaçoes", + "menu:notification:close": "fechar", + + "menu:not_allowed:you_are_not_allowed": "Você não tem permissão para usar este menu", + "menu:not_allowed:if_you_are_admin": "Se você for um administrador de servidor, precisará adicionar permissão ACE ao seu server.cfg", + + "menu:animations:animations": "Animaçoes", + "menu:animations:add_animation": "adicionar animaçoes", + "menu:animations:close": "fechar", + "menu:animations:save": "salvar", + + "menu:dynamic:create_new_job": "Criar novo emprego", + "menu:dynamic:new_job_label": "Nova categoria de trabalho:", + "menu:dynamic:new_job_name": "Novo nome trabalho (id):", + + "menu:dynamic:delete_job_confirm": "Tem certeza que deseja deletar este trabalho?", + + "menu:dynamic:job_markers:create_marker": "criar marcador", + "menu:dynamic:job_markers:label": "rotulo", + "menu:dynamic:job_markers:coord_x": "Coord X", + "menu:dynamic:job_markers:coord_y": "Coord Y", + "menu:dynamic:job_markers:coord_z": "Coord Z", + "menu:dynamic:job_markers:current_coords": "cordenada atual", + "menu:dynamic:job_markers:min_grade": "categoria minima", + + "menu:dynamic:public_markers:create_public_marker": "criar marcador publico", + "menu:dynamic:public_markers:label": "rotulo", + "menu:dynamic:public_markers:coord_x": "Coord X", + "menu:dynamic:public_markers:coord_y": "Coord Y", + "menu:dynamic:public_markers:coord_z": "Coord Z", + "menu:dynamic:public_markers:current_coords": "cordenada atual", + + "menu:dynamic:harvest:name": "Nome (ID)", + "menu:dynamic:harvest:min_quantity": "quantidade minima", + "menu:dynamic:harvest:max_quantity": "quantidade maxima", + "menu:dynamic:harvest:time_to_harvest": "tempo para colher (segundos)", + "menu:dynamic:harvest:probabilty": "Probablidade de encontrar", + + "menu:dynamic:default": "Defaulte", + + "menu:dynamic:animations:animation_dictionary": "Dicionário de animação:", + "menu:dynamic:animations:animation_name": "Nome de animaçao:", + "menu:dynamic:animations:animation_duration": "Duraçao de animaçao (segundos):", + "menu:dynamic:animations:scenario_name": "Nome senario", + "menu:dynamic:animations:scenario_duration": "Duraçao senario (segundos):", + "menu:dynamic:animations:remove": "Remover", + + "menu:dynamic:marker_info:stash": "Armario", + "menu:dynamic:marker_info:stash_settings": "definiçoes do armario", + "menu:dynamic:marker_info:armory": "Arsenal", + "menu:dynamic:marker_info:armory_settings": "definiçoes do arsenal", + "menu:dynamic:marker_info:safe": "Cofre", + "menu:dynamic:marker_info:temporary_garage": "Garagem - veiculos temporarios", + "menu:dynamic:marker_info:temporary_garage_settings": "Definiçoes de garagem", + "menu:dynamic:marker_info:garage_buyable": "Garagem - Veiculos de compra", + "menu:dynamic:marker_info:garage_buyable_settings": "definiçoes de garagem", + "menu:dynamic:marker_info:garage_owned": "Veículos próprios", + "menu:dynamic:marker_info:garage_owned_settings": "Definiçoes de garagen", + "menu:dynamic:marker_info:boss": "Chefe", + "menu:dynamic:marker_info:boss_settings": "Definiçoes de chefe", + "menu:dynamic:marker_info:wardrobe": "Guarda-roupa - Roupas salvas pelo jogador", + "menu:dynamic:marker_info:job_outfit": "Roupa de trabalho", + "menu:dynamic:marker_info:job_outfit_settings": "Roupas", + "menu:dynamic:marker_info:shop": "Loja (comprar items)", + "menu:dynamic:marker_info:shop_settings": "Loja de items", + "menu:dynamic:marker_info:market": "mercado (vender items)", + "menu:dynamic:marker_info:market_settings": "Mercado items", + "menu:dynamic:marker_info:harvest": "Ponto para colher", + "menu:dynamic:marker_info:harvest_settings": "Items para colher", + "menu:dynamic:marker_info:process": "Ponto de porcesso", + "menu:dynamic:marker_info:process_settings": "Processar item", + "menu:dynamic:marker_info:crafting_table": "Mensa de craft", + "menu:dynamic:marker_info:crafting_table_settings": "Items para craft", + "menu:dynamic:marker_info:teleport": "Teleporte", + "menu:dynamic:marker_info:teleport_settings": "definiçoes de teleporte", + "menu:dynamic:marker_info:weapon_upgrader": "Melhorador de armas", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Preços de componentes / tintas", + "menu:dynamic:marker_info:duty": "On/Off serviço", + "menu:dynamic:marker_info:job_shop": "Loja trabalho", + "menu:dynamic:marker_info:job_shop_settings": "definiçao de loja", + + "menu:dynamic:marker:crafting_table:time_to_craft": "tempo para criar (segundos)", + "menu:dynamic:marker:crafting_table:result_item": "Item criado", + "menu:dynamic:marker:crafting_table:quantity": "Quantitade", + "menu:dynamic:marker:crafting_table:item_id": "Id item", + "menu:dynamic:marker:crafting_table:item_quantity": "Quantidade de item", + "menu:dynamic:marker:crafting_table:lose_on_use": "Perder ao usar", + "menu:dynamic:marker:crafting_table:remove": "Removeer", + "menu:dynamic:marker:crafting_table:animations": "Animaçoes", + "menu:dynamic:marker:crafting_table:add_to_craft": "adicionar ao craft", + "menu:dynamic:marker:crafting_table:remove_craft": "Remover craft", + + "menu:dynamic:marker:temporary_garage:delete": "Apagar", + "menu:dynamic:marker:temporary_garage:random_plate": "Placa aleatória", + + "menu:datatable:lengthMenu": "Mostrar _MENU_ resultados", + "menu:datatable:zeroRecords": "sem resultados", + "menu:datatable:info": "Mostrar _PAGINA_ de _PAGINAS_", + "menu:datatable:infoEmpty": "Nenhum resultado disponível", + "menu:datatable:infoFiltered": "(filtrar por _MAXIMO_ resultado)", + "menu:datatable:search": "Procurar:", + "menu:datatable:next": "proximo", + "menu:datatable:previous": "Anterior", + + "menu:chart:players_in_rank": "Jogadores na classificação", + + "menu:settings:player_menu_position": "Posição do menu do jogador", + "menu:settings:player_menu_position:bottom_right": "Canto inferior direito", + "menu:settings:player_menu_position:top_right": "Canto superior direito", + "menu:settings:player_menu_position:bottom_left": "Inferior esquerdo", + "menu:settings:player_menu_position:top_left": "Superior esquerdo", + "menu:settings:max_distance_marker": "Distância máxima onde o marcador pode ser visto", + "menu:settings:use3Dtext": "Use texto 3D em vez de marcadores", + "menu:settings:text_size": "Tamanho do texto", + "menu:settings:font_to_use": "Fonte para usar", + "menu:settings:seconds_to_lockpick_car": "Segundos para destarncar um carro", + "menu:settings:vehicle_alarm": "O veículo deve ter alarme ao selecionar o bloqueio?", + "menu:settings:jsfour_idcard": "Use o script jsfour-idcard (se tiver) para ver o cartão de identificação do alvo na ação de verificação de identidade / licença de veículo / licença de arma", + "menu:settings:can_use_actions_off_duty": "O jogador pode usar o menu de ações F6 quando está fora de serviço?", + "menu:settings:car_driving_licenses_ids": "IDs de carteiras de habilitação de carro", + "menu:settings:weapon_licenses_ids": "IDs de licenças de armas", + "menu:settings:new_driving_license": "Nova carteira de habilitação", + "menu:settings:add": "Adicionar", + "menu:settings:new_weapon_license": "Nova licença de arma", + "menu:settings:can_sell_multiple_items": "Pode vender vários itens de uma vez no mercado?", + "menu:settings:language": "Lingua", + "menu:settings:allow_afk_farming": "Habilitar colheita automática e cultivo de marcador de processo", + "menu:settings:unemployed_job_id": "ID de trabalho desempregado", + "menu:settings:unemployed_job_grade": "Grau de emprego desempregado", + "menu:settings:ace_permission": "Permissão ACE", + + "menu:settings:enable_discord_logs": "Habilitar registros de discord", + "menu:settings:discord_webhooks": "Webhooks do discord", + "menu:settings:main_webhook": "Webhook pincipal", + "menu:settings:separated_webhooks": "Webhooks separados", + + "menu:settings:handcuffs_requires_item": "Algemas requerem item", + "menu:settings:handcuffs_item_name": "Nome do item de algemas", + + "menu:settings:lockpick_requires_item": "Veículo lockpick requer item", + "menu:settings:lockpick_item_name": "Nome do item Lockpick", + "menu:settings:lockpickRemoveOnUse": "Perder lockpick em uso", + + "menu:settings:robbable_accounts": "Contas que podem ser roubadas", + "menu:settings:new_robbable_account": "Nova conta", + "menu:settings:canAlwaysCarryItem": "Sempre pode carregar itens", + "menu:settings:accounts_depositable_in_safe": "Contas depositáveis no cofre", + "menu:settings:enable_cash_in_safes_old_esx": "Habilitar cash in safe para a versão ESX antiga", + + "menu:settings:vehicle_reparation": "Reparação de veículos", + "menu:settings:repair_vehicle_requires_item": "Reparar o veículo requer item", + "menu:settings:repair_vehicle_item_name": "Nome do item do fixkit", + "menu:settings:lose_fixkit_on_use": "Perder o fixkit em uso", + + "menu:settings:vehicle_cleaning": "Limpeza de veículos", + "menu:settings:clean_vehicle_requires_item": "Veículo limpo requer item", + "menu:settings:clean_vehicle_item_name": "Nome do item esponja", + "menu:settings:lose_sponge_on_use": "Perder a esponja ao usar", + + "menu:settings:healing": "Cura", + "menu:settings:healing_requires_item": "A cura requer item", + "menu:settings:healing_item_name": "Nome do item da bandagem", + "menu:settings:lose_bandage_on_use": "Perder a bandagem ao usar", + + "menu:settings:reviving": "Reviver", + "menu:settings:reviving_requires_item": "Reviver requer item", + "menu:settings:reviving_item_name": "Medikit item nome", + "menu:settings:lose_medikit_on_use": "Perder medikit em uso", + + "menu:settings:enable_property_outfits": "Ativar roupas de armazenamento de dados de propriedade no marcador de guarda-roupa", + + "menu:settings:apply_changes": "Aplicar mudanças", + "menu:settings:restore_default_config": "Restaurar configuração padrão", + "menu:are_you_sure_to_restore_settings": "Tem certeza de que deseja restaurar as configurações padrão?", + + "menu:items_dialog:title": "Lista de itens", + "menu:items_dialog:search_item": "Item de pesquisa", + + "menu:weapons_dialog:title": "Lista de armas", + "menu:weapons_dialog:search_weapon": "Procurar armas", + + "menu:dialog:choose_item": "Escolher item", + "menu:dialog:choose_weapon": "Escolher arma" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/html/menu_translations/sk.json b/resources/[creators]/jobs_creator/html/menu_translations/sk.json new file mode 100644 index 0000000..05e3a5a --- /dev/null +++ b/resources/[creators]/jobs_creator/html/menu_translations/sk.json @@ -0,0 +1,412 @@ +{ + "menu:jobs": " Joby", + "menu:public_markers": " Verejne markery", + "menu:statistics": " Statistiky", + "menu:settings": " Nastavenia", + + "menu:create_new_job": "Vytvorit novy job", + + "menu:job_label": "Job popis", + "menu:job_id": "Job ID", + "menu:ranks": "Hodnosti", + + "menu:create_new_marker": "Vytovorit novy marker", + + "menu:marker:id": "ID", + "menu:marker:label": "Popis", + "menu:marker:type": "Typ", + "menu:marker:x": "X", + "menu:marker:y": "Y", + "menu:marker:z": "Z", + "menu:marker:minimum_grade": "Minimalna hodnost", + + "menu:online_players": "Online hraci", + "menu:total_players": "Vsetci hraci", + "menu:society_money": "Firemne peniaze", + + "menu:job:ranks": " Hodnosti", + "menu:job:markers": " Markery", + "menu:job:statistics": " Statistiky", + "menu:job:settings": " Nastavenia", + + "menu:create_new_rank": "Vytvorit novu hodnost", + + "menu:rank:id": "ID", + "menu:rank:label": "Popis", + "menu:rank:name": "Meno", + "menu:rank:grade": "Hodnost", + "menu:rank:salary": "Plat", + + "menu:job_settings:whitelisted": "Whitelisted Job", + "menu:job_settings:enable_billing": "Povolit faktury", + "menu:job_settings:enable_search_players": "Povolit okradanie a prehladavanie hracov", + "menu:job_settings:enable_handcuff_players": "Povolit putanie hracov", + "menu:job_settings:enable_lockpick_players": "Povolit vypacit zamok na vozidle", + "menu:job_settings:enable_wash_vehicles": "Povolit umyvanie vozidla", + "menu:job_settings:enable_repair_vehicles": "Povolit opravu vozidla", + "menu:job_settings:enable_impound_vehicles": "Povolit odtiahnut vozidlo", + "menu:job_settings:enable_check_identities": "Povolit zobrazenie ID", + "menu:job_settings:enable_check_vehicle_owner": "Povolit zobrazenie majitela vozidla", + "menu:job_settings:enable_check_driving_license": "Povolit zobrazenie vodicskeho preukazu", + "menu:job_settings:enable_check_weapon_license": "Povolot zobrazenie zbrojneho preukazu", + "menu:job_settings:enable_heal": "Povolit liecenie", + "menu:job_settings:enable_revive": "Povolit ozivovanie", + + "menu:job_settings:delete_job": "Vymazat job", + "menu:job_settings:save_changes": "Ulozit zmeny", + + "menu:rank_creation:create_rank": "Vytvorit hodnost", + "menu:rank_creation:label": "Popis", + "menu:rank_creation:name": "Meno (id)", + "menu:rank_creation:grade": "Hodnost", + "menu:rank_creation:salary": "Plat", + "menu:rank_creation:close": "Zatvorit", + "menu:rank_creation:create": "Vytvorit", + + "menu:rank_edit:edit": "Upravit hodnost", + "menu:rank_edit:label": "Popis", + "menu:rank_edit:name_id": "Meno (id)", + "menu:rank_edit:grade": "Hodnost", + "menu:rank_edit:salary": "Plat", + "menu:rank_edit:delete": "Vymazat", + "menu:rank_edit:close": "Zavri", + "menu:rank_edit:save": "Ulozit", + + "menu:delete_dialog:delete": "Vymazat", + "menu:delete_dialog:close": "Zavri", + + "menu:edit_marker:edit_marker": "Upravit marker", + "menu:edit_marker:label": "Popis", + "menu:edit_marker:marker_type": "Marker Typ", + "menu:edit_marker:minimum_grade": "Minimalna Hodnost", + "menu:edit_marker:specific_grades": "Specificka hodnost", + "menu:edit_marker:choose_grades": "Vybrat hodnost", + "menu:edit_marker:use_minimum_grade": "Pouzit minimalnu Hodnost", + "menu:edit_marker:use_specific_grades": "Pouzit specificku hodnost", + "menu:edit_marker:marker_size": "Marker velkost", + "menu:edit_marker:scale_x": "Scale X", + "menu:edit_marker:scale_y": "Scale Y", + "menu:edit_marker:scale_z": "Scale Z", + "menu:edit_marker:marker_coordinates": "Marker suradnice", + "menu:edit_marker:coord_x": "Coord X", + "menu:edit_marker:coord_y": "Coord Y", + "menu:edit_marker:coord_z": "Coord Z", + "menu:edit_marker:current_coords": "Aktualne suradnice", + "menu:edit_marker:marker_color": "Marker farba", + "menu:edit_marker:marker_opacity": "Marker vyraznost", + "menu:edit_marker:map_blip": "Map blip", + "menu:edit_marker:blip_sprite": "Sprite", + "menu:edit_marker:blip_color": "Color", + "menu:edit_marker:blip_scale": "Scale", + "menu:edit_marker:standing_npc": "Stojace NPC", + "menu:edit_marker:npc_model": "Model", + "menu:edit_marker:npc_heading": "Heading", + "menu:edit_marker:object": "Object", + "menu:edit_marker:object_model": "Model", + "menu:edit_marker:object_rotation_pitch": "Pitch", + "menu:edit_marker:object_rotation_roll": "Roll", + "menu:edit_marker:object_rotation_yaw": "Yaw", + + "menu:grades_dialog:title": "Job hodnosti", + + "menu:edit_marker:temporary_garage:vehicle_spawnpoint": "Vozidlo Spawnpoint", + "menu:edit_marker:temporary_garage:spawnpoint_heading": "Spawnpoint heading", + "menu:edit_marker:temporary_garage:current_cooords_and_heading": "Aktualne suradnice a heading", + "menu:edit_marker:temporary_garage:vehicle_model": "Vozidlo Model", + "menu:edit_marker:temporary_garage:vehicle_name": "Vozidlo Name", + "menu:edit_marker:temporary_garage:vehicle_primary_color": "Primarna Farba", + "menu:edit_marker:temporary_garage:vehicle_secondary_color": "Sekundarna Farba", + "menu:edit_marker:temporary_garage:vehicle_plate": "Znacka", + "menu:edit_marker:temporary_garage:delete": "Vymazat", + "menu:edit_marker:temporary_garage:new_vehicle_model": "Nove vozidlo model", + "menu:edit_marker:temporary_garage:cant_be_empty": "Nemoze byt prazdne", + "menu:edit_marker:temporary_garage:add_vehicle": "Pridat vozidlo", + + "menu:edit_marker:boss:can_wash_money": "Moze vyprat peniaze?", + "menu:edit_marker:boss:return_percentage_after_wash": "Precento navratnosti po vyprani", + "menu:edit_marker:boss:add_money_to_society_account": "Pridaj peniaze do firmy", + "menu:edit_marker:boss:can_withdraw_money": "Vybrat peniaze?", + "menu:edit_marker:boss:can_deposit_money": "Vlozit penmiaze?", + "menu:edit_marker:boss:can_manage_employees": "Upravovat zamestnancov?", + "menu:edit_marker:boss:can_manage_wages": "Uprava platu a hodnosti?", + "menu:edit_marker:boss:maximum_salary": "Maximalna vyplata", + + "menu:edit_marker:shop:add_to_shop": "Pridat do shopu", + "menu:edit_marker:shop:item_id": "Item ID", + "menu:edit_marker:shop:item_price": "Item Cena", + "menu:edit_marker:shop:black_money": "Spinave peniaze", + "menu:edit_marker:shop:remove_item": "Odstranit item", + + "menu:edit_marker:garage_buyable:vehicle_spawnpoint": "Vozidlo Spawnpoint", + "menu:edit_marker:garage_buyable:spawnpoint_heading": "Spawnpoint heading", + "menu:edit_marker:garage_buyable:current_cooords_and_heading": "Aktualne suradnice a heading", + "menu:edit_marker:garage_buyable:new_vehicle_model": "Nove vozidlo model", + "menu:edit_marker:garage_buyable:add_vehicle": "Pridaj vozidlo", + + "menu:edit_marker:garage_owned:vehicle_spawnpoint": "Vozidlo Spawnpoint", + "menu:edit_marker:garage_owned:spawnpoint_heading": "Spawnpoint heading", + "menu:edit_marker:garage_owned:current_cooords_and_heading": "Aktualne suradnice a heading", + + "menu:edit_marker:crafting_table:create_new_craft": "Vytvorit craftenie", + + "menu:edit_marker:armory:is_armory_shared": "Zdielana zbrojnica?", + "menu:edit_marker:armory:max_ammo_when_take": "Maximalna municia pri vybere?", + "menu:edit_marker:armory:delete_armory_content": "Vymazat obsah zbrojnice", + + "menu:edit_marker:stash:delete_stash_content": "Vymazat obsah ", + + "menu:edit_marker:job_outfit:create_new_outfit": "Vytvorit novy outfit", + + "menu:edit_marker:teleport:teleport_to": "Teleport na", + "menu:edit_marker:teleport:current_coords": "Aktualne suradnice", + + "menu:edit_marker:market:item_id": "Item ID", + "menu:edit_marker:market:item_min_price": "Item minimalna cena", + "menu:edit_marker:market:item_max_price": "Item maximalna cena", + "menu:edit_marker:market:black_money": "Spinave peniaze?", + "menu:edit_marker:market:time_to_sell": "Cas predaja", + "menu:edit_marker:market:remove": "Odstranit", + "menu:edit_marker:market:add_item": "Pridat item", + "menu:edit_marker_market:society_percentage": "Percento, ktore dostane frakcia", + + "menu:edit_marker:harvest:requires_a_tool": "Potrebny nastroj?", + "menu:edit_marker:harvest:tool_to_harvest": "Nastroj na zber", + "menu:edit_marker:harvest:lose_on_use": "Strata pri pouziti", + "menu:edit_marker:harvest:quantity_to_lose": "Mnozstvo", + "menu:edit_marker:harvest:probability_to_lose": "Pravdepodobnost straty", + "menu:edit_marker:harvest:disappear_after_use": "Po pouziti zmizne", + "menu:edit_marker:harvest:disappear_seconds": "Zmniznut sekundy", + "menu:edit_marker:harvest:animations": "Animacie", + "menu:edit_marker:harvest:add_item": "Pridat item", + + "menu:edit_marker:process:remove_item": "Odstranit item", + "menu:edit_marker:process:give_item": "Dat item", + "menu:edit_marker:process:time_to_process": "Cas procesu", + "menu:edit_marker:process:animations": "Animacie", + + "menu:edit_marker:weapon_upgrader:extended_clip": "Extended Clip", + "menu:edit_marker:weapon_upgrader:drum_clip": "Drum Clip", + "menu:edit_marker:weapon_upgrader:flashlight": "Flashlight", + "menu:edit_marker:weapon_upgrader:suppressor": "Suppressor", + "menu:edit_marker:weapon_upgrader:scope": "Scope", + "menu:edit_marker:weapon_upgrader:advanced_scope": "Advanced Scope", + "menu:edit_marker:weapon_upgrader:grip": "Grip", + "menu:edit_marker:weapon_upgrader:box_clip": "Box Clip", + "menu:edit_marker:weapon_upgrader:luxary_finish": "Luxary Finish", + "menu:edit_marker:weapon_upgrader:default_tint": "Default tint", + "menu:edit_marker:weapon_upgrader:green_tint": "Green tint", + "menu:edit_marker:weapon_upgrader:gold_tint": "Gold tint", + "menu:edit_marker:weapon_upgrader:pink_tint": "Pink tint", + "menu:edit_marker:weapon_upgrader:army_tint": "Army tint", + "menu:edit_marker:weapon_upgrader:lspd_tint": "LSPD tint", + "menu:edit_marker:weapon_upgrader:orange_tint": "Orange tint", + "menu:edit_marker:weapon_upgrader:platinum_tint": "Platinum tint", + + "menu:edit_marker:job_shop:job_allowed_to_sell": "Job ktory moze predavat veci", + "menu:edit_marker:job_shop:allowed_job": "Povolene joby predaja", + "menu:edit_marker:job_shop:minimum_grade": "Minimalna hodnost", + + "menu:edit_marker:delete_marker": "Vymazat marker", + "menu:edit_marker:close": "Zatvorit", + "menu:edit_marker:save": "Ulozit", + + "menu:input_text:close": "Zatvorit", + "menu:input_text:confirm": "Potvrdit", + + "menu:notification:notification": "Notifikacie", + "menu:notification:close": "Zatvorit", + + "menu:not_allowed:you_are_not_allowed": "Na poutzivanie menu nemate potrebne opravnenie", + "menu:not_allowed:if_you_are_admin": "Ak ste admin pridajte povolenia /add ACE/ do suboru server.cfg", + + "menu:animations:animations": "Animacie", + "menu:animations:add_animation": "Pridat animaciu", + "menu:animations:close": "Zatvorit", + "menu:animations:save": "Ulozit", + + "menu:dynamic:create_new_job": "Vytvorit novy job", + "menu:dynamic:new_job_label": "Novy job popis:", + "menu:dynamic:new_job_name": "Meno jobu (id):", + + "menu:dynamic:delete_job_confirm": "Naozaj chcete vymazat job?", + + "menu:dynamic:job_markers:create_marker": "Vytvorit marker", + "menu:dynamic:job_markers:label": "Popis", + "menu:dynamic:job_markers:coord_x": "Coord X", + "menu:dynamic:job_markers:coord_y": "Coord Y", + "menu:dynamic:job_markers:coord_z": "Coord Z", + "menu:dynamic:job_markers:current_coords": "Aktualne suradnice", + "menu:dynamic:job_markers:min_grade": "Minimalna hodnost", + + "menu:dynamic:public_markers:create_public_marker": "Vytvorit verejny marker", + "menu:dynamic:public_markers:label": "Popis", + "menu:dynamic:public_markers:coord_x": "Coord X", + "menu:dynamic:public_markers:coord_y": "Coord Y", + "menu:dynamic:public_markers:coord_z": "Coord Z", + "menu:dynamic:public_markers:current_coords": "Aktualne suradnice", + + "menu:dynamic:harvest:name": "Meno (ID)", + "menu:dynamic:harvest:min_quantity": "Minimalne mnozstvo", + "menu:dynamic:harvest:max_quantity": "Maximalne mnozstvo", + "menu:dynamic:harvest:time_to_harvest": "Cas zbierania (sekundy)", + "menu:dynamic:harvest:probabilty": "Pravdepodobnost najdenia", + + "menu:dynamic:default": "Predvolene", + + "menu:dynamic:animations:animation_dictionary": "Animacia nastavenie:", + "menu:dynamic:animations:animation_name": "Animacia meno:", + "menu:dynamic:animations:animation_duration": "Animacia trvanie (sekundy):", + "menu:dynamic:animations:scenario_name": "Scenario nazov", + "menu:dynamic:animations:scenario_duration": "Scenario trvanie (sekundy):", + "menu:dynamic:animations:remove": "Odstranit", + + "menu:dynamic:marker_info:stash": "Sklad", + "menu:dynamic:marker_info:stash_settings": "Sklad nastavenia", + "menu:dynamic:marker_info:armory": "Zbrojnica", + "menu:dynamic:marker_info:armory_settings": "Zbrojnica nastavenie", + "menu:dynamic:marker_info:safe": "Trezor", + "menu:dynamic:marker_info:temporary_garage": "Garaz - Job vozidla", + "menu:dynamic:marker_info:temporary_garage_settings": "Garaz nastavenia", + "menu:dynamic:marker_info:garage_buyable": "Garaz - Kupitelne vozidla", + "menu:dynamic:marker_info:garage_buyable_settings": "Garaz nastavenia", + "menu:dynamic:marker_info:garage_owned": "Vlastnene vozidla", + "menu:dynamic:marker_info:garage_owned_settings": "Garaz nastavenia", + "menu:dynamic:marker_info:boss": "Boss", + "menu:dynamic:marker_info:boss_settings": "Boss nastavenia", + "menu:dynamic:marker_info:wardrobe": "Satnik - Hrac ulozene outfity", + "menu:dynamic:marker_info:job_outfit": "Job Outfit", + "menu:dynamic:marker_info:job_outfit_settings": "Outfity", + "menu:dynamic:marker_info:shop": "Obchod (Kupit itemy)", + "menu:dynamic:marker_info:shop_settings": "Obchod itemy", + "menu:dynamic:marker_info:market": "Obchod (Predaj itemov)", + "menu:dynamic:marker_info:market_settings": "Obchod itemy", + "menu:dynamic:marker_info:harvest": "Zbieranie point", + "menu:dynamic:marker_info:harvest_settings": "Itemy na zber", + "menu:dynamic:marker_info:process": "Vyroba point", + "menu:dynamic:marker_info:process_settings": "Vyroba item", + "menu:dynamic:marker_info:crafting_table": "Pracovny stolik", + "menu:dynamic:marker_info:crafting_table_settings": "Vytvaranie nastavenia", + "menu:dynamic:marker_info:teleport": "Teleport point", + "menu:dynamic:marker_info:teleport_settings": "Teleport nastavenia", + "menu:dynamic:marker_info:weapon_upgrader": "Zbrane uprava", + "menu:dynamic:marker_info:weapon_upgrader_settings": "Ceny komponentov/odtienov", + "menu:dynamic:marker_info:duty": "On/Off Duty", + "menu:dynamic:marker_info:job_shop": "Job Obchod", + "menu:dynamic:marker_info:job_shop_settings": "Obchod nastavenia", + + "menu:dynamic:marker:crafting_table:time_to_craft": "Cas vyroby (sekundy)", + "menu:dynamic:marker:crafting_table:result_item": "Vysledny item", + "menu:dynamic:marker:crafting_table:quantity": "Mnozstvo", + "menu:dynamic:marker:crafting_table:item_id": "Item ID", + "menu:dynamic:marker:crafting_table:item_quantity": "Item mnozstvo", + "menu:dynamic:marker:crafting_table:lose_on_use": "Stratenie po pouziti", + "menu:dynamic:marker:crafting_table:remove": "Odstranit", + "menu:dynamic:marker:crafting_table:animations": "Animacie", + "menu:dynamic:marker:crafting_table:add_to_craft": "Pridat do vyroby", + "menu:dynamic:marker:crafting_table:remove_craft": "Odstranit z vyroby", + + "menu:dynamic:marker:temporary_garage:delete": "Vymazat", + "menu:dynamic:marker:temporary_garage:random_plate": "Nahodna znacka", + + "menu:datatable:lengthMenu": "Zobrazenie _MENU_ vysledky", + "menu:datatable:zeroRecords": "Ziadne vysledky", + "menu:datatable:info": "Zobrazenie _STRANKA_ z _STRANOK_", + "menu:datatable:infoEmpty": "Nie su ziadne vysledky", + "menu:datatable:infoFiltered": "(filtracia z _MAX_ vysledkov)", + "menu:datatable:search": "Hladaj:", + "menu:datatable:next": "Dalej", + "menu:datatable:previous": "Spat", + + "menu:chart:players_in_rank": "Hraci v poradi", + + "menu:settings:player_menu_position": "Hrac menu pozicia", + "menu:settings:player_menu_position:bottom_right": "Vpravo dole", + "menu:settings:player_menu_position:top_right": "Vpravo hore", + "menu:settings:player_menu_position:right": "V pravo", + "menu:settings:player_menu_position:bottom_left": "Vlavo dole", + "menu:settings:player_menu_position:top_left": "Vlavo hore", + "menu:settings:player_menu_position:left": "Vlavo", + "menu:settings:max_distance_marker": "Maximalny distanc markeru", + "menu:settings:use3Dtext": "Pouzit 3D text na markery", + "menu:settings:text_size": "Text velkost", + "menu:settings:font_to_use": "Pismo", + "menu:settings:seconds_to_lockpick_car": "Pocet sekund na vypacenie zamku", + "menu:settings:vehicle_alarm": "Ma mat vozidlo spusteny alarm pocas pacenia?", + "menu:settings:jsfour_idcard": "Na zobrazenie ID karty pouzite skript jsfour-idcard (ak ho mate).", + "menu:settings:can_use_actions_off_duty": "Moze pouzivat hrac F6 menu ak je off duty?", + "menu:settings:car_driving_licenses_ids": "ID vodicskeho preukazu", + "menu:settings:weapon_licenses_ids": "ID zbrojnych preukazov", + "menu:settings:new_driving_license": "Nova vodicska licencia", + "menu:settings:add": "Pridat", + "menu:settings:new_weapon_license": "Nova zbrojna licencia", + "menu:settings:can_sell_multiple_items": "Moze predavat viacero poloziek a itemov naraz?", + "menu:settings:language": "Jazyk", + "menu:settings:allow_afk_farming": "Zapnute automatickeho zberu a spracovania", + "menu:settings:unemployed_job_id": "ID nezamestnaneho zamestnania", + "menu:settings:unemployed_job_grade": "Nezamestnany job hodnosti", + "menu:settings:ace_permission": "ACE povolenia", + + "menu:settings:enable_discord_logs": "Polvolit discord logy", + "menu:settings:discord_webhooks": "Discord webhooky", + "menu:settings:main_webhook": "Hlavny webhook", + "menu:settings:separated_webhooks": "Oddelene webhooky", + + "menu:settings:handcuffs_requires_item": "Putanie potrebny item", + "menu:settings:handcuffs_item_name": "Puta item nazov", + "menu:settings:freeze_when_handcuffed": "Freeze hraca po sputani", + + "menu:settings:lockpick_requires_item": "Vypacovanie zamku na vozidle potrebny item", + "menu:settings:lockpick_item_name": "Lockpick item nazov", + "menu:settings:lockpickRemoveOnUse": "Stratit lockpick po pouziti", + + "menu:settings:robbable_accounts": "Robbable ucty", + "menu:settings:new_robbable_account": "Novy ucet", + "menu:settings:canAlwaysCarryItem": "Vzdy moze nosit itemy", + "menu:settings:accounts_depositable_in_safe": "Peniaze ulozene v trezore", + "menu:settings:enable_cash_in_safes_old_esx": "Povolte peniaze v trezore pre starsiu verziu ESX", + + "menu:settings:vehicle_reparation": "Vozidla opravy", + "menu:settings:repair_vehicle_requires_item": "Opravovat vozidlo iba s itemom", + "menu:settings:repair_vehicle_item_name": "Fixkit item nazov", + "menu:settings:lose_fixkit_on_use": "Vymazat fixkit item po pouzity", + + "menu:settings:vehicle_cleaning": "Vozidlo umyvanie", + "menu:settings:clean_vehicle_requires_item": "Umyt vozidlo iba s itemom", + "menu:settings:clean_vehicle_item_name": "Spongia nazov", + "menu:settings:lose_sponge_on_use": "Vymazat spongiu item po pouziti", + + "menu:settings:healing": "Liecenie", + "menu:settings:healing_requires_item": "Liecenie potrebny item", + "menu:settings:healing_item_name": "Bandaz nazov itemu", + "menu:settings:lose_bandage_on_use": "Vymazat spongiu po puziti", + + "menu:settings:reviving": "Ozivenie hraca", + "menu:settings:reviving_requires_item": "Ozivenie hraca potreby item", + "menu:settings:reviving_item_name": "Medikit item nazov", + "menu:settings:lose_medikit_on_use": "Vymazat medikit po pouziti", + + "menu:settings:enable_property_outfits": "Povolit outfity v property", + + "menu:settings:apply_changes": "Aplikovat zmeny", + "menu:settings:restore_default_config": "Obnovit defaultne nastavenia", + "menu:are_you_sure_to_restore_settings": "Naozaj chces obnovit defaultne nastavenia?", + + "menu:items_dialog:title": "Itemy zoznam", + "menu:items_dialog:search_item": "Hladaj item", + + "menu:weapons_dialog:title": "Zbrane zoznam", + "menu:weapons_dialog:search_weapon": "Hladaj zbran", + + "menu:dialog:choose_item": "Vybrat item", + "menu:dialog:choose_weapon": "Vybrat zbran", + + "menu:settings:actions_menu_key": "Klavesnica pre akcne menu", + + "menu:settings:park_all_owned_vehicles_on_restart": "Zaparkovat vsetky vozidla do garaze po restarte", + + "menu:account_name": "Ucet nazov", + "menu:accounts_dialog:title": "Ucet zoznam", + "menu:minimum_amount": "Minimalna suma", + + "menu:edit_marker:requires_minimum_account_money": "Vyzadovat mininimum penazi na ucte?" +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/integrations/cl_integrations.lua b/resources/[creators]/jobs_creator/integrations/cl_integrations.lua new file mode 100644 index 0000000..5261aa2 --- /dev/null +++ b/resources/[creators]/jobs_creator/integrations/cl_integrations.lua @@ -0,0 +1,44 @@ +EXTERNAL_EVENTS_NAMES = { + ["esx:getSharedObject"] = nil, -- This is nil because it will be found automatically, change it to your one ONLY in the case it can't be found + + ["esx_skin:save"] = "esx_skin:save", + + ["esx_billing:sendBill"] = "esx_billing:sendBill", + + ["jsfour-idcard:open"] = "jsfour-idcard:open", + + ["esx_license:removeLicense"] = "esx_license:removeLicense", + ["esx_license:addLicense"] = "esx_license:addLicense", + + ["esx_skin:getPlayerSkin"] = "esx_skin:getPlayerSkin", + + -- Just used if you choose illenium instead of framework "outfit manager" + ["illenium-appearance:client:openOutfitMenu"] = "illenium-appearance:client:openOutfitMenu", + ["illenium-apearance:client:outfitsCommand"] = "illenium-apearance:client:outfitsCommand", +} + +-- If true, the markers will be hidden when the player is not on duty, if false, they will be visible but it can't be used +COMPLETELY_HIDE_MARKERS_WHEN_OFF_DUTY = false + +--[[ + Default progressbar color (must be a hex code). Examples: + "#0fffef" - Light blue + "#ff0f0f" - Red + "#0f0fff" - Blue +]] +DEFAULT_PROGRESSBAR_COLOR = "#0fffef" + +-- If you use an ambulance script that edits death behavior, making native IsPedDeadOrDying return false when the player is dead +function IsPedDeadOrDyingCustom(ped) + if not IsPedAPlayer(ped) then return IsPedDeadOrDying(ped) end -- Most likely you don't need to touch this + + -- EDIT THIS FUNCTION TO RETURN TRUE WHEN THE PLAYER IS DEAD AND FALSE WHEN THE PLAYER IS ALIVE + local isPlayerDead = IsPedDeadOrDying(ped) + return isPlayerDead +end + +-- This function is called right before a vehicle is parked in a permanent garage, you can return false to cancel the park +function PreVehicleParking(vehicle, plate, model) + -- Add your code here, return false only if you want to cancel the park + return true +end diff --git a/resources/[creators]/jobs_creator/integrations/sh_integrations.lua b/resources/[creators]/jobs_creator/integrations/sh_integrations.lua new file mode 100644 index 0000000..b430a7e --- /dev/null +++ b/resources/[creators]/jobs_creator/integrations/sh_integrations.lua @@ -0,0 +1,16 @@ +--[[ + This is the plate format that will be used to create random plates + Configure the plate format using # for fixed characters + + Examples: + "#LSPD#123" -> LSPD920, LSPD945, LSPD984 (as you can see, LSPD doesn't change) + "AB123CD" -> XC111EW, SI849TW, YS364KD + "CBZ 629" -> EGP 015, VHS 687, SXN 296 + "72 QT 15" -> 63 VD 85, 27 AC 66, 63 HR 75 +]] +EXAMPLE_PLATE = "AB123CD" + +--[[ + The shared object of the framework will refresh each X seconds. If for any reason you don't want it to refresh, set to nil +]] +SECONDS_TO_REFRESH_SHARED_OBJECT = nil diff --git a/resources/[creators]/jobs_creator/integrations/sv_integrations.lua b/resources/[creators]/jobs_creator/integrations/sv_integrations.lua new file mode 100644 index 0000000..4dcc60a --- /dev/null +++ b/resources/[creators]/jobs_creator/integrations/sv_integrations.lua @@ -0,0 +1,27 @@ +-- You can edit the events on the right side if you for any reason don't use the default event name + +EXTERNAL_EVENTS_NAMES = { + ["esx:getSharedObject"] = nil, -- This is nil because it will be found automatically, change it to your one ONLY in the case it can't be found + + ["esx_society:registerSociety"] = "esx_society:registerSociety", + ["esx_society:getSociety"] = "esx_society:getSociety", + + ["esx_addonaccount:getSharedAccount"] = "esx_addonaccount:getSharedAccount", + + ["esx_datastore:getSharedDataStore"] = "esx_datastore:getSharedDataStore", + ["esx_datastore:getDataStore"] = "esx_datastore:getDataStore", + + ["esx_ambulancejob:revive"] = "esx_ambulancejob:revive", + ["esx_ambulancejob:heal"] = "esx_ambulancejob:heal", +} + +-- Skips or not if an item exists (useful with inventories that doesn't save items in database or in ESX.Items table, example ox_inventory) +SKIP_ITEM_EXISTS_CHECK = false + +--[[ + Default duty status on join for QBCore + true = on duty + false = off duty + nil = use qbcore default +]] +DEFAULT_DUTY_STATUS = true diff --git a/resources/[creators]/jobs_creator/locales/bh.lua b/resources/[creators]/jobs_creator/locales/bh.lua new file mode 100644 index 0000000..9b7da7b --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/bh.lua @@ -0,0 +1,385 @@ +locales['bh'] = { + -- [[ Generic ]] + ["interact"] = "Pritisni E da pristupis izborniku", + ["billing_reason"] = "Razlog", + ["billing_amount"] = "Racun kolicina", + ["no_players_nearby"] = "Nema nikoga u blizini", + ["no_vehicles_nearby"] = "Nema vozila u blizini", + ["invoice_sent"] = "$%s racun kreiran", + ["too_far"] = "Daleko ste", + ["yes"] = "Da", + ["no"] = "Ne", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Otvori izbornik", + ['actions_menu'] = "Akcije", + ['actions_billing'] = "Racuni", + ['actions_search'] = "Pretrazi", + ['actions_put_handcuffs'] = "Zavezi/Odvezi", + ['actions_start_dragging'] = "Vuci", + ['actions_put_in_car'] = "Stavi u vozilo", + ['actions_take_from_car'] = "Izvadi iz vozila", + ['actions_menu_search'] = "Pretrazi", + ['actions_lockpick_car'] = "Obij vozilo", + ['no_car_found'] = "Nema vozila u blizini", + ['not_locked_vehicle'] = "Vozilo nije zakljucano", + ['you_need_lockpick'] = "Potreban ti je lockpick", + ['lockpick_used'] = "Iskoristio si lockpick", + ['actions:lockpick:lockpickingVehicle'] = "Obijas vozilo", + ['actions_menu_search_took'] = "Uzeo si %d %s", + ['actions_menu_search_stolen'] = "x%d %s ti je ukradeno", + ['actions_menu_search_took_money'] = "Uzeo si $%s %s", + ['actions_menu_search_stolen_money'] = "$%s %s ti je ukradeno", + ['actions_menu_search_doesnt_have_weapon'] = "Osoba nema oruzje", + ['actions_menu_search_took_weapon'] = "Uzeo si %s sa %d metaka", + ['actions_menu_search_stolen_weapon'] = "%s sa %d metaka, je ukradeno od tebe.", + ['you_need_handcuffs'] = "Nemas lisice!", + ['not_handcuffed'] = "Igrac nije svezan", + ['cant_while_dragging'] = "Ne mozes dok vuces", + ['search_inventory_empty'] = "Inventory je prazan", + ['actions_menu_being_searched'] = "Netko vas pretrazuje", + ['actions:wash_vehicle'] = "Operi vozilo", + ['actions:washing_vehicle'] = "Pranje vozila", + ['actions:repair_vehicle'] = "Popravi vozilo", + ['actions:repairing_vehicle'] = "Popravljanje vozila", + ['actions:no_vehicles_close'] = "Nema vozila u blizini", + ['actions:impound_vehicle'] = "Zaplijeni vozilo", + ['actions:impounding_vehicle'] = "Zaplijenjivanje vozila", + ['actions:you_need'] = "Treba ti %s", + ['actions:check_identity'] = "Provjeri identitet", + ['actions:check_vehicle_owner'] = "Provjeri vlasnika", + ['actions:checkVehicleOwner:owner'] = "Vlasnik vozila je %s", + ['actions:checkVehicleOwner:owner_not_found'] = "Vlasnik nije pronadjen", + ['actions:checkVehicleOwner:car_not_found'] = "Nema vozila u blizini", + ['actions:checkIdentity:no_player_found'] = "Nema nikoga u blizini", + ['actions:checkIdentity:player_found'] = "Pronadjeno ime: %s", + ['actions:checkIdentity:somebody_checked_your_id'] = "Netko vam je provjerio identitet", + + ['actions:license'] = "%s", + ['actions:licenses'] = "Dozvole", + ['actions:no_license_found'] = "Nema pronadjenih dozvola", + ['actions:check_licenses'] = "Provjeri dozvole", + ['actions:driving_license'] = "Vozacka dozvola", + ['actions:weapon_license'] = "Oruzje dozvola", + ['actions:license:give_remove'] = "Oduzmi dozvole", + ['actions:gave_license'] = "Dao si %s", + ['actions:removed_license'] = "Oduzeo si %s", + ['actions:heal_small'] = "Izlijecili ste male povrede", + ['actions:heal_big'] = "Izlijecili ste velike povrede", + ['actions:you_need_bandage'] = "Potrebne su vam bandage", + ['actions:revive'] = "Reanimiraj", + ['actions:you_need_medikit'] = "Potreban ti je medikit", + + -- [[ Stash stuff ]] + ["open_stash"] = "Pritisni E da otvoris ormaric", + ["deposited"] = "Ostavio si x%d %s", + ["not_enough"] = "Nemas dovoljno %s", + ["no_space"] = "Nemas dovoljno mjesta", + ["took"] = "Uzeo si ~b~x%d %s", + ["impossible_take"] = "Nije moguce uzeti x%d %s", + ["empty_inventory"] = "Tvoj inventory je prazan", + ["empty_stash"] = "Ormaric je prazan", + ['stash'] = "Ormaric", + ['stash_take'] = "Ormaric - Uzmi", + ['stash_deposit'] = "Ormaric - Ostavi", + ['quantity'] = "Kolicina", + ['invalid_quantity'] = "Pogresna kolicina", + ['deposit'] = "Ostavi", + ['take'] = "Uzmi", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Pritisni E da se obuces", + ['player_clothes'] = "Vasi outfiti", + ['remove_cloth'] = "Obrisi outfit", + ['save_cloth'] = "Sacuvaj outfit", + ['you_saved_outfit'] = "Outfit sacuvan", + ['delete_outfit'] = "Outfit obrisan", + ['clothes'] = "Odjeca", + ['outfit_label_empty'] = "Outfit mora imati ime", + ['outfit_name'] = "Ime outfita", + ["wardrobe:empty"] = "Ormar je prazan", + ["wardrobe:delete"] = "%s - Obrisi", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Pritisni ~INPUT_CONTEXT~ da otvoris izbornik", + ["not_boss"] = "Nisi sef", + ["boss_menu"] = "Sef menu", + ["boss:society_money"] = "Firma novac: $%s", + ["boss:withdraw"] = "Podigni novac", + ["boss:deposit"] = "Ostavi novac", + ["boss:wash_money"] = "Operi novac", + ["boss:grades"] = "Upravljaj platama", + ["boss:employees"] = "Upravljaj zaposlenicima", + ["boss:withdraw_amount"] = "Podigni - kolicina", + ["boss:deposit_amount"] = "Ostavi - kolicina", + ["boss:you_dont_have_enough_money"] = "Nemas toliko novca", + ["boss:invalid_amount"] = "Pogresan unos", + ["boss:withdrew_money"] = "Podigao si $%s", + ["boss:deposited_money"] = "Ostavio si $%s", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "rank plata", + ["boss:grade_salary_updated"] = "Vas rank je update-ovan", + ["boss:grade_salary_not_updated"] = "Niste uspjeli update-ovati rank", + ["boss:employees_list"] = "Lista zaposlenih", + ["boss:recruit"] = "Zaposli", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Otpusti", + ["boss:change_grade"] = "Promjeni rank", + ["boss:are_you_sure"] = "Da li si siguran?", + ["boss:cancel"] = "Odustani", + ["boss:employee_fired"] = "Zaposlenik je otpusten", + ["boss:you_got_hired"] = "Zaposljen si u %s", + ["boss:you_hired"] = "Zaposlio si %s", + ["boss:nobody_close"] = "Nema nikoga u blizini", + ["boss:grade"] = "%d. %s - Plata $%s", + ["boss:changed_grade_successfully"] = "Rank uspjesno update-an", + ["boss:your_grade_changed_to"] = "Vas rank je promijenjen %s", + ["boss:how_much_to_wash"] = "Koliko novca zelite oprati ?", + ["boss:you_washed_money"] = "Oprao si $%s te si dobio $%s", + ["boss:not_enough_dirty_money"] = "Nemas toliko prljavog novca", + ["boss:couldnt_wash_money"] = "Radnja nije uspjesna", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Pritisni ~INPUT_CONTEXT~ da otvoris garazu", + ["garage"] = "Garaza", + ["take_vehicle"] = "Uzmi vozilo", + ["park_vehicle"] = "Parkiraj vozilo", + ["no_vehicle"] = "Nema vozila u garazi", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Pritisni ~INPUT_CONTEXT~ da otvoris shop", + ["job_shop"] = "Posao Shop", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "Nemate dovoljno novca", + ['you_bought'] = "Kupio si x%d %s za ~%s~$%s", + ['shop_empty'] = "Shop je prazan", + ['shop:you_already_have_that_weapon'] = "Vec imas ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Kupi vozilo", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "Kupili ste vozilo", + ['are_you_sure'] = "Da li si siguran da zelis kupiti %s za $%s?", + ['no_vehicles_in_garage'] = "Nema vozila u garazi!", + ['vehicle_outside'] = "Vozilo nije u garazi", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Nema vozila za kupovinu!", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Pritisni ~INPUT_CONTEXT~ da otvoris garazu", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Pritisni ~INPUT_CONTEXT~ da otvoris crafting stol", + ['crafting_table'] = "Radni stol", + ['dont_have_ingredients'] = "Nemate iteme potrebne za craftanje", + ['crafting'] = "Craftanje %s", + ['you_crafted'] = "Izradili ste x%d %s", + ['already_have'] = "Vec imas kod sebe %s", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Pritisni ~INPUT_CONTEXT~ da zaustavis", + ['you_stopped'] = "Zaustavit cete se kada zavrsite sa kraftanjem", + + -- [[ Armory stuff ]] + ['open_armory'] = "Pritisni ~INPUT_CONTEXT~ da otvoris oruzarnicu", + ['not_have_any_weapon'] = "Nemate oruzje kod sebe", + ['armory'] = "Oruzarnica", + ['armory_take'] = "Oruzarnica - Uzmi", + ['armory_deposit'] = "Oruzarnica - Ostavi", + ['take_weapon'] = "Uzmi oruzje", + ['deposit_weapon'] = "Ostavi oruzje", + ['you_dont_have_weapon'] = "Nemas to oruzje kod sebe", + ['no_weapons_in_armory'] = "Nema oruzja u oruzarnici", + ['you_deposited_weapon'] = "Ostavio si %s", + ['you_took_weapon'] = "Uzeo si %s", + ['you_already_have_that_weapon'] = "Vec imas %s", + ['weapon_ammo'] = "Oruzje municija", + ['weapon'] = "%s - x%d metaka", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Pritisni ~INPUT_CONTEXT~ da otvoris ormaric", + ['job_outfit'] = "Posao uniforma", + ['no_outfits'] = "Nema dostupnih uniformi", + ['civilian_outfit'] = "Civilna odjeca", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Pritisni ~INPUT_CONTEXT~ da se teleportujes", + ['teleport_to'] = "Pritisni ~INPUT_CONTEXT~ da odes do %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Pritisni ~INPUT_CONTEXT~ da otvoris sef", + ['account'] = "%s - $%s", + ['safe'] = "Sef", + ['empty_safe'] = "Sef je prazan", + ['nothing_to_deposit'] = "Nemate nista sto bi mogli ostaviti", + ['withdrawn_safe'] = "Uzeli ste %s$%s %s~s~", + ['deposited_safe'] = "Ostavili ste %s$%s %s~s~", + ['cash'] = "Novac", + ['withdraw'] = "Uzmi", + + -- [[ Market Stuff ]] + ['open_market'] = "Pritisni ~INPUT_CONTEXT~ da otvoris market", + ['market_item'] = "%s - $%s - &%s", + ['market'] = "Market", + ['not_enough_item'] = "Nemas dovoljno %s", + ['you_sold'] = "Prodao si x%d %s za %s$%s", + ['nothing_can_be_sold_yet'] = "Trenutno se ne moze prodavati", + ['market:how_many_to_sell'] = "Koliko zelis prodati?", + ['market:you_are_already_selling'] = "Vec prodajes", + ['market:selling'] = "Prodaja x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Pritisni ~INPUT_CONTEXT~ da uberes", + ['harvest:harvesting'] = "Branje %s", + ['harvest:press_to_stop'] = "Pritisni ~INPUT_CONTEXT~ da zaustavis", + ['harvest:you_will_stop_on_finish'] = "Zaustavit cete se kada zavrsite", + ['harvest:you_need_tool_count'] = "Potrebno ti je ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Potrebno ti je ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Pritisni ~INPUT_CONTEXT~ da otvoris izbornik", + ['weapon_upgrader'] = "Upgrade oruzja", + ['owned_component'] = "%s - POSJEDUJES", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Default", + ['tint_green'] = "Zelena", + ['tint_gold'] = "Zlatna", + ['tint_pink'] = "Roza", + ['tint_army'] = "Army", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Narandzasta", + ['tint_platinum'] = "Platina", + ['components'] = "Komponente", + ['tints'] = "Tinte", + ['already_have_tint'] = "Ves imas tu boju", + ['bought_tint'] = "Kupili ste %s boju za %s", + ['bought_component'] = "Kupio si %s za %s", + ['removed_component'] = "Uklonili ste %s sa %s", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Pritisni ~INPUT_CONTEXT~ da ides na duznost", + ['go_off_duty'] = "Pritisni ~INPUT_CONTEXT~ da ides sa duznosti", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Pritisni ~INPUT_CONTEXT~ da otvoris shop", + ['job_owned_shop'] = "Posao Shop", + ['shop'] = "Shop", + ['put_on_sale'] = "Stavi na prodaju", + ['remove_from_sale'] = "Skloni iz prodaje", + ['item_price'] = "Item cijena", + ['invalid_price'] = "Pogresna cijena", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "Shop je prazan", + ['job_shop_quantity'] = "Kolicina - x%d -> $%s", + ['job_shop_cant_afford'] = "Nemas dovoljno novca", + ['job_shop:bought_item'] = "Kupio si x%d %s za $%s", + ['job_shop:add_supplies'] = "Dodaj stvari", + ['job_shop:what_to_put_on_sale'] = "Sta zelis staviti na prodaju?", + ['job_shop:what_to_remove_from_sale'] = "Sta zelis ukloniti sa prodaje?", + ['job_shop:what_to_restock'] = "Sta zelis nadopuniti?", + ['job_shop:how_many_to_restock'] = "Kolicina?", + ['job_shop:added_to_supplies'] = "Dodao si x%d %s u zalihe", + ['job_shop:you_put_on_sale'] = "Stavili ste x%d %s na prodaju za $%s", + ['job_shop:you_removed_from_sale'] = "Ukolnio si x%d %s iz prodaje", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Vec imas ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Nemas nista za prodati", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Pritisni ~INPUT_CONTEXT~ da procesujes", + ['process:you_need'] = "Potrebno ti je x%d %s", + ['process:processing'] = "Procesuiranje %s", + ['process:press_to_stop'] = "Pritisni ~INPUT_CONTEXT~ da zaustavis", + ['process:you_will_stop_on_finish'] = "Zaustavit cete se kada zavrsite", + ['process:no_space'] = "Ne mozes ponjeti x%d %s", + + -- [[ Logs stuff ]] + ['log:generic'] = "Nickname: %s\nIdentifier: %s\n\n%s", + + ['log_deposited_stash'] = "Ostavio item", + ['log_deposited_stash_description'] = "Ostavio x**%d** **%s** (**%s**) na markeru ID **%d**", + + ['log_took_stash'] = "Uzeo item", + ['log_took_stash_description'] = "Uzeo x**%d** **%s** (**%s**) sa markera ID **%d**", + + ['log_deposited_weapon'] = "Ostavio oruzje", + ['log_deposited_weapon_description'] = "Ostavio **%s** (**%s**) sa x**%d** metaka na markeru ID **%d**", + + ['log_took_weapon'] = "Uzeo oruzje", + ['log_took_weapon_description'] = "Uzeo **%s** (**%s**) sa x**%d** metaka na markeru ID **%d**", + + ['log_deposited_money'] = "Ostavio novac", + ['log_deposited_money_description'] = "Ostavio $**%d** u firmu '**%s**'", + + ['log_withdrew_money'] = "Uzeo novac", + ['log_withdrew_money_description'] = "Uzeo $**%d** iz firme '**%s**'", + + ['log_updated_salary'] = "Podesio platu", + ['log_updated_salary_description'] = "Podesio platu za rank **%d** na **$%s**", + + ['log_fired_employee'] = "Uposlenik otpusten", + ['log_fired_employee_description'] = "Otpustio osobu sa identifierom **%s**", + + ['log_recruited_employee'] = "Zaposlio osobu", + ['log_recruited_employee_description'] = "Zaposlio **%s** sa identifierom **%s**", + + ['log_changed_grade_employee'] = "Promjenjen rank", + ['log_changed_grade_employee_description'] = "Promjenjen rank od **%s** u **%d**", + + ['log_washed_money'] = "Pranje novca", + ['log_washed_money_description'] = "Oprao $**%s**", + + ['log_sold_item'] = "Prodaja itema", + ['log_sold_item_description'] = "Prodao **x%d** **%s** za **$%s**", + + ['log_bought_item'] = "Kupovina itema", + ['log_bought_item_description'] = "Kupio x%d **%s** (**%s**) na markeru ID **%d**", + + ['log_not_existing_item'] = "Item ne postoji", + ['log_not_existing_item_description'] = "Pokusao da kupi '**%s**' na markeru ID **%d**, ali item nije u shopu", + + ['log_bought_vehicle'] = "Kupovina vozila", + ['log_bought_vehicle_description'] = "Kupio '**%s**' za $**%d** na markeru ID **%d**", + + ['log_not_existing_vehicle'] = "Vozilo ne postoji", + ['log_not_existing_vehicle_description'] = "Pokusao da kupi '**%s**' na markeru ID **%d**,ali vozilo ne postoji", + + ['log_crafted_item'] = "Crafting", + ['log_crafted_item_description'] = "Kraftovao **x%d** **%s** (**%s**) na markeru ID **%d**", + + ['log_deposited_safe'] = "Ostavi u sef", + ['log_deposited_safe_description'] = "Ostavio $**%s** **%s** na markeru ID **%d**", + + ['log_withdrew_safe'] = "Uzmi iz sefa", + ['log_withdrew_safe_description'] = "Uzeo $**%s** **%s** na markeru ID **%d**", + + ['log_harvested'] = "Branje", + ['log_harvested_description'] = "Ubrao x**%d** **%s** na markeru ID **%d**", + + ['log_bought_tint'] = "Kupovina tinte", + ['log_bought_tint_description'] = "Kupio **%s** '**%s**' tintu za $**%d** na markeru ID **%d**", + + ['log_removed_component'] = "Ukloni dio", + ['log_removed_component_description'] = "Uklonio **%s** sa **%s** na markeru ID **%d**", + + ['log_bought_component'] = "Kupi dio", + ['log_bought_component_description'] = "Kupio **%s** za **%s** na markeru ID **%d**", + + ['log_not_allowed_marker'] = "Zabranjeno koristenje markera", + ['log_not_allowed_marker_description'] = "Je pokusao koristi markerID %d, bez dozvole", + + ['logs:process:title'] = "Procesuiranje", + ['logs:process:description'] = "Procesuirano **x%d** **%s** u **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Stavi na prodaju", + ['logs:job_shop:put_on_sale:description'] = "Stavi na prodaju **x%d** **%s** za **$%s** na markeru ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Ukloni iz prodaje", + ['logs:job_shop:remove_from_sale:description'] = "Uklonio **x%d** **%s** za **$%s** na markeru ID **%d**", + + ['logs:job_shop:bought_item'] = "Kupio item", + ['logs:job_shop:bought_item:description'] = "Kupio **x%d** **%s** za **$%s** na markeru ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Dodao zalihe", + ['logs:job_shop:add_to_supplies:description'] = "Dodao **x%d** **%s** za **$%s** u zalihe na markeru ID **%d**", +} diff --git a/resources/[creators]/jobs_creator/locales/cz.lua b/resources/[creators]/jobs_creator/locales/cz.lua new file mode 100644 index 0000000..802e0b3 --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/cz.lua @@ -0,0 +1,413 @@ +locales['cz'] = { + -- [[ Generic ]] + ["interact"] = "Stiskněte ~INPUT_CONTEXT~ pro interakci", + ["billing_reason"] = "Důvod Pokuty", + ["billing_amount"] = "Fakturační částka", + ["no_players_nearby"] = "Žádní hráči v okolí", + ["no_vehicles_nearby"] = "Žádná vozidla v okolí", + ["invoice_sent"] = "~g~$%s~s~ faktura odeslána", + ["too_far"] = "Příliš daleko", + ["yes"] = "Ano", + ["no"] = "Ne", + ["you_need_minimum_account_money"] = "Potřebujete minimálně $~y~%d~s~ na ~b~%s~s~", + ["bill"] = "Faktura", + ["bill_received"] = "Obdrželi jste fakturu
    Částka: $%s
    Důvod: %s

    Stisknutím níže uvedeného tlačítka účet přijmete", + ["bill_paid"] = "Zaplatili jste fakturu za $%s", + + -- [[ Actions menu ]] + ['actions_put_handcuffs'] = "Spoutat", + ['actions_start_dragging'] = "Presunout", + ['open_actions_menu'] = "Otevřít nabídku akcí", + ['actions_menu'] = "Nabídka akcí", + ['actions_billing'] = "Dát osobě pokutu", + ['actions_search'] = "Prohledat osobu", + ['actions_put_in_car'] = "Vložit do auta", + ['actions_take_from_car'] = "Vytáhnout z auta", + ['actions_menu_search'] = "Hledat hráče", + ['actions_lockpick_car'] = "Vypáčit auto", + ['no_car_found'] = "Nebylo nalezeno žádné blízké auto", + ['not_locked_vehicle'] = "Toto vozidlo není uzamčeno", + ['you_need_lockpick'] = "Potřebujete ~r~lockpick~s~", + ['lockpick_used'] = "Použil jsi ~r~lockpick~s~", + ['actions:lockpick:lockpickingVehicle'] = "Lockpicking vehicle", + ['actions_menu_search_took'] = "Vy ~g~jste převzal~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ vám bylo ~r~stolen~s~", + ['actions_menu_search_took_money'] = "Vy ~g~jste převzal~s~ ~y~$%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~$%s %s~s~ vám bylo ~r~stolen~s~", + ['actions_menu_search_doesnt_have_weapon'] = "Hráč ~r~nemá~s~ tuto zbraň", + ['actions_menu_search_took_weapon'] = "Hráč si ~g~převzal~s~ ~y~%s~s~ pomocí ~y~%d kulky~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ s ~y~%d kulky~s~ vám byly ~r~ukradene~s~", + ['you_need_handcuffs'] = "Potřebujete ~r~pouta~s~", + ['not_handcuffed'] = "Hráč není ~r~spoutaný~s~", + ['cant_while_dragging'] = "Tohle nemůžeš dělat, když táhneš", + ['search_inventory_empty'] = "Inventář je prázdný", + ['actions_menu_being_searched'] = "Prohledává se", + ['actions:wash_vehicle'] = "Umýt vozidlo", + ['actions:washing_vehicle'] = "Mytí vozidla", + ['actions:repair_vehicle'] = "Oprava vozidla", + ['actions:repairing_vehicle'] = "Oprava vozidla", + ['actions:no_vehicles_close'] = "Žádné uzavřené vozidlo", + ['actions:impound_vehicle'] = "Odtáhnout vozidlo", + ['actions:impounding_vehicle'] = "Odtáhnutí vozidla", + ['actions:you_need'] = "Potřebujete ~y~%s~s~", + ['actions:check_identity'] = "Zkontrolovat totožnost", + ['actions:check_vehicle_owner'] = "Zkontrolujte vlastníka vozidla", + ['actions:checkVehicleOwner:owner'] = "Vozidlo vlastní ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Vlastník vozidla nebyl nalezen", + ['actions:checkVehicleOwner:car_not_found'] = "Vozidlo není nalezeno", + ['actions:no_player_found'] = "Nikdo nebyl nalezen", + ['actions:checkIdentity:player_found'] = "Nalezeno jméno občana: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Somebody~s~ zkontroloval vaši totožnost", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Licence", + ['actions:no_license_found'] = "Žádná licence nebyla nalezena", + ['actions:check_licenses'] = "Zkontrolovat licence", + ['actions:driving_license'] = "Řidičský průkaz", + ['actions:weapon_license'] = "Zbrojní průkaz", + ['actions:license:give_remove'] = "Odstranit licence", + ['actions:gave_license'] = "Vy ~g~jste poskytl~s~ ~y~%s~s~", + ['actions:removed_license'] = "Vy ~r~jste odstranil~s~ ~y~%s~s~", + ['actions:heal_small'] = "Léčí malé rány", + ['actions:heal_big'] = "Ošetřete vážná zranění", + ['actions:you_need_bandage'] = "Potřebujete ~r~bandage~s~", + ['actions:revive'] = "Oživení", + ['actions:revive:not_dead'] = "Osoba není mrtvá", + ['actions:you_need_medikit'] = "Potřebujete ~r~medikit~s~", + ['actions:the_player_must_be_handcuffed'] = "Hráč musí mít pouta nebo ruce nahoře.", + + -- [[ Stash stuff ]] + ["open_stash"] = "Stiskněte ~INPUT_CONTEXT~ pro otevření skrýše", + ["deposited"] = "Vložili jste ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "Není dost ~y~%s~s~", + ["no_space"] = "Nemáte žádné místo", + ["took"] = "Vzal jsi ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Nemožné získat x%d %s", + ["empty_inventory"] = "Tvůj inventář je prázdný", + ["empty_stash"] = "Skrýš je prázdná", + ["stash"] = "Skrýš", + ["stash_take"] = "Skrýš - Vezměte si", + ['stash_deposit'] = "Úschovna - Vklad", + ['quantity'] = "Množství", + ['invalid_quantity'] = "Neplatné množství", + ['deposit'] = "Záloha", + ['take'] = "Vezměte si", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Stisknutím ~INPUT_CONTEXT~ otevřete skříň", + ["player_clothes"] = "Vaše oblečení", + ['remove_cloth'] = "Smazat oblečení", + ['save_cloth'] = "Uložit aktuální oblečení", + ['you_saved_outfit'] = "Oblečení uloženo", + ['delete_outfit'] = "Outfit odstraněn", + ['clothes'] = "Oblečení", + ['outfit_label_empty'] = "Název outfitu nemůže být prázdný", + ['outfit_name'] = "Název vašeho oblečení", + ["wardrobe:empty"] = "Šatník je prázdný", + ["wardrobe:delete"] = "%s - Odstranit", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Stiskněte ~INPUT_CONTEXT~ pro otevření nabídky šéfa", + ["not_boss"] = "Nejste šéf", + ["boss_menu"] = "Boss menu", + ["boss:society_money"] = "Peníze společnosti: $%s", + ["boss:withdraw"] = "Vybrat peníze společnosti", + ["boss:deposit"] = "Vložit peníze společnosti", + ["boss:wash_money"] = "Vyprázdnit peníze", + ["boss:grades"] = "Spravovat platy tříd", + ["boss:employees"] = "Spravovat platy zaměstnanců", + ["boss:withdraw_amount"] = "Výběr částky", + ["boss:deposit_amount"] = "Výše vkladu", + ["boss:you_dont_have_enough_money"] = "Nemáte dostatek peněz", + ["boss:invalid_amount"] = "Neplatná částka", + ["boss:withdrew_money"] = "Vybrali jste ~g~$%s~s~", + ["boss:deposited_money"] = "Vložili jste ~g~$%s~s~", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "Nová platová třída", + ["boss:grade_salary_updated"] = "~y~Platová třída~s~ ~g~aktualizováno~s~", + ["boss:grade_salary_not_updated"] = "~r~Nebylo možné aktualizovat~s~ ~y~Platová třída~s~", + ["boss:employees_list"] = "Seznam zaměstnanců", + ["boss:recruit"] = "Nábor", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Požár", + ["boss:change_grade"] = "Změna třídy", + ["boss:are_you_sure"] = "Jste si jistý, že?", + ["boss:cancel"] = "Zrušit", + ["boss:employee_fired"] = "Zaměstnanci ~r~vyhozeno~s~", + ["boss:you_got_hired"] = "Byl jste ~g~najatý~s~ na ~b~%s~s~", + ["boss:you_hired"] = "Byl ~g~jste najatý~s~ %s", + ["boss:nobody_close"] = "Nikdo v blízkosti", + ["boss:grade"] = "%d. %s - Salary $%s", + ["boss:changed_grade_successfully"] = "Úspěšně změněna známka", + ["boss:your_grade_changed_to"] = "Vaše známka se změnila na ~b~%s~s~", + ["boss:how_much_to_wash"] = "Kolik peněz chceš vyprat?", + ["boss:you_washed_money"] = "Vypral jsi ~r~$%s~s~ a dostal jsi ~g~$%s~s~", + ["boss:not_enough_dirty_money"] = "Nemáš dost ~r~dirty money~s~", + ["boss:couldnt_wash_money"] = "Nemohl jsem vyprat peníze", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Stiskněte ~INPUT_CONTEXT~ pro otevření garáže", + ["garage"] = "Garáž", + ["take_vehicle"] = "Vezmi vozidlo", + ["park_vehicle"] = "Zaparkovat vozidlo", + ["no_vehicle"] = "V této garáži nejsou žádná vozidla", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Stisknutím tlačítka ~INPUT_CONTEXT~ otevřete obchod.", + ["job_shop"] = "Obchod s pracovními příležitostmi", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "Nemáte dost peněz", + ['you_bought'] = "Koupil jsi ~b~x%d~s~ ~y~%s~s~ za ~%s~$%s~s~", + ['shop_empty'] = "Tento obchod je prázdný", + ['shop:you_already_have_that_weapon'] = "Už máte ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Koupit vozidlo", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "Koupili jste vozidlo", + ['are_you_sure'] = "Určitě si koupíte %s za $%s?", + ['no_vehicles_in_garage'] = "V této garáži nejsou žádná vozidla", + ['vehicle_outside'] = "Vozidlo není v garáži", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Nejsou žádná vozidla ke koupi", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Stisknutím ~INPUT_CONTEXT~ otevřete garáž.", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Stisknutím ~INPUT_CONTEXT~ otevřete tabulku craftingu", + ['crafting_table'] = "Tabulka řemesel", + ['dont_have_ingredients'] = "Nemáte všechny ~r~required~s~ položky", + ['crafting'] = "Crafting %s", + ['you_crafted'] = "Vyrobil jsi ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Už máš ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Stiskněte ~INPUT_CONTEXT~ pro zastavení", + ['you_stopped'] = "Zastavíš, až skončí crafting", + ['crafting_table:nothing_to_craft'] = "Není co craftovat", + ["craft_amount"] = "Množství craftů", + + -- [[ Armory stuff ]] + ['open_armory'] = "Stisknutím ~INPUT_CONTEXT~ otevřete zbrojnici", + ['not_have_any_weapon'] = "Nemáte žádnou zbraň", + ['armory'] = "Zbrojnice", + ['armory_take'] = "Zbrojnice - Vezmi", + ['armory_deposit'] = "Zbrojnice - Vlož", + ['take_weapon'] = "Vezmi si zbraň", + ['deposit_weapon'] = "Vložit zbraň", + ['you_dont_have_weapon'] = "Nemáš tuto zbraň", + ['no_weapons_in_armory'] = "Nemáte zde žádné zbraně", + ['you_deposited_weapon'] = "Máš ~g~uloženo~s~ %s", + ['you_took_weapon'] = "Vzal jsi ~r~took~s~ %s", + ['you_already_have_that_weapon'] = "Už máš ~g~%s~s~", + ['weapon_ammo'] = "Munice do zbraně", + ['weapon'] = "%s - x%d kulky", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Stiskněte ~INPUT_CONTEXT~ pro otevření oblečení úlohy", + ['job_outfit'] = "Oblečení pro práci", + ['no_outfits'] = "Žádné oblečení není k dispozici", + ['civilian_outfit'] = "Civilní oblečení", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Stiskněte ~INPUT_CONTEXT~ pro teleport", + ['teleport_to'] = "Stiskněte ~INPUT_CONTEXT~ pro přechod do %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Stiskněte ~INPUT_CONTEXT~ pro otevření trezoru", + ['account'] = "%s - $%s", + ['safe'] = "Safe", + ['empty_safe'] = "Safe je prázdný", + ['nothing_to_deposit'] = "Nemáte zde co uložit", + ['withdrawn_safe'] = "Vybrali jste %s$%s %s~s~", + ['deposited_safe'] = "Vložili jste %s$%s %s~s~", + ['cash'] = "Hotovost", + ['withdraw'] = "Vybrat", + + -- [[ Market Stuff ]] + ['open_market'] = "Stisknutím ~INPUT_CONTEXT~ otevřete trh.", + ['market_item'] = "%s - $%s - $%s", + ["market"] = "Market", + ['not_enough_item'] = "Nemáte dostatek %s", + ['you_sold'] = "Prodal jsi ~b~x%d~s~ ~y~%s~s~ za %s$%s", + ['nothing_can_be_sold_yet'] = "Zatím zde nelze nic prodat", + ['market:how_many_to_sell'] = "Kolik jich chcete prodat?", + ['market:you_are_already_selling'] = "Už prodáváte", + ['market:selling'] = "Prodáváte x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Stiskněte ~INPUT_CONTEXT~ pro sklizeň", + ['harvest:harvesting'] = "Sklizeň %s", + ['harvest:press_to_stop'] = "Stiskněte ~INPUT_CONTEXT~ pro zastavení", + ['harvest:you_will_stop_on_finish'] = "Zastavíte po dokončení", + ['harvest:you_need_tool_count'] = "Potřebujete ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Potřebujete ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Stisknutím ~INPUT_CONTEXT~ otevřete nástroj pro vylepšení zbraně", + ['weapon_upgrader'] = "Vylepšovač zbraní", + ['owned_component'] = "%s - Vlastní", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Default", + ['tint_green'] = "Green", + ['tint_gold'] = "Gold", + ['tint_pink'] = "Růžová", + ['tint_army'] = "Army", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Oranžová", + ['tint_platinum'] = "Platinum", + ['components'] = "Components", + ['tints'] = "Odstíny", + ['already_have_tint'] = "Tento odstín již máte", + ['bought_tint'] = "Koupil/a jste si ~y~%s~s~ tón pro ~g~%s~s~", + ['bought_component'] = "Koupil/a jste ~y~%s~s~ za ~g~%s~s~", + ['removed_component'] = "Odstranili jste ~y~%s~s~ z ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Stiskněte ~INPUT_CONTEXT~ pro přechod ~g~on duty~s~", + ['go_off_duty'] = "Stiskněte ~INPUT_CONTEXT~ pro přechod ~r~off duty~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Stiskněte ~INPUT_CONTEXT~ pro otevření obchodu", + ['job_owned_shop'] = "Obchod s prací", + ['shop'] = "Obchod", + ['put_on_sale'] = "Dát do prodeje", + ['remove_from_sale'] = "Odstranit z prodeje", + ['item_price'] = "Cena položky", + ['invalid_price'] = "Neplatná cena", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "Obchod je prázdný", + ['job_shop_quantity'] = "Množství - x%d -> $%s", + ['job_shop_cant_afford'] = "Tohle si nemůžeš dovolit.", + ['job_shop:bought_item'] = "Vy jste ~g~koupil~s~ x%d ~y~%s~s~ za ~g~$%s~s~", + ['job_shop:add_supplies'] = "Přidat zásoby", + ['job_shop:what_to_put_on_sale'] = "Co byste chtěli dát do prodeje?", + ['job_shop:what_to_remove_from_sale'] = "Co byste chtěli stáhnout z prodeje?", + ['job_shop:what_to_restock'] = "Co byste chtěli doplnit?", + ['job_shop:how_many_to_restock'] = "Kolik kusů doplnit na sklad?", + ['job_shop:added_to_supplies'] = "Přidáno ~b~x%d~s~ ~y~%s~s~ do zásob", + ['job_shop:you_put_on_sale'] = "Dáváte do prodeje ~b~x%d~s~ ~y~%s~s~ za ~g~$%s~s~", + ['job_shop:you_removed_from_sale'] = "Odstranili jste z prodeje ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Už máte ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Nemáte nic k prodeji", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Pro zpracování stiskněte ~INPUT_CONTEXT~", + ['process:you_need'] = "Potřebujete ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Zpracování %s", + ['process:press_to_stop'] = "Stiskněte ~INPUT_CONTEXT~ pro zastavení", + ['process:you_will_stop_on_finish'] = "Po dokončení se zastavíte", + ['process:no_space'] = "Nemůžete přenášet ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Přezdívka: %s\nIdentifikátor: %s\n\n%s", + + ['log_deposited_stash'] = "Uložená položka", + ['log_deposited_stash_description'] = "Uloženo x**%d** **%s** (**%s**) v ID značky **%d**", + + ['log_took_stash'] = "Převzatá položka", + ['log_took_stash_description'] = "Took x**%d** **%s** (**%s**) z ID značky **%d**", + + ['log_deposited_weapon'] = "Uložená zbraň", + ['log_deposited_weapon_description'] = "Deposited **%s** (**%s**) s x**%d** municí v ID značky **%d**", + + ['log_took_weapon'] = "Vzal si zbraň", + ['log_took_weapon_description'] = "Vzal si **%s** (**%s**) s x**%d** municí v ID značky **%d**", + + ['log_deposited_money'] = "Uložené peníze", + ['log_deposited_money_description'] = "Deposited $**%d** ve společnosti '**%s**'", + + ['log_withdrew_money'] = "Vybrané peníze", + ['log_withdrew_money_description'] = "Staženo $**%d** od společnosti '**%s**'", + + ['log_updated_salary'] = "Aktualizovaný plat", + ['log_updated_salary_description'] = "Aktualizovaný plat v platové třídě **%d** na**$%s**", + + ['log_fired_employee'] = "Zaměstnanec propuštěn", + ['log_fired_employee_description'] = "Propuštěn hráč s identifikátorem **%s**", + + ['log_recruited_employee'] = "Přijatý zaměstnanec", + ['log_recruited_employee_description'] = "Přijat **%s**, jehož identifikátor je **%s**", + + ['log_changed_grade_employee'] = "Zaměstnanec změnil třídu", + ['log_changed_grade_employee_description'] = "Změněna třída zaměstnance **%s** na **%d**", + + ['log_sold_item'] = "Sold item", + ['log_sold_item_description'] = "Sold **x%d** **%s** for **$%s**", + ['log_washed_money'] = "Vyprané peníze", + ['log_washed_money_description'] = "Washed $**%s**", + + ['log_bought_item'] = "Koupená položka", + ['log_bought_item_description'] = "Koupeno x%d **%s** (**%s**) od značky ID **%d**", + + ['log_not_existing_item'] = "Neexistující položka", + ['log_not_existing_item_description'] = "Pokusil jsem se koupit '**%s**' ze značky ID **%d**, ale položka není v obchodě", + + ['log_bought_vehicle'] = "Koupeno vozidlo", + ['log_bought_vehicle_description'] = "Koupil '**%s**' za $**%d** od značky ID **%d**", + + ['log_not_existing_vehicle'] = "Neexistující vozidlo", + ['log_not_existing_vehicle_description'] = "Pokusil jsem se koupit '**%s**' od značky ID **%d**, ale vozidlo není v garáži", + + ['log_crafted_item'] = "Crafted item", + ['log_crafted_item_description'] = "Crafted **x%d** **%s** (**%s**) v ID značky **%d**", + + ['log_deposited_safe'] = "Uloženo do trezoru", + ['log_deposited_safe_description'] = "Uloženo $**%s** **%s** v markeru ID **%d**", + + + ['log_harvested'] = "Sklizeno", + ['log_harvested_description'] = "Sklizeno x**%d** **%s** z markeru ID **%d**", + ['log_withdrew_safe'] = "Staženo z trezoru", + ['log_withdrew_safe_description'] = "Stažení $**%s** **%s** z markeru ID **%d**", + + ['log_bought_tint'] = "Zakoupený odstín", + ['log_bought_tint_description'] = "Zakoupen odstín **%s** '**%s**' za $**%d** z markeru ID **%d**", + + ['log_removed_component'] = "Odstraněná součást", + ['log_removed_component_description'] = "Odstraněno **%s** z **%s** ze značky ID **%d**", + + ['log_bought_component'] = "Koupená komponenta", + ['log_bought_component_description'] = "Koupeno **%s** pro **%s** z ID značky **%d**", + + ['log_not_allowed_marker'] = "Není povoleno použití značky", + ['log_not_allowed_marker_description'] = "Pokusil se použít marker ID %d, ale není povolen", + + ['logs:process:title'] = "Zpracováno", + ['logs:process:description'] = "Zpracováno **x%d** **%s** na **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Dáno do prodeje", + ['logs:job_shop:put_on_sale:description'] = "Zařazeno do prodeje **x%d** **%s** pro **$%s** v ID značky **%d**", + + ['logs:job_shop:remove_from_sale'] = "Odstraněno z prodeje", + ['logs:job_shop:remove_from_sale:description'] = "Odstraněno **x%d** **%s** pro **$%s** z ID značky **%d**", + + ['logs:job_shop:bought_item'] = "Koupená položka", + ['logs:job_shop:bought_item:description'] = "Koupeno **x%d** **%s** za **$%s** v ID značky **%d**", + + ['logs:job_shop:add_to_supplies'] = "Přidáno do zásob", + ['logs:job_shop:add_to_supplies:description'] = "Přidáno **x%d** **%s** za **$%s** do zásob v ID značky **%d**", + + -- Steal action + ['logs:actions:stolen_item'] = "Ukradený předmět", + ['logs:actions:stolen_item:description'] = "Ukradl **x%d** **%s** z **%s** (%s)", + + ['logs:actions:stolen_account'] = "Ukradený účet", + ['logs:actions:stolen_account:description'] = "Ukradl $**%d** **%s** z **%s** (%s)", + + ['logs:actions:stolen_weapon'] = "Ukradená zbraň", + ['logs:actions:stolen_weapon:description'] = "Ukradl **%s** s **x%s** kulky z **%s** (%s)", + + -- Other + ["you_cant_do_this_in_a_vehicle"] = "Toto nemůžete dělat ve vozidle", + ["society_received_money_from_your_sale"] = "Vaše společnost získala ~g~$%s~s~ z vašeho prodeje", + ["actions_put_soft_handcuffs"] = "Dát/Sundat Měkká pouta", + ["actions_put__hard_handcuffs"] = "Dát/Sundat Tvrdá pouta", + ["now_you_are_on_duty"] = "Nyní jste ve službě", + ["now_you_are_off_duty"] = "Nyní jste mimo službu", + + ["item_received"] = "Obdržel jsi ~b~x%d~s~ ~y~%s~s~", + ["no_free_spawnpoints"] = "Žádný volný spawnpoint", + ["player_is_not_handcuffed"] = "Hráč není spoutaný" +} diff --git a/resources/[creators]/jobs_creator/locales/da.lua b/resources/[creators]/jobs_creator/locales/da.lua new file mode 100644 index 0000000..554d1aa --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/da.lua @@ -0,0 +1,392 @@ +locales['da'] = { + -- [[ Generic ]] + ["interact"] = "Tryk på ~INPUT_CONTEXT~ for at bruge", + ["billing_reason"] = "Regning begrundelse", + ["billing_amount"] = "Beløbet på regning", + ["no_players_nearby"] = "Ingen spillere i nærheden", + ["no_vehicles_nearby"] = "Ingen køretøjer i nærheden", + ["invoice_sent"] = "~g~$%s~s~ Regning sendt", + ["too_far"] = "For langt væk", + ["yes"] = "Ja", + ["no"] = "Nej", + ["you_need_minimum_account_money"] = "Du skal have mindst $~y~%d~s~ i ~b~%s~s~", + ["bill"] = "Regning", + ["bill_received"] = "Du har modtaget en regning
    på: $%s
    Grund: %s

    Tryk på knappen under for at acceptere regningen", + ["bill_paid"] = "Du har betalt en regning for $%s", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Åben Job menu", + ['actions_menu'] = "Job menu", + ['actions_billing'] = "Regninger", + ['actions_search'] = "Visiter", + ['actions_put_handcuffs'] = "Håndjern", + ['actions_start_dragging'] = "Træk", + ['actions_put_in_car'] = "Sæt i køretøj", + ['actions_take_from_car'] = "Tag ud af køretøj", + ['actions_menu_search'] = "Visiter spiller", + ['actions_lockpick_car'] = "Dirk bil op", + ['no_car_found'] = "Ingen bil i nærheden fundet!", + ['not_locked_vehicle'] = "Dette køretæj er ikke låst!", + ['you_need_lockpick'] = "Du skal bruge et ~r~dirkesæt~s~", + ['lockpick_used'] = "Du brugte et ~r~Dirkesæt~s~", + ['actions:lockpick:lockpickingVehicle'] = "Dirker køretøj op", + ['actions_menu_search_took'] = "Du ~g~tog~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ Blev ~r~stjålet~s~ fra dig", + ['actions_menu_search_took_money'] = "Du ~g~tog~s~ ~y~$%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~$%s %s~s~ blev ~r~stjålet~s~ fra dig!", + ['actions_menu_search_doesnt_have_weapon'] = "Spilleren ~r~har ikke~s~ dette våben", + ['actions_menu_search_took_weapon'] = "Du ~g~tog~s~ ~y~%s~s~ med ~y~%d skud~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ med ~y~%d skud~s~ blev ~r~stjålet~s~ fra dig", + ['you_need_handcuffs'] = "Du skal bruge ~r~Håndjern~s~", + ['not_handcuffed'] = "Spilleren er ikke i ~r~hånjern~s~", + ['cant_while_dragging'] = "Du kan ikke gøre dette mens du trækker en person", + ['search_inventory_empty'] = "Tasken er tom", + ['actions_menu_being_searched'] = "Du bliver visiteret", + ['actions:wash_vehicle'] = "Vask køretøj", + ['actions:washing_vehicle'] = "Vasker køretøj", + ['actions:repair_vehicle'] = "Reparer køretøj", + ['actions:repairing_vehicle'] = "Reparere køretøj", + ['actions:no_vehicles_close'] = "Intet køretøj i nærheden", + ['actions:impound_vehicle'] = "Beslaglæg køretøj", + ['actions:impounding_vehicle'] = "Beslaglægger køretøj", + ['actions:you_need'] = "Du har brug for ~y~%s~s~", + ['actions:check_identity'] = "Tjek identitet", + ['actions:check_vehicle_owner'] = "Tjek ejeren af køretøjet", + ['actions:checkVehicleOwner:owner'] = "Dette køretøj er ejet af ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Køretøjs ejer ikke fundet", + ['actions:checkVehicleOwner:car_not_found'] = "Intet køretøj i nærheden", + ['actions:no_player_found'] = "Ingen tæt på", + ['actions:checkIdentity:player_found'] = "Borger navn fundet: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Nogen~s~ tjekkede din identitet", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Legitimationskort", + ['actions:no_license_found'] = "Intet legitimationskort fundet", + ['actions:check_licenses'] = "Tjekker legitimationskort", + ['actions:driving_license'] = "Kørekort", + ['actions:weapon_license'] = "Jagttilladelse", + ['actions:license:give_remove'] = "Remove legitimationskort", + ['actions:gave_license'] = "Du ~g~gav~s~ ~y~%s~s~", + ['actions:removed_license'] = "Du ~r~fjernede~s~ ~y~%s~s~", + ['actions:heal_small'] = "Kurer små sår", + ['actions:heal_big'] = "Kurer seriøse skader", + ['actions:you_need_bandage'] = "Du mangler noget ~r~bandage~s~", + ['actions:revive'] = "Revive", + ['actions:revive:not_dead'] = "Personen er ikke død", + ['actions:you_need_medikit'] = "Du skal bruge en ~r~førstehjælpskasse~s~", + + -- [[ Stash stuff ]] + ["open_stash"] = "Tryk på ~INPUT_CONTEXT~ for at åbne kiste", + ["deposited"] = "Du lagde ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "Ikke nok ~y~%s~s~", + ["no_space"] = "Du har ikke mere plads", + ["took"] = "Du tog ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Umuligt at få x%d %s", + ["empty_inventory"] = "Din taske er tom", + ["empty_stash"] = "Denne kiste er tom", + ['stash'] = "Kiste", + ['stash_take'] = "Kiste - Tag", + ['stash_deposit'] = "Kiste - Læg", + ['quantity'] = "Antal", + ['invalid_quantity'] = "Ugyldigt antal", + ['deposit'] = "Læg", + ['take'] = "Tag", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Tryk på ~INPUT_CONTEXT~ for at åbne garderoben", + ['player_clothes'] = "Dine outfits", + ['remove_cloth'] = "Slet outfit", + ['save_cloth'] = "Gem outfit", + ['you_saved_outfit'] = "Outfit gemt", + ['delete_outfit'] = "Outfit slettet", + ['clothes'] = "Tøj", + ['outfit_label_empty'] = "Outfit navn kan ikke være tomt", + ['outfit_name'] = "Dit outfit navn", + ["wardrobe:empty"] = "Garderoben er tom", + ["wardrobe:delete"] = "%s - Slet", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Tryk på ~INPUT_CONTEXT~ for at åbne bossmenuen", + ["not_boss"] = "Du er ikke bossen", + ["boss_menu"] = "Boss menu", + ["boss:society_money"] = "Firma penge: $%s", + ["boss:withdraw"] = "Hæv firma penge", + ["boss:deposit"] = "Indsæt firma penge", + ["boss:wash_money"] = "Vask penge", + ["boss:grades"] = "Administer løninger", + ["boss:employees"] = "Administer ansatte", + ["boss:withdraw_amount"] = "Hæv penge", + ["boss:deposit_amount"] = "Indsæt penge", + ["boss:you_dont_have_enough_money"] = "Du har ikke nok penge", + ["boss:invalid_amount"] = "Ugyldigt antal", + ["boss:withdrew_money"] = "Du hævede ~g~$%s~s~", + ["boss:deposited_money"] = "Du indsatte ~g~$%s~s~", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "Ny stillings lønning", + ["boss:grade_salary_updated"] = "~y~Stillings lønning~s~ ~g~opdateret~s~", + ["boss:grade_salary_not_updated"] = "~r~Kunne ikke opdatere~s~ ~y~stillings lønning~s~", + ["boss:employees_list"] = "Medarbejderliste", + ["boss:recruit"] = "Ansæt", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Fyr / Opsig", + ["boss:change_grade"] = "Ændre stilling", + ["boss:are_you_sure"] = "Er du sikker?", + ["boss:cancel"] = "Annuller", + ["boss:employee_fired"] = "Medarbejder blev ~r~fyret~s~", + ["boss:you_got_hired"] = "Du blev ~g~ansat~s~ hos ~b~%s~s~", + ["boss:you_hired"] = "Du ~g~ansatte~s~ %s", + ["boss:nobody_close"] = "Ingen tæt på", + ["boss:grade"] = "%d. %s - Lønning $%s", + ["boss:changed_grade_successfully"] = "Ændrede stilling", + ["boss:your_grade_changed_to"] = "Din stilling blev ændret til ~b~%s~s~", + ["boss:how_much_to_wash"] = "Hvor mange penge vil du hvidvaske?", + ["boss:you_washed_money"] = "Du hvidvaskede ~r~$%s~s~ og modtog ~g~$%s~s~", + ["boss:not_enough_dirty_money"] = "Du har ikke nok ~r~Sorte penge~s~", + ["boss:couldnt_wash_money"] = "Kunne ikke vaske penge", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Tryk på ~INPUT_CONTEXT~ for at åbne garagen", + ["garage"] = "Garage", + ["take_vehicle"] = "Tag bil", + ["park_vehicle"] = "Parker bil", + ["no_vehicle"] = "Der er ingen biler i garagen", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Tryk på ~INPUT_CONTEXT~ for at åbne butikken", + ["job_shop"] = "Jobcenter", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "Du har ikke nok penge", + ['you_bought'] = "Du købte ~b~x%d~s~ ~y~%s~s~ for ~%s~$%s~s~", + ['shop_empty'] = "Denne butik er tom", + ['shop:you_already_have_that_weapon'] = "Du har allerede ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Køb køretøj", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "Du ~g~købte~s~ et køretøj", + ['are_you_sure'] = "Er du sikker på at du vil købe %s for $%s?", + ['no_vehicles_in_garage'] = "Der er intet køretøj i denne garage", + ['vehicle_outside'] = "Køretøjet er ikke i en garage", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Der er ingen køretøjer at købe", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Tryk på ~INPUT_CONTEXT~ for at åbne garagen", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Tryk på ~INPUT_CONTEXT~ for at åbne håndværksbordet", + ['crafting_table'] = "Håndværksbord", + ['dont_have_ingredients'] = "Du har ikke de ~r~nødtvendige~s~ genstande", + ['crafting'] = "Fremstilning %s", + ['you_crafted'] = "Du lavede ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Du har allerede ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Tryk på ~INPUT_CONTEXT~ for at stoppe", + ['you_stopped'] = "Du vil stoppe når du er færdig med at fremstille", + ['crafting_table:nothing_to_craft'] = "Intet at lave", + ["craft_amount"] = "Antal der skal fremstilles", + + -- [[ Armory stuff ]] + ['open_armory'] = "Tryk på ~INPUT_CONTEXT~ for at åbne våbenskabet", + ['not_have_any_weapon'] = "Du har ikke nogle våben", + ['armory'] = "Våbenskab", + ['armory_take'] = "Våbenskab - Tag", + ['armory_deposit'] = "Våbenskab - Læg", + ['take_weapon'] = "Tag våben", + ['deposit_weapon'] = "Læg våben", + ['you_dont_have_weapon'] = "Du ~r~har ikke~s~ dette våben", + ['no_weapons_in_armory'] = "Der er ingen våben her", + ['you_deposited_weapon'] = "Du ~g~lagde~s~ %s", + ['you_took_weapon'] = "Du ~r~tog~s~ %s", + ['you_already_have_that_weapon'] = "Du har allerede ~g~%s~s~", + ['weapon_ammo'] = "Våben ammunition", + ['weapon'] = "%s - x%d skud", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Tryk på ~INPUT_CONTEXT~ for at åbne job outfit menuen", + ['job_outfit'] = "Job outfits", + ['no_outfits'] = "ingen outfits tilgængelige", + ['civilian_outfit'] = "Civil outfit", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Tryk på ~INPUT_CONTEXT~ for at teleportere", + ['teleport_to'] = "Tryk på ~INPUT_CONTEXT~ for at gå til %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Tryk på ~INPUT_CONTEXT~ for at åbne pengeskabet", + ['account'] = "%s - $%s", + ['safe'] = "Pengeskab", + ['empty_safe'] = "Pengeskab er tomt", + ['nothing_to_deposit'] = "Du har intet at lægge her", + ['withdrawn_safe'] = "Du tog %s$%s %s~s~", + ['deposited_safe'] = "Du lagde %s$%s %s~s~", + ['cash'] = "Penge", + ['withdraw'] = "Tag", + + -- [[ Market Stuff ]] + ['open_market'] = "Tryk på ~INPUT_CONTEXT~ for at åbne butikken", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Butik", + ['not_enough_item'] = "Du har ikke nok %s", + ['you_sold'] = "Du solgte ~b~x%d~s~ ~y~%s~s~ for %s$%s", + ['nothing_can_be_sold_yet'] = "Du kan ikke sælge noget her endnu", + ['market:how_many_to_sell'] = "Hvor mange vil du sælge?", + ['market:you_are_already_selling'] = "Du er allerede igang med at sælge", + ['market:selling'] = "Sælger x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Tryk på ~INPUT_CONTEXT~ for at høste", + ['harvest:harvesting'] = "Høster %s", + ['harvest:press_to_stop'] = "Tryk på ~INPUT_CONTEXT~ for at stoppe", + ['harvest:you_will_stop_on_finish'] = "Du vil stoppe når du er færdig", + ['harvest:you_need_tool_count'] = "Du skal bruge ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Du mangler ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Tryk på ~INPUT_CONTEXT~ for at åbne våbenværlstedet", + ['weapon_upgrader'] = "Våbenværksted", + ['owned_component'] = "%s - Ejet", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Default", + ['tint_green'] = "Grøn", + ['tint_gold'] = "Guld", + ['tint_pink'] = "Pink", + ['tint_army'] = "Militær", + ['tint_lspd'] = "Politi", + ['tint_orange'] = "Orange", + ['tint_platinum'] = "Platinum", + ['components'] = "Komponenter", + ['tints'] = "Farver", + ['already_have_tint'] = "Du har allerede denne farve", + ['bought_tint'] = "Du købte ~y~%s~s~ farve for ~g~%s~s~", + ['bought_component'] = "Du købte ~y~%s~s~ for ~g~%s~s~", + ['removed_component'] = "Du fjernede ~y~%s~s~ fra ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "tryk på ~INPUT_CONTEXT~ for at ~g~på arbejde~s~", + ['go_off_duty'] = "Press ~INPUT_CONTEXT~ to go ~r~fra arbejde~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Tryk på ~INPUT_CONTEXT~ for at åbne butikken", + ['job_owned_shop'] = "Job butik", + ['shop'] = "Butik", + ['put_on_sale'] = "Sæt til salg", + ['remove_from_sale'] = "Fjern fra butik", + ['item_price'] = "Genstands pris", + ['invalid_price'] = "Ugyldig pris", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "Denne butik er tom", + ['job_shop_quantity'] = "Antal tilgængelig - x%d -> $%s", + ['job_shop_cant_afford'] = "Du ~r~har ikke råd~s~ til dette", + ['job_shop:bought_item'] = "Du ~g~købte~s~ x%d ~y~%s~s~ for ~g~$%s~s~", + ['job_shop:add_supplies'] = "Tilføj forsyninger", + ['job_shop:what_to_put_on_sale'] = "Hvad vil du til salg?", + ['job_shop:what_to_remove_from_sale'] = "Hvad vil du fjerne fra butikken?", + ['job_shop:what_to_restock'] = "Hvad vil du fylde på lager igen?", + ['job_shop:how_many_to_restock'] = "Hvor mange vil du fylde på lager?", + ['job_shop:added_to_supplies'] = "Tilføjede ~b~x%d~s~ ~y~%s~s~ til lageret", + ['job_shop:you_put_on_sale'] = "Du satte ~b~x%d~s~ ~y~%s~s~ til salg for ~g~$%s~s~", + ['job_shop:you_removed_from_sale'] = "Du fjernede ~b~x%d~s~ fra ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Du har allerede ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Du har intet at sælge", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Tryk på ~INPUT_CONTEXT~ for at bearbejde", + ['process:you_need'] = "Du skal bruge ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Bearbejder %s", + ['process:press_to_stop'] = "Tryk ~INPUT_CONTEXT~ for at stoppe", + ['process:you_will_stop_on_finish'] = "Du vil stoppe når du er færdig", + ['process:no_space'] = "Du kan ikke have ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Kaldenavn: %s\nIdentifier: %s\n\n%s", + + ['log_deposited_stash'] = "Lage genstand", + ['log_deposited_stash_description'] = "Lagde x**%d** **%s** (**%s**) i marker ID **%d**", + + ['log_took_stash'] = "Tog genstand", + ['log_took_stash_description'] = "Tog x**%d** **%s** (**%s**) fra marker ID **%d**", + + ['log_deposited_weapon'] = "Lagde våben", + ['log_deposited_weapon_description'] = "Lagde **%s** (**%s**) med x**%d** skud i marker ID **%d**", + + ['log_took_weapon'] = "Tog vpben", + ['log_took_weapon_description'] = "Tog **%s** (**%s**) med x**%d** skud i marker ID **%d**", + + ['log_deposited_money'] = "Indsatte", + ['log_deposited_money_description'] = "Indsatte $**%d** i firmakasse '**%s**'", + + ['log_withdrew_money'] = "Hævede penge", + ['log_withdrew_money_description'] = "Hævded $**%d** fra firmakasse '**%s**'", + + ['log_updated_salary'] = "Ændret løn", + ['log_updated_salary_description'] = "Opdaterde løn på stilling fra **%d** til **$%s**", + + ['log_fired_employee'] = "Ansat fyret", + ['log_fired_employee_description'] = "Fyrede spiller med identifier **%s**", + + ['log_recruited_employee'] = "Ansatte", + ['log_recruited_employee_description'] = "Ansatte **%s** med identifier **%s**", + + ['log_changed_grade_employee'] = "Ændrede stilling på medarbejder", + ['log_changed_grade_employee_description'] = "Ændrede stilling på **%s** til **%d**", + + ['log_washed_money'] = "Hvidvaskede penge", + ['log_washed_money_description'] = "Hvidvaskede $**%s**", + + ['log_sold_item'] = "Solgte genstand", + ['log_sold_item_description'] = "Solgte **x%d** **%s** for **$%s**", + + ['log_bought_item'] = "Købte genstand", + ['log_bought_item_description'] = "Købte x%d **%s** (**%s**) fra marker ID **%d**", + + ['log_not_existing_item'] = "Genstand eksitere ikke", + ['log_not_existing_item_description'] = "Prøvede at købe '**%s**' fra marker ID **%d**, men genstanden er ikke i shoppen", + + ['log_bought_vehicle'] = "Købte køretøj", + ['log_bought_vehicle_description'] = "Købte '**%s**' for $**%d** fra marker ID **%d**", + + ['log_not_existing_vehicle'] = "Køretøj eksitere ikke", + ['log_not_existing_vehicle_description'] = "Prøvede at købe '**%s**' fra marker ID **%d**, men køretøjet er ikke i garagen", + + ['log_crafted_item'] = "Lavede genstand", + ['log_crafted_item_description'] = "Lavede **x%d** **%s** (**%s**) i marker ID **%d**", + + ['log_deposited_safe'] = "Indsat i pengeskab", + ['log_deposited_safe_description'] = "Indsatte $**%s** **%s** i marker ID **%d**", + + ['log_withdrew_safe'] = "Hævede fra pengeskab", + ['log_withdrew_safe_description'] = "Hævede $**%s** **%s** fra marker ID **%d**", + + ['log_harvested'] = "Høstede", + ['log_harvested_description'] = "Høstede x**%d** **%s** fra marker ID **%d**", + + ['log_bought_tint'] = "Købte farve", + ['log_bought_tint_description'] = "Købte **%s** '**%s**' farve for $**%d** fra marker ID **%d**", + + ['log_removed_component'] = "Fjernede Komponent", + ['log_removed_component_description'] = "Fjernede **%s** fra **%s** fra marker ID **%d**", + + ['log_bought_component'] = "Købte Komponent", + ['log_bought_component_description'] = "Købte **%s** for **%s** fra marker ID **%d**", + + ['log_not_allowed_marker'] = "Ikke tilladelse til at bruge marker", + ['log_not_allowed_marker_description'] = "Prøvede at bruge marker ID %d Men har ikke tilladelse", + + ['logs:process:title'] = "Bearbejdede", + ['logs:process:description'] = "Bearbejdede **x%d** **%s** til **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Sæt til salg", + ['logs:job_shop:put_on_sale:description'] = "Satte **x%d** **%s** til salg for **$%s** i marker ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Fjernede fra butikken", + ['logs:job_shop:remove_from_sale:description'] = "Fjernede **x%d** **%s** fra **$%s** fra marker ID **%d**", + + ['logs:job_shop:bought_item'] = "Købte genstand", + ['logs:job_shop:bought_item:description'] = "Købte **x%d** **%s** for **$%s** i marker ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Tilføjet til lager", + ['logs:job_shop:add_to_supplies:description'] = "Tilføjede **x%d** **%s** for **$%s** til lageret i marker ID **%d**", +} + diff --git a/resources/[creators]/jobs_creator/locales/de.lua b/resources/[creators]/jobs_creator/locales/de.lua new file mode 100644 index 0000000..d6de304 --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/de.lua @@ -0,0 +1,417 @@ +-------------------- +-- Translation by -- +-- Mubarak#6666 -- +-------------------- + +locales['de'] = { + -- [[ Generic ]] + ["interact"] = "Drücke ~INPUT_CONTEXT~ um zu interagieren", + ["billing_reason"] = "Rechnungsgrund", + ["billing_amount"] = "Rechnungssumme", + ["no_players_nearby"] = "Keine Person in der Nähe", + ["no_vehicles_nearby"] = "Kein Fahrzeug in der Nähe", + ["invoice_sent"] = "~g~$%s~s~ Rechnung versendet", + ["too_far"] = "Zu weit", + ["yes"] = "Ja", + ["no"] = "Nein", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Öffne Aktionsmenü", + ['actions_menu'] = "Aktionsmenü", + ['actions_billing'] = "Rechnungsstellung", + ['actions_search'] = "Durchsuchen", + ['actions_put_handcuffs'] = "Handfesseln anlegen", + ['actions_start_dragging'] = "Tragen", + ['actions_put_in_car'] = "Ins Fahrzeug setzen", + ['actions_take_from_car'] = "Aus dem Fahrzeug holen", + ['actions_menu_search'] = "Durchsuchen", + ['actions_lockpick_car'] = "Fahrzeug aufbrechen", + ['no_car_found'] = "Kein Fahrzeug in der Nähe gefunden", + ['not_locked_vehicle'] = "Das Fahrzeug ist nicht abgeschlossen", + ['you_need_lockpick'] = "Du brauchst einen ~r~Dietrich~s~", + ['lockpick_used'] = "Du hast ein ~r~Dietrich~s~ benutzt", + ['actions:lockpick:lockpickingVehicle'] = "Fahrzeug aufbrechen...", + ['actions_menu_search_took'] = "Du hast ~y~x%d %s~s~ ~g~genommen~s~", + ['actions_menu_search_stolen'] = "Dir wurden ~y~x%d %s~s~ ~r~gestohlen~s~", + ['actions_menu_search_took_money'] = "Du ~g~nimmst~s~ ~y~$%s %s~s~ an dich", + ['actions_menu_search_stolen_money'] = "Dir wurden ~y~$%s %s~s~ ~r~gestohlen~s~", + ['actions_menu_search_doesnt_have_weapon'] = "Spieler besitzt diese Waffe ~r~nicht~s~", + ['actions_menu_search_took_weapon'] = "Du ~g~entimmst~s~ ~y~%s~s~ mit ~y~%d Kugeln~s~", + ['actions_menu_search_stolen_weapon'] = "Dir wurde ~y~%s~s~ mit ~y~%d Kugeln~s~ ~r~geklaut~s~", + ['you_need_handcuffs'] = "Du benötigst ~r~Kabelbinder~s~", + ['not_handcuffed'] = "Person ist nicht ~r~gefesselt~s~", + ['cant_while_dragging'] = "Während dem tragen nicht möglich!", + ['search_inventory_empty'] = "Inventar ist leer", + ['actions_menu_being_searched'] = "Du wirst durchsucht...", + ['actions:wash_vehicle'] = "Fahrzeug waschen", + ['actions:washing_vehicle'] = "Fahrzeug wird gewaschen...", + ['actions:repair_vehicle'] = "Fahrzeug Reparieren", + ['actions:repairing_vehicle'] = "Reperiere Fahrzeug...", + ['actions:no_vehicles_close'] = "Kein Fahrzeug in der Nähe", + ['actions:impound_vehicle'] = "Fahrzeug beschlagnahmen", + ['actions:impounding_vehicle'] = "Fahrzeug wird abgeschleppt...", + ['actions:you_need'] = "Du benötigst ~y~%s~s~", + ['actions:check_identity'] = "Überprüfe Identität...", + ['actions:check_vehicle_owner'] = "Überprüfe Fahrzeugbesitzer", + ['actions:checkVehicleOwner:owner'] = "Das Fahrzeug gehört ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Fahrzeugbesitzer konnte nicht identifiziert werden", + ['actions:checkVehicleOwner:car_not_found'] = "Kein Fahrzeug in der Nähe", + ['actions:no_player_found'] = "Niemand in der Nähe", + ['actions:checkIdentity:player_found'] = "Name gefunden: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "Deine Identität wurde überprüft", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Lizenzen", + ['actions:no_license_found'] = "Keine Lizenz gefunden", + ['actions:check_licenses'] = "Überprüfe Lizenzen", + ['actions:driving_license'] = "Führerschein", + ['actions:weapon_license'] = "Waffenschein", + ['actions:license:give_remove'] = "Entferne Lizenzen", + ['actions:gave_license'] = "Du ~g~gibst~s~ ~y~%s~s~", + ['actions:removed_license'] = "Du hast ~y~%s~s~ ~r~entzogen~s~", + ['actions:heal_small'] = "Heile kleine wunden", + ['actions:heal_big'] = "Behandle ernsthafte Verletzungen", + ['actions:you_need_bandage'] = "Du benötigst eine ~r~Bandage~s~", + ['actions:revive'] = "Wiederbeleben", + ['actions:you_need_medikit'] = "Du benötigst ein ~r~Medikit~s~", + + -- [[ Stash stuff ]] + ["open_stash"] = "Drücke ~INPUT_CONTEXT~ um das Lager zu öffnen", + ["deposited"] = "Du hast ~b~x%d~s~ ~y~%s~s~ eingelagert", + ["not_enough"] = "Du hast nicht genug ~y~%s~s~", + ["no_space"] = "Du hast keinen Platz", + ["took"] = "Du hast ~b~x%d~s~ ~y~%s~s~ herausgenommen", + ["impossible_take"] = "Herausnehmen von x%d %s nicht möglich", + ["empty_inventory"] = "Dein Inventar ist leer", + ["empty_stash"] = "Das Lager ist leer", + ['stash'] = "Lager", + ['stash_take'] = "Lager - Nehmen", + ['stash_deposit'] = "Lager - Ablegen", + ['quantity'] = "Menge", + ['invalid_quantity'] = "Ungültige Menge", + ['deposit'] = "Ablegen", + ['take'] = "Nehmen", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Drücke ~INPUT_CONTEXT~ um den Kleiderschrank zu öffnen", + ['player_clothes'] = "Deine Outfits", + ['remove_cloth'] = "Outfit löschen", + ['save_cloth'] = "Aktuelles Outfit speichern", + ['you_saved_outfit'] = "Outfit gespeichert", + ['delete_outfit'] = "Outfit gelöscht", + ['clothes'] = "Kleidung", + ['outfit_label_empty'] = "Outfitname darf nicht leer sein", + ['outfit_name'] = "Dein Outfitname", + ["wardrobe:empty"] = "Kleiderschrank ist leer", + ["wardrobe:delete"] = "%s - Löschen", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Drücke ~INPUT_CONTEXT~, um das Boss Menü zu öffnen", + ["not_boss"] = "Du bist kein Boss", + ["boss_menu"] = "Boss Menü", + ["boss:society_money"] = "Firmengeld: $%s", + ["boss:withdraw"] = "Firmengeld abheben", + ["boss:deposit"] = "Firmengeld einzahlen", + ["boss:wash_money"] = "Geld Waschen", + ["boss:grades"] = "Verwalte Gehalt", + ["boss:employees"] = "Verwalte Mitarbeiter", + ["boss:withdraw_amount"] = "Auszahlungsbetrag", + ["boss:deposit_amount"] = "Einzahlungsbetrag", + ["boss:you_dont_have_enough_money"] = "Du hast nicht genpgend Geld", + ["boss:invalid_amount"] = "Ungültige Summe", + ["boss:withdrew_money"] = "Du hast ~g~$%s~s~ abgehoben", + ["boss:deposited_money"] = "Du hast ~g~$%s~s~ eingezahlt", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "Neues Gehalt", + ["boss:grade_salary_updated"] = "~y~ Gehalt ~s~ ~g~aktualisiert~s~", + ["boss:grade_salary_not_updated"] = "~r~Konnte~s~ das ~y~Gehalt nicht aktualisieren~s~", + ["boss:employees_list"] = "Mitarbeiterliste", + ["boss:recruit"] = "Einstellen", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Feuern", + ["boss:change_grade"] = "Befördern/Degradieren", + ["boss:are_you_sure"] = "Bist du dir sicher?", + ["boss:cancel"] = "Abbrechen", + ["boss:employee_fired"] = "Mitarbeiter ~r~gefeuert~s~", + ["boss:you_got_hired"] = "Du wurdest bei ~b~%s~s~ ~g~eingestellt~s~", + ["boss:you_hired"] = "Du hast %s ~g~angestellt~s~ ", + ["boss:nobody_close"] = "Niemand in der Nähe", + ["boss:grade"] = "%d. %s - Gehalt $%s", + ["boss:changed_grade_successfully"] = "Erfolgreich befördert/degradiert", + ["boss:your_grade_changed_to"] = "Du wurdest zu ~b~%s~s~ befördert/degradiert", + ["boss:how_much_to_wash"] = "Wie viel Geld willst du waschen?", + ["boss:you_washed_money"] = "Du hast ~r~$%s~s~ gewaschen und ~g~$%s~s~ bekommen", + ["boss:not_enough_dirty_money"] = "Du hast nicht genug ~r~Schwarzgeld~s~", + ["boss:couldnt_wash_money"] = "Konnte das Geld nicht waschen", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Drücke ~INPUT_CONTEXT~ um die Garage zu öffnen", + ["garage"] = "Garage", + ["take_vehicle"] = "Fahrzeug ausparken", + ["park_vehicle"] = "Fahrzeug einparken", + ["no_vehicle"] = "In dieser Garage befinden sich keine Fahrzeuge", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Drücke ~INPUT_CONTEXT~ um den Shop zu öffnen", + ["job_shop"] = "Job-Shop", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "Du hast nicht genug Geld", + ['you_bought'] = "Du hast ~b~x%d~s~ ~y~%s~s~ für ~%s~$%s~s~ gekauft", + ['shop_empty'] = "Dieser Laden ist leer", + ['shop:you_already_have_that_weapon'] = "Du besitzt bereits ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Fahrzeug kaufen", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "Du hast ein Fahrzeug ~g~gekauft~s~", + ['are_you_sure'] = "Möchtest du wirklich %s für $%s kaufen?", + ['no_vehicles_in_garage'] = "In dieser Garage befinden sich keine Fahrzeuge", + ['vehicle_outside'] = "Fahrzeug steht nicht in der Garage", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Es gibt keine Fahrzeuge zu kaufen", + + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Drücke ~INPUT_CONTEXT~ um die Garage zu öffnen", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Drücke ~INPUT_CONTEXT~ um die Werkbank zu öffnen", + ['crafting_table'] = "Werkbank", + ['dont_have_ingredients'] = "Du besitzt nicht alle ~r~erforderlichen~s~ Gegenstände", + ['crafting'] = "Herstellen %s", + ['you_crafted'] = "Du hast ~b~x%d~s~ ~g~%s~s~ hergestellt", + ['already_have'] = "Du besitzt bereits ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Drücke ~INPUT_CONTEXT~ um abzubrechen", + ['you_stopped'] = "Du wirst aufhören, wenn die Herstellung endet", + ['crafting_table:nothing_to_craft'] = "Keine Herrstelungsmöglichkeiten", + + -- [[ Armory stuff ]] + ['open_armory'] = "Drücke ~INPUT_CONTEXT~ um die Waffenkammer zu öffnen", + ['not_have_any_weapon'] = "Du besitzt keine Waffe", + ['armory'] = "Waffenkammer", + ['armory_take'] = "Waffenkammer - herausnehmen", + ['armory_deposit'] = "Waffenkammer - einlagern", + ['take_weapon'] = "Waffe nehmen", + ['deposit_weapon'] = "Waffe einlagern", + ['you_dont_have_weapon'] = "Du besitzt diese Waffe ~r~nicht~s~", + ['no_weapons_in_armory'] = "Hier gibt es keine Waffen", + ['you_deposited_weapon'] = "Du hast %s ~g~eingelagert~s~", + ['you_took_weapon'] = "Du hast dir %s ~r~herausgenommen~s~", + ['you_already_have_that_weapon'] = "Du besitzt bereits ein/e ~g~%s~s~", + ['weapon_ammo'] = "Waffenmunition", + ['weapon'] = "%s - x%d Kugeln", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Drücke ~INPUT_CONTEXT~ um die Outfits des Jobs zu öffnen", + ['job_outfit'] = "Job-Outfits", + ['no_outfits'] = "Keine Outfits verfügbar", + ['civilian_outfit'] = "Zivilkleidung", + + + -- [[ Teleport Stuff ]] + ['teleport'] = "Drücke ~INPUT_CONTEXT~ um dich zu teleportieren", + ['teleport_to'] = "Drücke ~INPUT_CONTEXT~ um nach %s zu gehen", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Drücke ~INPUT_CONTEXT~ um den Tresor öffnen", + ['account'] = "%s - $%s", + ['safe'] = "Tresor", + ['empty_safe'] = "Tresor ist leer", + ['nothing_to_deposit'] = "Du hast nichts zum einlagern", + ['withdrawn_safe'] = "Du hast %s$%s %s~s~ herausgenommen", + ['deposited_safe'] = "Du hast %s$%s %s~s~ eingelagert", + ['cash'] = "Geld", + ['withdraw'] = "Nehmen", + + -- [[ Market Stuff ]] + ['open_market'] = "Drücke ~INPUT_CONTEXT~ um den Markt öffnen", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Markt", + ['not_enough_item'] = "Du hast nicht genug %s", + ['you_sold'] = "Du hast ~b~x%d~s~ ~y~%s~s~ für %s$%s verkauft", + ['nothing_can_be_sold_yet'] = "Hier kann noch nichts verkauft werden", + ['market:how_many_to_sell'] = "Wie viel möchtest du verkaufen?", + ['market:you_are_already_selling'] = "Du bist bereits am verkaufen", + ['market:selling'] = "Verkaufe x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Drücke ~INPUT_CONTEXT~ um zu sammeln", + ['harvest:harvesting'] = "Sammle %s", + ['harvest:press_to_stop'] = "Drücke ~INPUT_CONTEXT~ um zu stoppen", + ['harvest:you_will_stop_on_finish'] = "Du wirst aufhören, wenn du fertig bist", + ['harvest:you_need_tool_count'] = "Du benötigst ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Du benötigst ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Drücke ~INPUT_CONTEXT~ um die Waffen-Werkbank zu öffnen", + ['weapon_upgrader'] = "Waffen-Upgrade", + ['owned_component'] = "%s - Im Besitz", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Standard", + ['tint_green'] = "Grün", + ['tint_gold'] = "Gold", + ['tint_pink'] = "Pink", + ['tint_army'] = "Army", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Orange", + ['tint_platinum'] = "Platin", + ['components'] = "Komponenten", + ['tints'] = "Farbtöne", + ['already_have_tint'] = "Du besitzt diese Tönung bereits", + ['bought_tint'] = "Du hast ~y~%s~s~ für ~g~%s~s~ gekauft", + ['bought_component'] = "Du hast ~y~%s~s~ für ~g~%s~s~ gekauft", + ['removed_component'] = "Du hast ~y~%s~s~ von ~g~%s~s~ entfernt", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Drücke ~INPUT_CONTEXT~ um ~g~in den Dienst~s~ zu gehen", + ['go_off_duty'] = "Drücke ~INPUT_CONTEXT~ um ~r~aus dem Dienst~s~ zu gehen", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Drücke ~INPUT_CONTEXT~ um den Laden zu öffnen", + ['job_owned_shop'] = "Job-Shop", + ['shop'] = "Shop", + ['put_on_sale'] = "Zum Verkauf anbieten", + ['remove_from_sale'] = "Aus dem Angebot entfernen", + ['item_price'] = "Stückpreis", + ['invalid_price'] = "Ungültiger Preis", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "Der Laden ist leer", + ['job_shop_quantity'] = "Menge - x%d -> $%s", + ['job_shop_cant_afford'] = "Du kannst dir das ~r~nicht~s~ leisten", + ['job_shop:bought_item'] = "Du hast x%d ~y~%s~s~ für ~g~$%s~s~ ~g~gekauft~s~", + ['job_shop:add_supplies'] = "Zubehör hinzufügen", + ['job_shop:what_to_put_on_sale'] = "Was möchtest du verkaufen?", + ['job_shop:what_to_remove_from_sale'] = "Was möchtest du aus dem Verkauf entfernen?", + ['job_shop:what_to_restock'] = "Was möchtest du aufstocken?", + ['job_shop:how_many_to_restock'] = "Wie viel soll dem Bestand hinzugefügt werden?", + ['job_shop:added_to_supplies'] = "~b~x%d~s~ ~y~%s~s~ zum Lager hinzugefügt", + ['job_shop:you_put_on_sale'] = "Du hast ~b~x%d~s~ ~y~%s~s~ für ~g~$%s~s~ angeboten", + ['job_shop:you_removed_from_sale'] = "Du hast ~b~x%d~s~ ~y~%s~s~ zurückgenommen", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Du besitzt bereits ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Du hast nichts zu verkaufen", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Drücke ~INPUT_CONTEXT~ zum verarbeiten", + ['process:you_need'] = "Du benötigst ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Verarbeite %s", + ['process:press_to_stop'] = "Drücke ~INPUT_CONTEXT~ um aufzuhören", + ['process:you_will_stop_on_finish'] = "Wenn du fertig bist, hörst du auf", + ['process:no_space'] = "Du kannst ~b~x%d~s~ ~y~%s~s~ nicht tragen", + + + -- [[ Logs stuff ]] + ['log:generic'] = "Nickname: %s\nIndentifikation: %s\n\n%s", + + ['log_deposited_stash'] = "Gegensttand - Eingelagert", + ['log_deposited_stash_description'] = "Verstaut x**%d** **%s** (**%s**) in markierung ID **%d**", + + ['log_took_stash'] = "Gegenstand - Herausgenommen", + ['log_took_stash_description'] = "Took x**%d** **%s** (**%s**) from marker ID **%d**", + + ['log_deposited_weapon'] = "Waffe - Eingelagert", + ['log_deposited_weapon_description'] = "Eingelagert **%s** (**%s**) mit x**%d** Munition in markierung ID **%d**", + + ['log_took_weapon'] = "Waffe - Herausgenommen", + ['log_took_weapon_description'] = "Genommen **%s** (**%s**) mit x**%d** Munition in markierung ID **%d**", + + ['log_deposited_money'] = "Geld - Eingelagert", + ['log_deposited_money_description'] = "Eingelagert $**%d** in Firmengeld '**%s**'", + + ['log_withdrew_money'] = "Geld - Ausgezahlt", + ['log_withdrew_money_description'] = "Ausgezahlt $**%d** von Firmengeld '**%s**'", + + ['log_updated_salary'] = "Gehalt bearbeitet", + ['log_updated_salary_description'] = "Gehalt vom Rang bearbeitet **%d** zu **$%s**", + + ['log_fired_employee'] = "Mitarbeiter gefeuert", + ['log_fired_employee_description'] = "Spieler mit Indentität gefeuert **%s**", + + ['log_recruited_employee'] = "Mitarbeiter Eingestellt", + ['log_recruited_employee_description'] = "Eingestellt **%s** mit Identität **%s**", + + ['log_changed_grade_employee'] = "Befördern/Degradieren zu Rang", + ['log_changed_grade_employee_description'] = "Befördern/Degradieren vom Mitarbeiter **%s** zu **%d**", + + ['log_washed_money'] = "Geld gewaschen", + ['log_washed_money_description'] = "Gewaschen $**%s**", + + ['log_sold_item'] = "Verkaufter Gegenstand", + ['log_sold_item_description'] = "Verkauft **x%d** **%s** für **$%s**", + + ['log_bought_item'] = "Gegenstand gekauft", + ['log_bought_item_description'] = "Gekauft x%d **%s** (**%s**) für vom Markierung ID **%d**", + + ['log_not_existing_item'] = "Gegenstand exestiertnicht", + ['log_not_existing_item_description'] = "Versucht zu kaufen '**%s**' vom markierung ID **%d**, aber der gegenstand ist nicht im Shop", + + ['log_bought_vehicle'] = "Fahrzeug gekauft", + ['log_bought_vehicle_description'] = "Gekauft '**%s**' für $**%d** von Markierung ID **%d**", + + ['log_not_existing_vehicle'] = "Fahrzeug exestiert nicht", + ['log_not_existing_vehicle_description'] = "Versucht zu kaufen '**%s**' vom Markierung ID **%d**, aber das Fahrzeug exestiert nicht", + + ['log_crafted_item'] = "Hergestellter Gegenstand", + ['log_crafted_item_description'] = "Hergestellt **x%d** **%s** (**%s**) in Markierung ID **%d**", + + ['log_deposited_safe'] = "Eingelagert im Tresor", + ['log_deposited_safe_description'] = "Eingelagert $**%s** **%s** in markierung ID **%d**", + + ['log_withdrew_safe'] = "Ausgelagert vom Tresor", + ['log_withdrew_safe_description'] = "Ausgelagert $**%s** **%s** vom markierung ID **%d**", + + ['log_harvested'] = "Gesammelt", + ['log_harvested_description'] = "Gesammelt x**%d** **%s** von markierung ID **%d**", + + ['log_bought_tint'] = "Gekaufter Farbton", + ['log_bought_tint_description'] = "Farbton **%s** '**%s**' gekauft für $**%d** vom markierung ID **%d**", + + ['log_removed_component'] = "Komponent entfernt", + ['log_removed_component_description'] = "Entfernt **%s** von **%s** vom markierung ID **%d**", + + ['log_bought_component'] = "Komponent gekauft", + ['log_bought_component_description'] = "Gekauft **%s** für **%s** vom Markierung ID **%d**", + + ['log_not_allowed_marker'] = "Nicht erlaubter Marker benutzt", + ['log_not_allowed_marker_description'] = "Versuchte Markierung ID %d zu benutzen hat aber nicht die erlaubniss dazu", + + ['logs:process:title'] = "Verarbeitet", + ['logs:process:description'] = "Verarbeitet **x%d** **%s** zu **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Zum verkaufen zur verfügung gestellt", + ['logs:job_shop:put_on_sale:description'] = "Zum verkaufen gestellt **x%d** **%s** for **$%s** in markierung ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Entfernt zum Verkaufen", + ['logs:job_shop:remove_from_sale:description'] = "Entfernt **x%d** **%s** für **$%s** vom markierung ID **%d**", + + ['logs:job_shop:bought_item'] = "Gegenstand - Gekauft", + ['logs:job_shop:bought_item:description'] = "Gekauft **x%d** **%s** für **$%s** in markierung ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Zur lieferung hinzugefügt", + ['logs:job_shop:add_to_supplies:description'] = "Hinzugefügt **x%d** **%s** für **$%s** zur lieferung in markierung ID **%d**", + -- Steal action + ['logs:actions:stolen_item'] = "Item gestohlen", + ['logs:actions:stolen_item:description'] = "Hat gestohlen **x%d** **%s** von **%s** (%s)", + + ['logs:actions:stolen_account'] = "Cash gestohlen", + ['logs:actions:stolen_account:description'] = "Hat gestohlen $**%d** **%s** von **%s** (%s)", + + ['logs:actions:stolen_weapon'] = "Waffen gestohlen", + ['logs:actions:stolen_weapon:description'] = "Hat gestohlen **%s** mit **x%s** magazin von **%s** (%s)", + + -- Other + ["you_cant_do_this_in_a_vehicle"] = "Du kannst das nicht in einem Fahrzeug machen", + ["society_received_money_from_your_sale"] = "Ihre Gesellschaft hat ~g~$%s~s~ von Ihrem Verkauf erhalten", + ["actions_put_soft_handcuffs"] = "Weiche Handschellen", + ["actions_put__hard_handcuffs"] = "Harte Handschellen", + ["now_you_are_on_duty"] = "Sie sind jetzt im Dienst", + ["now_you_are_off_duty"] = "Sie sind jetzt dienstfrei", + + ["item_received"] = "Du hast ~b~x%d~s~ ~y~%s~s~ erhalten", + ["no_free_spawnpoints"] = "Kein freier Spawnpunkt", + ["player_is_not_handcuffed"] = "Spieler ist nicht gefesselt", + ["you_are_not_on_duty"] = "~r~Du bist nicht im Dienst~s~", + ["you_cant_while_handcuffed"] = "~r~Du kannst nicht mit Handschellen ~s~" + } + diff --git a/resources/[creators]/jobs_creator/locales/el.lua b/resources/[creators]/jobs_creator/locales/el.lua new file mode 100644 index 0000000..07ec0ac --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/el.lua @@ -0,0 +1,385 @@ +locales['el'] = { + -- [[ Generic ]] + ["interact"] = "Pata ~INPUT_CONTEXT~ to interact", + ["billing_reason"] = "Λόγος απόδειξης", + ["billing_amount"] = "Ποσό απόδειξης", + ["no_players_nearby"] = "Den uparxoun paiktes konta", + ["no_vehicles_nearby"] = "Den uparxoun amaksia konta", + ["invoice_sent"] = "~g~€%s~s~ Estiles tin apodeiksi", + ["too_far"] = "Poli Makria", + ["yes"] = "Nai", + ["no"] = "Oxi", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Ανοίξτε το μενού ενεργειών", + ['actions_menu'] = "Μενού ενεργειών", + ['actions_billing'] = "Απόδειξη", + ['actions_search'] = "Ψάξιμο", + ['actions_put_handcuffs'] = "Χειροπέδες", + ['actions_start_dragging'] = "Μετέφερε", + ['actions_put_in_car'] = "Βάλτε στο αυτοκίνητο", + ['actions_take_from_car'] = "Βγάλε από το αυτοκίνητο", + ['actions_menu_search'] = "Ψάξε παίκτη", + ['actions_lockpick_car'] = "Ξεκλείδωμα Αυτοκινήτου", + ['no_car_found'] = "Den uparxoun amaksia konta", + ['not_locked_vehicle'] = "To oxima den einai kleidomeno", + ['you_need_lockpick'] = "Xreiazese ~r~lockpick~s~", + ['lockpick_used'] = "Xreisimopioises ~r~lockpick~s~", + ['actions:lockpick:lockpickingVehicle'] = "Ξεκλείδωμα Aυτοκινήτου", + ['actions_menu_search_took'] = "Molis ~g~eklepses~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ molis ~r~klapike~s~ apo esena", + ['actions_menu_search_took_money'] = "Molis ~g~eklepses~s~ ~y~€%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~€%s %s~s~ to ~r~klepsane~s~ apo esena", + ['actions_menu_search_doesnt_have_weapon'] = "O Paiktis ~r~den exei~s~ auto to oplo", + ['actions_menu_search_took_weapon'] = "Molis ~g~eklepses~s~ ~y~%s~s~ me ~y~%d sferes~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ me ~y~%d sferes~s~ ~r~klapike~s~ apo esena", + ['you_need_handcuffs'] = "Xreiazesai ~r~handcuffs~s~", + ['not_handcuffed'] = "O Paiktis den einai ~r~handcuffed~s~", + ['cant_while_dragging'] = "Den mporeite na to kanete auto", + ['search_inventory_empty'] = "Ο Παίκτης δεν έχει τίποτα επάνω του", + ['actions_menu_being_searched'] = "Kapoios se psaxnei", + ['actions:wash_vehicle'] = "Πλύνετε το όχημα", + ['actions:washing_vehicle'] = "Πλύσιμο οχήματος", + ['actions:repair_vehicle'] = "Επισκευή οχήματος", + ['actions:repairing_vehicle'] = "Επισκευή οχήματος", + ['actions:no_vehicles_close'] = "Den uparxoun amaksia konta", + ['actions:impound_vehicle'] = "Kατάσχεση οχήματος", + ['actions:impounding_vehicle'] = "Κατάσχεση του οχήματος", + ['actions:you_need'] = "Xreiazesai ~y~%s~s~", + ['actions:check_identity'] = "Ελέγξτε την ταυτότητα", + ['actions:check_vehicle_owner'] = "Ελέγξτε τον ιδιοκτήτη του οχήματος", + ['actions:checkVehicleOwner:owner'] = "To oxima anikei se ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "O katoxos tou oxímatos den vréthike", + ['actions:checkVehicleOwner:car_not_found'] = "Kanena oxima konta", + ['actions:no_player_found'] = "Den einai kapoios konta sou", + ['actions:checkIdentity:player_found'] = "Βρέθηκε το όνομα του πολίτη: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Kapoios~s~ eide tin tautotita sou.", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Άδειες", + ['actions:no_license_found'] = "Δεν βρέθηκε άδεια", + ['actions:check_licenses'] = "Ελέγξτε τις άδειες", + ['actions:driving_license'] = "Δίπλωμα οδήγησης", + ['actions:weapon_license'] = "Άδεια οπλοφορίας", + ['actions:license:give_remove'] = "Αφαίρεση άδειες", + ['actions:gave_license'] = "Molis ~g~edwses~s~ ~y~%s~s~", + ['actions:removed_license'] = "Molis ~r~afereses~s~ ~y~%s~s~", + ['actions:heal_small'] = "Επουλώστε μικρές πληγές", + ['actions:heal_big'] = "Αντιμετωπίστε σοβαρούς τραυματισμούς", + ['actions:you_need_bandage'] = "Χρειάζεστε ένα ~r~Bandage~s~", + ['actions:revive'] = "Revive", + ['actions:you_need_medikit'] = "Χρειάζεστε ένα ~r~MediKit~s~", + + -- [[ Stash stuff ]] + ["open_stash"] = "Pata ~INPUT_CONTEXT~ gia na deis to stash", + ["deposited"] = "Molis afies ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "Den exeis arketa ~y~%s~s~", + ["no_space"] = "Den exeis xoro", + ["took"] = "Peires ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Adunaton na to pareis x%d %s", + ["empty_inventory"] = "Το απόθεμά σας είναι άδειο", + ["empty_stash"] = "Η αποθήκη είναι άδεια", + ['stash'] = "Αποθήκη", + ['stash_take'] = "Αποθήκη - Πάρτε", + ['stash_deposit'] = "Αποθήκη - Αφήστε", + ['quantity'] = "Ποσότητα", + ['invalid_quantity'] = "Mi egkiri posotita", + ['deposit'] = "Κατάθεση", + ['take'] = "Πάρτε", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Pata ~INPUT_CONTEXT~ gia to wardrobe", + ['player_clothes'] = "Τα ρούχα σου", + ['remove_cloth'] = "Διαγράψτε τη στολή", + ['save_cloth'] = "Αποθηκεύστε την τρέχουσα στολή", + ['you_saved_outfit'] = "H Stolh apothikeutike", + ['delete_outfit'] = "H Stolh diagraftike", + ['clothes'] = "Ρούχα", + ['outfit_label_empty'] = "To onoma den prepi na einai keno", + ['outfit_name'] = "Το όνομα της στολής σου", + ["wardrobe:empty"] = "Η ντουλάπα είναι άδεια", + ["wardrobe:delete"] = "%s - Διαγραφεί", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Pata ~INPUT_CONTEXT~ gia na deis to boss menu", + ["not_boss"] = "Den eisai afentiko", + ["boss_menu"] = "Boss menu", + ["boss:society_money"] = "Λεφτα Επιχείρησης: €%s", + ["boss:withdraw"] = "Βγάλε χρήματα από την επιχείρηση", + ["boss:deposit"] = "Κατάθεση χρημάτων στην επιχείρηση", + ["boss:wash_money"] = "Πλύνετε χρήματα", + ["boss:grades"] = "Διαχειριστείτε τους μισθούς βαθμών", + ["boss:employees"] = "Διαχειριστείτε τους υπαλλήλους", + ["boss:withdraw_amount"] = "Ποσό ανάληψης", + ["boss:deposit_amount"] = "Ποσό κατάθεσης", + ["boss:you_dont_have_enough_money"] = "Δεν έχεις αρκετά χρήματα", + ["boss:invalid_amount"] = "Mi egkiro poso", + ["boss:withdrew_money"] = "Ebgales ~g~€%s~s~", + ["boss:deposited_money"] = "Ebales ~g~€%s~s~", + ["boss:rank_salary"] = "%s - €%s", + ["boss:new_salary"] = "Νέος μισθος", + ["boss:grade_salary_updated"] = "~y~Mis8os Bathmou~s~ ~g~allakse~s~", + ["boss:grade_salary_not_updated"] = "~r~Den egine h allagi sto ~s~ ~y~grade salary~s~", + ["boss:employees_list"] = "Λίστα εργαζομένων", + ["boss:recruit"] = "Πρόσληψη", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Απόλυση εργαζομένου", + ["boss:change_grade"] = "Αλλαγή βαθμού", + ["boss:are_you_sure"] = "Είσαι σίγουρος?", + ["boss:cancel"] = "Ματαίωση", + ["boss:employee_fired"] = "O Ergazomenos ~r~apolithike~s~", + ["boss:you_got_hired"] = "Se proslabane ~g~hired~s~ se ~b~%s~s~", + ["boss:you_hired"] = "Molis ~g~proselabes~s~ %s", + ["boss:nobody_close"] = "Den einai kaneis konta", + ["boss:grade"] = "%d. %s - Μισθός €%s", + ["boss:changed_grade_successfully"] = "Allakses ton bathmo epitixos", + ["boss:your_grade_changed_to"] = "O bathmos sas allaxe se ~b~%s~s~", + ["boss:how_much_to_wash"] = "Πόσα χρήματα θέλετε να πλύνετε;", + ["boss:you_washed_money"] = "Eplines ~g~€%s~s~", + ["boss:not_enough_dirty_money"] = "Den exeis arketa ~r~Maura Xrimata~s~", + ["boss:couldnt_wash_money"] = "Den mporeis na plinis ta lefta", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Pata ~INPUT_CONTEXT~ gia na deis to garage", + ["garage"] = "Garage", + ["take_vehicle"] = "Πάρτε όχημα", + ["park_vehicle"] = "Πάρκαρε όχημα", + ["no_vehicle"] = "Δεν υπάρχουν οχήματα σε αυτό το γκαράζ", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Pata ~INPUT_CONTEXT~ gia na deis to katastima", + ["job_shop"] = "Κατάστημα", + ['shop:item'] = "%s - €%d", + ['not_enough_money'] = "Den exeis arketa lefta", + ['you_bought'] = "Molis agorases ~b~x%d~s~ ~y~%s~s~ gia ~g~€%s~s~", + ['shop_empty'] = "Το Κατάστημα είναι άδειο", + ['shop:you_already_have_that_weapon'] = "Exete idi ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Αγορά αυτοκινήτου", + ['buyable_vehicle'] = "%s - €%s", + ['bought_vehicle'] = "Molis ~g~agwrases~s~ ena amaksi", + ['are_you_sure'] = "Eisai sigouros oti thes na agwraseis %s gia €%s?", + ['no_vehicles_in_garage'] = "Δεν υπάρχουν οχήματα σε αυτό το γκαράζ", + ['vehicle_outside'] = "To oxhma den einai sto garage", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Δεν υπάρχουν οχήματα για αγορά", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Pata ~INPUT_CONTEXT~ gia na anoiksi to garage", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Pata ~INPUT_CONTEXT~ gia na deis to crafting table", + ['crafting_table'] = "Crafting Table", + ['dont_have_ingredients'] = "Den exeis ta ~r~aparaitita~s~ pragmata", + ['crafting'] = "Crafting %s", + ['you_crafted'] = "Molis eftiakses ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Exeis idi ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Pata ~INPUT_CONTEXT~ gia na stamatisis", + ['you_stopped'] = "Tha akiro8ei h diadikasia meta to Craft", + ['crafting_table:nothing_to_craft'] = "Τίποτα για να φτιάξετε", + + -- [[ Armory stuff ]] + ['open_armory'] = "Pata ~INPUT_CONTEXT~ gia na deis to armory", + ['not_have_any_weapon'] = "Δεν έχεις κανένα όπλο πάνω σου", + ['armory'] = "Οπλοστάσιο", + ['armory_take'] = "Οπλοστάσιο - Πάρτε", + ['armory_deposit'] = "Οπλοστάσιο - Κατάθεση", + ['take_weapon'] = "Πάρε όπλο", + ['deposit_weapon'] = "Άφησε Όπλο", + ['you_dont_have_weapon'] = "Den ~r~exeis~s~ auto to oplo", + ['no_weapons_in_armory'] = "Δεν υπάρχουν όπλα εδώ", + ['you_deposited_weapon'] = "Molis ~g~afises ena~s~ %s", + ['you_took_weapon'] = "Molis ~r~peires ena~s~ %s", + ['you_already_have_that_weapon'] = "Exeis idi ~g~%s~s~", + ['weapon_ammo'] = "Σφαίρες", + ['weapon'] = "%s - x%d Σφαίρες", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Pata ~INPUT_CONTEXT~ gia to Job Outfits", + ['job_outfit'] = "Ρούχα εργασίας", + ['no_outfits'] = "Δεν υπάρχουν διαθέσιμα ρούχα εργασίας", + ['civilian_outfit'] = "Πολιτικά ρούχα", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Pata ~INPUT_CONTEXT~ gia teleport", + ['teleport_to'] = "Pata ~INPUT_CONTEXT~ gia na pas %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Pata ~INPUT_CONTEXT~ gia to safe", + ['account'] = "%s - €%s", + ['safe'] = "Χρηματοκιβώτιο", + ['empty_safe'] = "Το xρηματοκιβώτιο είναι άδειο", + ['nothing_to_deposit'] = "Δεν έχεις τίποτα για να αφήσεις", + ['withdrawn_safe'] = "Ebgales %s€%s %s~s~", + ['deposited_safe'] = "Ebales %s€%s %s~s~", + ['cash'] = "Μετρητά", + ['withdraw'] = "Βγάλε", + + -- [[ Market Stuff ]] + ['open_market'] = "Pata ~INPUT_CONTEXT~ gia na anoixeis to market", + ['market_item'] = "%s - €%s - €%s", + ['market'] = "Αγορά", + ['not_enough_item'] = "Den exeis arketa %s", + ['you_sold'] = "Poulises ~b~x%d~s~ ~y~%s~s~ gia %s€%s", + ['nothing_can_be_sold_yet'] = "Tipota den borei na poulithei akoma edo", + ['market:how_many_to_sell'] = "Πόσα θέλετε να πουλήσετε;", + ['market:you_are_already_selling'] = "Πουλάτε ήδη", + ['market:selling'] = "Πώληση x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Pata ~INPUT_CONTEXT~ gia Harvest", + ['harvest:harvesting'] = "ΜΑΖΕΥΕΙΣ %s", + ['harvest:press_to_stop'] = "Pata ~INPUT_CONTEXT~ gia na stamatisis", + ['harvest:you_will_stop_on_finish'] = "Tha stamatsis otan teliosi", + ['harvest:you_need_tool_count'] = "Xreiazese ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Xreiazese ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Pata ~INPUT_CONTEXT~ gia to Weapon Upgrader", + ['weapon_upgrader'] = "Weapon Upgrader", + ['owned_component'] = "%s - Στην κατοχή σου", + ['buy_component'] = "%s - €%s", + ['tint_default'] = "Default", + ['tint_green'] = "Green", + ['tint_gold'] = "Gold", + ['tint_pink'] = "Pink", + ['tint_army'] = "Army", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Orange", + ['tint_platinum'] = "Platinum", + ['components'] = "Εξαρτήματα", + ['tints'] = "Αποχρώσεις", + ['already_have_tint'] = "Exeis autin tin apoxrwsei idi", + ['bought_tint'] = "Agorases ~y~%s~s~ apoxrwsei gia ~g~%s~s~", + ['bought_component'] = "Agorases ~y~%s~s~ gia ~g~%s~s~", + ['removed_component'] = "Afairesate ~y~%s~s~ apo ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Pata ~INPUT_CONTEXT~ gia na pas ~g~Entos Yperesias~s~", + ['go_off_duty'] = "Pata ~INPUT_CONTEXT~ gia na pas ~r~Ektos Yperesias~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Pata ~INPUT_CONTEXT~ gia na anoixeis to shop", + ['job_owned_shop'] = "Πωλητής Καταστήματος", + ['shop'] = "Κατάστημα", + ['put_on_sale'] = "Βάλτε στην πώληση", + ['remove_from_sale'] = "Κατάργηση από την πώληση", + ['item_price'] = "Τιμη προιοντος", + ['invalid_price'] = "Mi egkiri timi", + ['job_shop_item'] = "%s - x%d - €%s", + ['job_shop_empty'] = "Το μαγαζί είναι άδειο", + ['job_shop_quantity'] = "Ποσότητα - x%d -> €%s", + ['job_shop_cant_afford'] = "Den ~r~mporeis na agorasis~s~ auto", + ['job_shop:bought_item'] = "Molis ~g~agwrases~s~ x%d ~y~%s~s~ gia ~g~€%s~s~", + ['job_shop:add_supplies'] = "Προσθέστε Πράγματα", + ['job_shop:what_to_put_on_sale'] = "Τι θα θέλατε να πουλήσετε;", + ['job_shop:what_to_remove_from_sale'] = "Τι θα θέλατε να αφαιρέσετε από την πώληση;", + ['job_shop:what_to_restock'] = "Τι θα θέλατε να ανανεώσετε;", + ['job_shop:how_many_to_restock'] = "Πόσα να προσθέσετε στο απόθεμα?", + ['job_shop:added_to_supplies'] = "Balate ~b~x%d~s~ ~y~%s~s~ stis promi8eies", + ['job_shop:you_put_on_sale'] = "Ebales gia polisi ~b~x%d~s~ ~y~%s~s~ gia ~g~€%s~s~", + ['job_shop:you_removed_from_sale'] = "Katargiste apo tin polisi ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Exeis idi panw sou ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Den exeis tipota na poulisis", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Pata ~INPUT_CONTEXT~ gia na kaneis Process", + ['process:you_need'] = "Xreiazese ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Επεξεργασία %s", + ['process:press_to_stop'] = "Pata ~INPUT_CONTEXT~ gia na stamatisis", + ['process:you_will_stop_on_finish'] = "Molis telioses tin douleia", + ['process:no_space'] = "Den mporeis na koubalisis ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Όνομα: %s\nIdentifier: %s\n\n%s", + + ['log_deposited_stash'] = "Έβαλε Αντικείμενο", + ['log_deposited_stash_description'] = "Έβαλε x**%d** **%s** (**%s**) στο Marker ID: **%d**", + + ['log_took_stash'] = "Πήρε αντικείμενο", + ['log_took_stash_description'] = "Πήρε x**%d** **%s** (**%s**) από το Marker ID: **%d**", + + ['log_deposited_weapon'] = "Έβαλε όπλο", + ['log_deposited_weapon_description'] = "Έβαλε **%s** (**%s**) με x**%d** σφαίρες στο Marker ID: **%d**", + + ['log_took_weapon'] = "Πήρε όπλο", + ['log_took_weapon_description'] = "Πήρε **%s** (**%s**) με x**%d** σφαίρες απο το Marker ID: **%d**", + + ['log_deposited_money'] = "Έβαλε χρήματα", + ['log_deposited_money_description'] = "Έβαλε €**%d** στo ταμείο '**%s**'", + + ['log_withdrew_money'] = "Πήρε χρήματα", + ['log_withdrew_money_description'] = "Πήρε χρήματα €**%d** απο τo ταμείο '**%s**'", + + ['log_updated_salary'] = "Ενημερωμένος μισθός", + ['log_updated_salary_description'] = "Ενημερωμένος μισθός **%d** σε **€%s**", + + ['log_fired_employee'] = "Υπάλληλος απολύθηκε", + ['log_fired_employee_description'] = "Απόλυση Εργαζομένου με identifier **%s**", + + ['log_recruited_employee'] = "Πρόσληψη Υπαλλήλου", + ['log_recruited_employee_description'] = "Πρόσληψη **%s** του οποίου το identifier είναι **%s**", + + ['log_changed_grade_employee'] = "Αλλαγή βαθμού σε υπάλληλο", + ['log_changed_grade_employee_description'] = "Αλλαγή βαθμού σε υπάλληλο **%s** σε **%d**", + + ['log_washed_money'] = "Πλυμένα χρήματα", + ['log_washed_money_description'] = "Πλυμένα €**%s**", + + ['log_sold_item'] = "Πουλήθηκε το αντικείμενο", + ['log_sold_item_description'] = "Πουλήθηκε **x%d** **%s** για **€%s**", + + ['log_bought_item'] = "Αγόρασε ένα αντικείμενο", + ['log_bought_item_description'] = "Αγόρασε x%d **%s** (**%s**) από το Marker ID: **%d**", + + ['log_not_existing_item'] = "Μη υπάρχον στοιχείο", + ['log_not_existing_item_description'] = "Προσπάθησε να αγοράσει '**%s**' από το Marker ID: **%d**, αλλά το προϊόν δεν είναι στο κατάστημα", + + ['log_bought_vehicle'] = "Αγόρασε όχημα", + ['log_bought_vehicle_description'] = "Αγόρασε '**%s**' για €**%d** από το Marker ID: **%d**", + + ['log_not_existing_vehicle'] = "Μη υπάρχον όχημα", + ['log_not_existing_vehicle_description'] = "Προσπάθησε να αγοράσει '**%s**' από το Marker ID: **%d**, αλλά το όχημα δεν είναι στο γκαράζ", + + ['log_crafted_item'] = "Κατασκευάστηκε ένα αντικείμενο", + ['log_crafted_item_description'] = "Έφτιαξε **x%d** **%s** (**%s**) σε Marker ID: **%d**", + + ['log_deposited_safe'] = "Μπήκαν στο χρηματοκιβώτιο", + ['log_deposited_safe_description'] = "Κατατέθηκε €**%s** **%s** σε Marker ID: **%d**", + + ['log_withdrew_safe'] = "Βγήκαν από το χρηματοκιβώτιο", + ['log_withdrew_safe_description'] = "Βγήκαν €**%s** **%s** από το Marker ID: **%d**", + + ['log_harvested'] = "Μάζεψε", + ['log_harvested_description'] = "Μάζεψε x**%d** **%s** από το Marker ID: **%d**", + + ['log_bought_tint'] = "Αγόρασε απόχρωση", + ['log_bought_tint_description'] = "Αγόρασε την **%s** '**%s**' απόχρωση για €**%d** από το Marker ID: **%d**", + + ['log_removed_component'] = "Αφαιρέθηκε το εξάρτημα", + ['log_removed_component_description'] = "Αφαιρέθηκε **%s** το **%s** από το Marker ID: **%d**", + + ['log_bought_component'] = "Αγόρασε ένα εξάρτημα", + ['log_bought_component_description'] = "Αγόρασε ένα **%s** για **%s** από το Marker ID: **%d**", + + ['log_not_allowed_marker'] = "Δεν επιτρέπεται η χρήση του marker", + ['log_not_allowed_marker_description'] = "Προσπάθησε να χρησιμοποιήσει Marker ID: %d αλλά δεν του επιτρέπεται", + + ['logs:process:title'] = "Επεξεργασία", + ['logs:process:description'] = "Επεξεργάστηκε **x%d** **%s** για **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Βάλτε προς πώληση", + ['logs:job_shop:put_on_sale:description'] = "Βάλτε προς πώληση **x%d** **%s** για **€%s** στο Marker ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Αφαιρέθηκε από πώληση", + ['logs:job_shop:remove_from_sale:description'] = "Αφαιρέθηκε **x%d** **%s** για **€%s** από το Marker ID **%d**", + + ['logs:job_shop:bought_item'] = "Αγόρασε το αντικείμενο", + ['logs:job_shop:bought_item:description'] = "Αγοράστηκε **x%d** **%s** για **€%s** στο Marker ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Προστέθηκε στις προμήθειες", + ['logs:job_shop:add_to_supplies:description'] = "Προστέθηκε **x%d** **%s** για **€%s** στης προμήθειες στο Marker ID **%d**", +} diff --git a/resources/[creators]/jobs_creator/locales/en.lua b/resources/[creators]/jobs_creator/locales/en.lua new file mode 100644 index 0000000..621bbb1 --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/en.lua @@ -0,0 +1,467 @@ +locales['en'] = { + -- [[ Generic ]] + ["interact"] = "Press ~INPUT_CONTEXT~ to interact", + ["billing_reason"] = "Billing Reason", + ["billing_amount"] = "Billing Amount", + ["no_players_nearby"] = "No players nearby", + ["no_vehicles_nearby"] = "No vehicles nearby", + ["invoice_sent"] = "~g~$%s~s~ invoice sent", + ["too_far"] = "Too far", + ["yes"] = "Yes", + ["no"] = "No", + ["you_need_minimum_account_money"] = "You need at least $~y~%d~s~ in ~b~%s~s~", + ["bill"] = "Bill", + ["bill_received"] = "You have received an invoice
    Amount: $%s
    Reason: %s

    Press the button below to accept the bill", + ["bill_paid"] = "You paid an invoice for $%s", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Open actions menu", + ['actions_menu'] = "Actions menu", + ['actions_billing'] = "Billing", + ['actions_search'] = "Search", + ['actions_start_dragging'] = "Drag", + ['actions_put_in_car'] = "Put in car", + ['actions_take_from_car'] = "Take from car", + ['actions_menu_search'] = "Search player", + ['actions_lockpick_car'] = "Lockpick car", + ['no_car_found'] = "No close car found", + ['not_locked_vehicle'] = "This vehicle is not locked", + ['you_need_lockpick'] = "You need a ~r~lockpick~s~", + ['lockpick_used'] = "You used a ~r~lockpick~s~", + ['actions:lockpick:lockpickingVehicle'] = "Lockpicking vehicle", + ['actions_menu_search_took'] = "You ~g~took~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ was ~r~stolen~s~ from you", + ['actions_menu_search_took_money'] = "You ~g~took~s~ ~y~$%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~$%s %s~s~ was ~r~stolen~s~ from you", + ['actions_menu_search_doesnt_have_weapon'] = "Player ~r~doesn't~s~ have that weapon", + ['actions_menu_search_took_weapon'] = "You ~g~took~s~ ~y~%s~s~ with ~y~%d bullets~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ with ~y~%d bullets~s~ was ~r~stolen~s~ from you", + ['you_need_handcuffs'] = "You need ~r~handcuffs~s~", + ['not_handcuffed'] = "Player is not ~r~handcuffed~s~", + ['cant_while_dragging'] = "You can't do this while dragging", + ['search_inventory_empty'] = "Inventory empty", + ['actions_menu_being_searched'] = "You are being searched", + ['actions:wash_vehicle'] = "Wash vehicle", + ['actions:washing_vehicle'] = "Washing vehicle", + ['actions:repair_vehicle'] = "Repair vehicle", + ['actions:repairing_vehicle'] = "Repairing vehicle", + ['actions:no_vehicles_close'] = "No close vehicle", + ['actions:impound_vehicle'] = "Impound vehicle", + ['actions:impounding_vehicle'] = "Impounding vehicle", + ['actions:you_need'] = "You need ~y~%s~s~", + ['actions:check_identity'] = "Check identity", + ['actions:check_vehicle_owner'] = "Check vehicle owner", + ['actions:checkVehicleOwner:owner'] = "The vehicle is owned by ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Vehicle owner not found", + ['actions:checkVehicleOwner:car_not_found'] = "No vehicle close", + ['actions:no_player_found'] = "Nobody close", + ['actions:checkIdentity:player_found'] = "Citizen name found: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Somebody~s~ checked your identity", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Licenses", + ['actions:no_license_found'] = "No license found", + ['actions:check_licenses'] = "Check licenses", + ['actions:driving_license'] = "Driving license", + ['actions:weapon_license'] = "Weapon license", + ['actions:license:give_remove'] = "Give/Remove licenses", + ['actions:gave_license'] = "You ~g~gave~s~ ~y~%s~s~", + ['actions:removed_license'] = "You ~r~removed~s~ ~y~%s~s~", + ['actions:heal_small'] = "Heal small wounds", + ['actions:heal_big'] = "Treat serious injuries", + ['actions:you_need_bandage'] = "You need a ~r~bandage~s~", + ['actions:revive'] = "Revive", + ['actions:revive:not_dead'] = "The person is not dead", + ['actions:you_need_medikit'] = "You need a ~r~medikit~s~", + ['actions:the_player_must_be_handcuffed'] = "The player must be handcuffed or hands up", + + -- [[ Stash stuff ]] + ["open_stash"] = "Press ~INPUT_CONTEXT~ to open stash", + ["deposited"] = "You have deposited ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "Not enough ~y~%s~s~", + ["no_space"] = "You have no space", + ["took"] = "You took ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Impossible to get x%d %s", + ["empty_inventory"] = "Your inventory is empty", + ["empty_stash"] = "The stash is empty", + ['stash'] = "Stash", + ['stash_take'] = "Stash - Take", + ['stash_deposit'] = "Stash - Deposit", + ['quantity'] = "Quantity", + ['invalid_quantity'] = "Invalid quantity", + ['deposit'] = "Deposit", + ['take'] = "Take", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Press ~INPUT_CONTEXT~ to open the wardrobe", + ['player_clothes'] = "Your outfits", + ['remove_cloth'] = "Delete outfit", + ['save_cloth'] = "Save current outfit", + ['you_saved_outfit'] = "Outfit saved", + ['delete_outfit'] = "Outfit deleted", + ['clothes'] = "Clothes", + ['outfit_label_empty'] = "Outfit name can't be empty", + ['outfit_name'] = "Your outfit name", + ["wardrobe:empty"] = "Wardrobe is empty", + ["wardrobe:delete"] = "%s - Delete", + ["wardrobe"] = "Wardrobe", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Press ~INPUT_CONTEXT~ to open boss menu", + ["not_boss"] = "You are not the boss", + ["boss_menu"] = "Boss menu", + ["boss:society_money"] = "Society money: $%s", + ["boss:withdraw"] = "Withdraw society money", + ["boss:deposit"] = "Deposit society money", + ["boss:wash_money"] = "Wash money", + ["boss:grades"] = "Manage grades salaries", + ["boss:employees"] = "Manage employees", + ["boss:withdraw_amount"] = "Withdraw amount", + ["boss:deposit_amount"] = "Deposit amount", + ["boss:you_dont_have_enough_money"] = "You don't have enough money", + ["boss:invalid_amount"] = "Invalid amount", + ["boss:withdrew_money"] = "You withdrew ~g~$%s~s~", + ["boss:deposited_money"] = "You deposited ~g~$%s~s~", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "New grade salary", + ["boss:grade_salary_updated"] = "~y~Grade salary~s~ ~g~updated~s~", + ["boss:grade_salary_not_updated"] = "~r~Couldn't update~s~ ~y~grade salary~s~", + ["boss:employees_list"] = "Employees list", + ["boss:recruit"] = "Recruit", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Fire", + ["boss:change_grade"] = "Change grade", + ["boss:are_you_sure"] = "Are you sure?", + ["boss:cancel"] = "Cancel", + ["boss:employee_fired"] = "Employee ~r~fired~s~", + ["boss:you_got_hired"] = "You got ~g~hired~s~ in ~b~%s~s~", + ["boss:you_hired"] = "You ~g~hired~s~ %s", + ["boss:nobody_close"] = "Nobody close", + ["boss:grade"] = "%d. %s - Salary $%s", + ["boss:changed_grade_successfully"] = "Changed grade successfully", + ["boss:your_grade_changed_to"] = "Your grade changed to ~b~%s~s~", + ["boss:how_much_to_wash"] = "How much money do you want to wash?", + ["boss:you_washed_money"] = "You washed ~r~$%s~s~ and have received ~g~$%s~s~", + ["boss:not_enough_dirty_money"] = "You don't have enough ~r~dirty money~s~", + ["boss:couldnt_wash_money"] = "Couldn't wash money", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Press ~INPUT_CONTEXT~ to open garage", + ["garage"] = "Garage", + ["take_vehicle"] = "Take vehicle", + ["park_vehicle"] = "Park vehicle", + ["no_vehicle"] = "There are no vehicles in this garage", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Press ~INPUT_CONTEXT~ to open the shop", + ["job_shop"] = "Job shop", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "You don't have enough money", + ['you_bought'] = "You bought ~b~x%d~s~ ~y~%s~s~ for ~%s~$%s~s~", + ['shop_empty'] = "This shop is empty", + ['shop:you_already_have_that_weapon'] = "You already have ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Buy vehicle", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "You ~g~bought~s~ a vehicle", + ['are_you_sure'] = "Are you sure to buy %s for $%s?", + ['no_vehicles_in_garage'] = "There are no vehicles in this garage", + ['vehicle_outside'] = "Vehicle is not in garage", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "There are no vehicles to buy", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Press ~INPUT_CONTEXT~ to open garage", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Press ~INPUT_CONTEXT~ to open the crafting table", + ['crafting_table'] = "Crafting Table", + ['dont_have_ingredients'] = "You don't have all the ~r~required~s~ items", + ['crafting'] = "Crafting %s", + ['you_crafted'] = "You crafted ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "You already have ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Press ~INPUT_CONTEXT~ to stop", + ['you_stopped'] = "You'll stop when the crafting ends", + ['crafting_table:nothing_to_craft'] = "Nothing to craft", + ["craft_amount"] = "Craft amount", + + -- [[ Armory stuff ]] + ['open_armory'] = "Press ~INPUT_CONTEXT~ to open the armory", + ['not_have_any_weapon'] = "You don't have any weapon", + ['armory'] = "Armory", + ['armory_take'] = "Armory - Take", + ['armory_deposit'] = "Armory - Deposit", + ['take_weapon'] = "Take weapon", + ['deposit_weapon'] = "Deposit weapon", + ['you_dont_have_weapon'] = "You ~r~don't~s~ have that weapon", + ['no_weapons_in_armory'] = "There are no weapons here", + ['you_deposited_weapon'] = "You have ~g~deposited~s~ %s", + ['you_took_weapon'] = "You ~r~took~s~ %s", + ['you_already_have_that_weapon'] = "You already have ~g~%s~s~", + ['weapon_ammo'] = "Weapon ammo", + ['weapon'] = "%s - x%d bullets", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Press ~INPUT_CONTEXT~ to open the job's outfits", + ['job_outfit'] = "Job outfits", + ['no_outfits'] = "No outfits available", + ['civilian_outfit'] = "Civilian outfit", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Press ~INPUT_CONTEXT~ to teleport", + ['teleport_to'] = "Press ~INPUT_CONTEXT~ to go to %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Press ~INPUT_CONTEXT~ to open the safe", + ['account'] = "%s - $%s", + ['safe'] = "Safe", + ['empty_safe'] = "Safe is empty", + ['nothing_to_deposit'] = "You have nothing to deposit here", + ['withdrawn_safe'] = "You have withdrawn %s$%s %s~s~", + ['deposited_safe'] = "You have deposited %s$%s %s~s~", + ['cash'] = "Cash", + ['withdraw'] = "Withdraw", + + -- [[ Market Stuff ]] + ['open_market'] = "Press ~INPUT_CONTEXT~ to open market", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Market", + ['not_enough_item'] = "You don't have enough %s", + ['you_sold'] = "You sold ~b~x%d~s~ ~y~%s~s~ for %s$%s", + ['nothing_can_be_sold_yet'] = "Nothing can be sold here yet", + ['market:how_many_to_sell'] = "How many do you want to sell?", + ['market:you_are_already_selling'] = "You are already selling", + ['market:selling'] = "Selling x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Press ~INPUT_CONTEXT~ to harvest", + ['harvest:harvesting'] = "Harvesting %s", + ['harvest:press_to_stop'] = "Press ~INPUT_CONTEXT~ to stop", + ['harvest:you_will_stop_on_finish'] = "You will stop on finish", + ['harvest:you_need_tool_count'] = "You need ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "You need ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Press ~INPUT_CONTEXT~ to open weapon upgrader", + ['weapon_upgrader'] = "Weapon Upgrader", + ['owned_component'] = "%s - Owned", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Default", + ['tint_green'] = "Green", + ['tint_gold'] = "Gold", + ['tint_pink'] = "Pink", + ['tint_army'] = "Army", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Orange", + ['tint_platinum'] = "Platinum", + ['components'] = "Components", + ['tints'] = "Tints", + ['already_have_tint'] = "You already have this tint", + ['bought_tint'] = "You bought ~y~%s~s~ tint for ~g~%s~s~", + ['bought_component'] = "You bought ~y~%s~s~ for ~g~%s~s~", + ['removed_component'] = "You removed ~y~%s~s~ from ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Press ~INPUT_CONTEXT~ to go ~g~on duty~s~", + ['go_off_duty'] = "Press ~INPUT_CONTEXT~ to go ~r~off duty~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Press ~INPUT_CONTEXT~ to open the shop", + ['job_owned_shop'] = "Job Shop", + ['shop'] = "Shop", + ['put_on_sale'] = "Put on sale", + ['remove_from_sale'] = "Remove from sale", + ['item_price'] = "Item price", + ['invalid_price'] = "Invalid price", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "The shop is empty", + ['job_shop_quantity'] = "Quantity - x%d -> $%s", + ['job_shop_cant_afford'] = "You ~r~can't afford~s~ this", + ['job_shop:bought_item'] = "You ~g~bought~s~ x%d ~y~%s~s~ for ~g~$%s~s~", + ['job_shop:add_supplies'] = "Add supplies", + ['job_shop:what_to_put_on_sale'] = "What would you like to put on sale?", + ['job_shop:what_to_remove_from_sale'] = "What would you like to remove from sale?", + ['job_shop:what_to_restock'] = "What would you like to restock?", + ['job_shop:how_many_to_restock'] = "How many to add to stock?", + ['job_shop:added_to_supplies'] = "Added ~b~x%d~s~ ~y~%s~s~ to supplies", + ['job_shop:you_put_on_sale'] = "You put on sale ~b~x%d~s~ ~y~%s~s~ for ~g~$%s~s~", + ['job_shop:you_removed_from_sale'] = "You removed from sale ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "You already have ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "You have nothing to sell", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Press ~INPUT_CONTEXT~ to process", + ['process:you_need'] = "You need ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Processing %s", + ['process:press_to_stop'] = "Press ~INPUT_CONTEXT~ to stop", + ['process:you_will_stop_on_finish'] = "You will stop on finish", + ['process:no_space'] = "You can't carry ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Nickname: %s\nIdentifier: %s\n\n%s", + + ['log_deposited_stash'] = "Deposited item", + ['log_deposited_stash_description'] = "Deposited x**%d** **%s** (**%s**) in marker ID **%d**", + + ['log_took_stash'] = "Took item", + ['log_took_stash_description'] = "Took x**%d** **%s** (**%s**) from marker ID **%d**", + + ['log_deposited_weapon'] = "Deposited weapon", + ['log_deposited_weapon_description'] = "Deposited **%s** (**%s**) with x**%d** ammo in marker ID **%d**", + + ['log_took_weapon'] = "Took weapon", + ['log_took_weapon_description'] = "Took **%s** (**%s**) with x**%d** ammo in marker ID **%d**", + + ['log_deposited_money'] = "Deposited money", + ['log_deposited_money_description'] = "Deposited $**%d** in society '**%s**'", + + ['log_withdrew_money'] = "Withdrew money", + ['log_withdrew_money_description'] = "Withdrew $**%d** from society '**%s**'", + + ['log_updated_salary'] = "Updated salary", + ['log_updated_salary_description'] = "Updated salary of grade **%d** to **$%s**", + + ['log_fired_employee'] = "Employee fired", + ['log_fired_employee_description'] = "Fired player with identifier **%s**", + + ['log_recruited_employee'] = "Recruited employee", + ['log_recruited_employee_description'] = "Recruited **%s** whose identifier is **%s**", + + ['log_changed_grade_employee'] = "Changed grade to employee", + ['log_changed_grade_employee_description'] = "Changed grade to employee **%s** to **%d**", + + ['log_washed_money'] = "Washed money", + ['log_washed_money_description'] = "Washed $**%s**", + + ['log_sold_item'] = "Sold item", + ['log_sold_item_description'] = "Sold **x%d** **%s** for **$%s**", + + ['log_bought_item'] = "Bought item", + ['log_bought_item_description'] = "Bought x%d **%s** (**%s**) from marker ID **%d**", + + ['log_not_existing_item'] = "Not existing item", + ['log_not_existing_item_description'] = "Tried to buy '**%s**' from marker ID **%d**, but the item it's not in the shop", + + ['log_bought_vehicle'] = "Bought vehicle", + ['log_bought_vehicle_description'] = "Bought '**%s**' for $**%d** from marker ID **%d**", + + ['log_not_existing_vehicle'] = "Not existing vehicle", + ['log_not_existing_vehicle_description'] = "Tried to buy '**%s**' from marker ID **%d**, but the vehicle it's not in the garage", + + ['log_crafted_item'] = "Crafted item", + ['log_crafted_item_description'] = "Crafted **x%d** **%s** (**%s**) in marker ID **%d**", + + ['log_deposited_safe'] = "Deposit in safe", + ['log_deposited_safe_description'] = "Deposited $**%s** **%s** in marker ID **%d**", + + ['log_withdrew_safe'] = "Withdrew from safe", + ['log_withdrew_safe_description'] = "Withdrew $**%s** **%s** from marker ID **%d**", + + ['log_harvested'] = "Harvested", + ['log_harvested_description'] = "Harvested x**%d** **%s** from marker ID **%d**", + + ['log_bought_tint'] = "Bought tint", + ['log_bought_tint_description'] = "Bought the **%s** '**%s**' tint for $**%d** from marker ID **%d**", + + ['log_removed_component'] = "Removed component", + ['log_removed_component_description'] = "Removed **%s** from **%s** from marker ID **%d**", + + ['log_bought_component'] = "Bought component", + ['log_bought_component_description'] = "Bought **%s** for **%s** from marker ID **%d**", + + ['log_not_allowed_marker'] = "Not allowed marker use", + ['log_not_allowed_marker_description'] = "Tried to use marker ID %d but he's not allowed", + + ['logs:process:title'] = "Processed", + ['logs:process:description'] = "Processed **x%d** **%s** to **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Put on sale", + ['logs:job_shop:put_on_sale:description'] = "Put on sale **x%d** **%s** for **$%s** in marker ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Removed from sale", + ['logs:job_shop:remove_from_sale:description'] = "Removed **x%d** **%s** for **$%s** from marker ID **%d**", + + ['logs:job_shop:bought_item'] = "Bought item", + ['logs:job_shop:bought_item:description'] = "Bought **x%d** **%s** for **$%s** in marker ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Added to supplies", + ['logs:job_shop:add_to_supplies:description'] = "Added **x%d** **%s** for **$%s** to supplies in marker ID **%d**", + + -- Steal action + ['logs:actions:stolen_item'] = "Stolen item", + ['logs:actions:stolen_item:description'] = "Has stolen **x%d** **%s** from **%s** (%s)", + + ['logs:actions:stolen_account'] = "Stolen account", + ['logs:actions:stolen_account:description'] = "Has stolen $**%d** **%s** from **%s** (%s)", + + ['logs:actions:stolen_weapon'] = "Stolen weapon", + ['logs:actions:stolen_weapon:description'] = "Has stolen **%s** with **x%s** bullets from **%s** (%s)", + + -- Other + ["you_cant_do_this_in_a_vehicle"] = "You can't do this in a vehicle", + ["society_received_money_from_your_sale"] = "Your society has received ~g~$%s~s~ from your sale", + ["actions_put_soft_handcuffs"] = "Soft handcuff", + ["actions_put__hard_handcuffs"] = "Hard handcuff", + ["now_you_are_on_duty"] = "You are now on duty", + ["now_you_are_off_duty"] = "You are now off duty", + + ["item_received"] = "You received ~b~x%d~s~ ~y~%s~s~", + ["no_free_spawnpoints"] = "No free spawnpoint", + ["player_is_not_handcuffed"] = "Player is not handcuffed", + ["you_are_not_on_duty"] = "~r~You are not on duty~s~", + ["you_cant_while_handcuffed"] = "~r~You can't while handcuffed~s~", + + ["off_duty_job_label"] = "%s - Off duty", + ["off_duty_rank_label"] = "%s", + + ["actions:place_object"] = "Place object", + ["delete_object"] = "Delete object", + ["limit_reached"] = "Limit reached", + ["no_object_found"] = "No object found", + + ["open_stash_targeting"] = "Open stash", + ["open_wardrobe_targeting"] = "Open wardrobe", + ["open_boss_targeting"] = "Open boss menu", + ["open_garage_targeting"] = "Open garage", + ["open_shop_targeting"] = "Open shop", + ["open_crafting_table_targeting"] = "Open crafting table", + ["open_armory_targeting"] = "Open armory", + ["open_job_outfit_targeting"] = "Job outfits", + ["teleport_targeting"] = "Teleport", + ["open_safe_targeting"] = "Open safe", + ["open_market_targeting"] = "Open market", + ["harvest_targeting"] = "Harvest", + ["open_weapon_upgrader_targeting"] = "Open weapon upgrader", + ["toggle_duty_targeting"] = "Toggle duty", + ["open_job_shop_targeting"] = "Open job shop", + ["process:press_to_process_targeting"] = "Process", + ["garage_owned:press_to_open_targeting"] = "Open garage", + ['teleport_to_targeting'] = "Go to %s", + + ["input_context:letter"] = "E", -- This will replace ~INPUT_CONTEXT~ in the translations, useful for notification that doesn't support it + + ["place_entity:cancel"] = "Click ~INPUT_FRONTEND_PAUSE_ALTERNATE~ to ~r~cancel~s~", + ["place_entity:confirm"] = "Click ~INPUT_ATTACK~ to ~g~confirm~s~", + ["place_entity:move"] = "Hold ~INPUT_SPRINT~ to ~y~move~s~", + ["place_entity:heading"] = "Use ~INPUT_CURSOR_SCROLL_UP~ and ~INPUT_CURSOR_SCROLL_DOWN~ to edit ~y~heading~s~", + + ["you_received_item"] = "You received ~b~x%d~s~ ~y~%s~s~", + ["you_received_money"] = "You received ~b~$%s~s~ ~y~%s~s~", + ["you_received_weapon"] = "You received ~y~%s~s~", + + ["input_frontend_pause_alternate:letter"] = "ESC", + ["input_sprint:letter"] = "SHIFT", + ["input_attack:letter"] = "LEFT MOUSE", + ["input_cursor_scroll_up:letter"] = "SCROLLWHEEL UP", + ["input_cursor_scroll_down:letter"] = "SCROLLWHEEL DOWN", + + ["boss:no_employees"] = "No employees found", + ["boss:work_time"] = "Work time: %sh %sm (last %s days)", + ["boss:work_time_days_input_title"] = "How many days to look back (max 14)?", + ["boss:on_duty_suffix"] = " - On duty", + ["boss:off_duty_suffix"] = " - Off duty", + ["boss:offline_suffix"] = " - Offline", +} diff --git a/resources/[creators]/jobs_creator/locales/es.lua b/resources/[creators]/jobs_creator/locales/es.lua new file mode 100644 index 0000000..ecd3b67 --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/es.lua @@ -0,0 +1,385 @@ +locales['es'] = { + -- [[ Generic ]] + ["interact"] = "Pulsa ~INPUT_CONTEXT~ para abrir", + ["billing_reason"] = "Razón factura", + ["billing_amount"] = "Cantidad factura", + ["no_players_nearby"] = "No hay jugadores cerca", + ["no_vehicles_nearby"] = "No hay vehículos cerca", + ["invoice_sent"] = "~g~$%s~s~ factura enviada", + ["too_far"] = "Demasiado lejos", + ["yes"] = "Sí", + ["no"] = "No", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Abrir menú de acciones", + ['actions_menu'] = "Menú de acciones", + ['actions_billing'] = "Facturas", + ['actions_search'] = "Buscar", + ['actions_put_handcuffs'] = "Esposar", + ['actions_start_dragging'] = "Arrastrar", + ['actions_put_in_car'] = "Meter al vehículo", + ['actions_take_from_car'] = "Sacar del vehículo", + ['actions_menu_search'] = "Busqueda de jugador", + ['actions_lockpick_car'] = "Forzar vehículo", + ['no_car_found'] = "No hay coche cerca", + ['not_locked_vehicle'] = "No hay vehículo cerrado", + ['you_need_lockpick'] = "Necesitas una ~r~lockpick~s~", + ['lockpick_used'] = "Has usado ~r~lockpick~s~", + ['actions:lockpick:lockpickingVehicle'] = "Forzando vehículo", + ['actions_menu_search_took'] = "Has ~g~cogido~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ ha ~r~robado~s~ de ti", + ['actions_menu_search_took_money'] = "Ha ~g~cogido~s~ ~y~$%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~$%s %s~s~ ha ~r~robado~s~ de ti", + ['actions_menu_search_doesnt_have_weapon'] = "Esta persona ~r~no tiene~s~ armas", + ['actions_menu_search_took_weapon'] = "Has ~g~cogido~s~ ~y~%s~s~ con ~y~%d balas~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ con ~y~%d ballas~s~ te han ~r~robado~s~", + ['you_need_handcuffs'] = "Necesitas ~r~esposas~s~", + ['not_handcuffed'] = "El jugador no está ~r~esposado~s~", + ['cant_while_dragging'] = "No puedes agarrarlo", + ['search_inventory_empty'] = "Inventario vacío", + ['actions_menu_being_searched'] = "Estás siendo registrado", + ['actions:wash_vehicle'] = "Lavar vehículo", + ['actions:washing_vehicle'] = "Lavando vehículo", + ['actions:repair_vehicle'] = "Reparar vehículo", + ['actions:repairing_vehicle'] = "Reparando vehículo", + ['actions:no_vehicles_close'] = "No hay vehículo cerca", + ['actions:impound_vehicle'] = "Incautar vehículo", + ['actions:impounding_vehicle'] = "Incautando vehículo", + ['actions:you_need'] = "Necesitas ~y~%s~s~", + ['actions:check_identity'] = "Verificar la identidad", + ['actions:check_vehicle_owner'] = "Verificar propietario del vehículo", + ['actions:checkVehicleOwner:owner'] = "El propietario del vehículo es ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "El vehículo no tiene dueño", + ['actions:checkVehicleOwner:car_not_found'] = "Ningún vehículo cerca", + ['actions:checkIdentity:no_player_found'] = "Ningún jugador cerca", + ['actions:checkIdentity:player_found'] = "Nombre del ciudadano encontrado: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Alguien~s~ ha verificado su identidad", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Licencias", + ['actions:no_license_found'] = "Licencia no encontrada", + ['actions:check_licenses'] = "Revisando licencias", + ['actions:driving_license'] = "Licencia de conducir", + ['actions:weapon_license'] = "Licencia de armas", + ['actions:license:give_remove'] = "Remove licenses", + ['actions:gave_license'] = "Tu has ~g~entregado~s~ ~y~%s~s~", + ['actions:removed_license'] = "Tu has ~r~eliminado~s~ ~y~%s~s~", + ['actions:heal_small'] = "Curar pequeñas heridas", + ['actions:heal_big'] = "Tratar lesiones graves", + ['actions:you_need_bandage'] = "Tu necesitas una ~r~venda~s~", + ['actions:revive'] = "Revivir", + ['actions:you_need_medikit'] = "Tu necesitas un ~r~medikit~s~", + + -- [[ Stash stuff ]] + ["open_stash"] = "Pulsa ~INPUT_CONTEXT~ para abrir tu almacén", + ["deposited"] = "Has depositado ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "No tienes ~y~%s~s~", + ["no_space"] = "No hay espacio", + ["took"] = "Has cogido ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Imposible coger x%d %s", + ["empty_inventory"] = "Tu inventario está lleno", + ["empty_stash"] = "Almacén vacío", + ['stash'] = "Almacén", + ['stash_take'] = "Almacén - Coger", + ['stash_deposit'] = "Almacén - Depositar", + ['quantity'] = "Cantidad", + ['invalid_quantity'] = "Cantidad inválida", + ['deposit'] = "Depositar", + ['take'] = "Coger", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Pulsa ~INPUT_CONTEXT~ para abrir el armario", + ['player_clothes'] = "Tus outfits", + ['remove_cloth'] = "Borrar outfits", + ['save_cloth'] = "Guardar outfits", + ['you_saved_outfit'] = "Outfit guardado", + ['delete_outfit'] = "Outfit borrado", + ['clothes'] = "Ropa", + ['outfit_label_empty'] = "Pon un nombre a este outfit", + ['outfit_name'] = "Nombre de outfit", + ["wardrobe:empty"] = "El armario de ropa está vacío", + ["wardrobe:delete"] = "%s - Eliminar", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Pulsa ~INPUT_CONTEXT~ para abrir el menú de jefe", + ["not_boss"] = "No eres el jefe", + ["boss_menu"] = "Menú de jefe", + ["boss:society_money"] = "Dinero sociedad: $%s", + ["boss:withdraw"] = "Sacar dinero sociedad", + ["boss:deposit"] = "Depositar dinero sociedad", + ["boss:wash_money"] = "Lavar dinero", + ["boss:grades"] = "Salarios", + ["boss:employees"] = "Empleados", + ["boss:withdraw_amount"] = "Sacar cantidad", + ["boss:deposit_amount"] = "Cantidad depositada", + ["boss:you_dont_have_enough_money"] = "No tienes ese dinero", + ["boss:invalid_amount"] = "Cantidad invalida", + ["boss:withdrew_money"] = "Has sacado ~g~$%s~s~", + ["boss:deposited_money"] = "Has depositado ~g~$%s~s~", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "Salario de nuevo grado", + ["boss:grade_salary_updated"] = "~y~salario~s~ ~g~actualizado~s~", + ["boss:grade_salary_not_updated"] = "~r~no puedes actualizar~s~ ~y~el salario~s~", + ["boss:employees_list"] = "Empleados", + ["boss:recruit"] = "Contratar", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Fuego", + ["boss:change_grade"] = "Cambiar grado", + ["boss:are_you_sure"] = "Seguro?", + ["boss:cancel"] = "Cancelar", + ["boss:employee_fired"] = "Empleado ~r~despedido~s~", + ["boss:you_got_hired"] = "Has sido ~g~contratado~s~ en ~b~%s~s~", + ["boss:you_hired"] = "Has sido ~g~despedido~s~ %s", + ["boss:nobody_close"] = "Nadie cerca", + ["boss:grade"] = "%d. %s - Salario $%s", + ["boss:changed_grade_successfully"] = "Grado cambiado", + ["boss:your_grade_changed_to"] = "Tu grado ha sido cambiado a ~b~%s~s~", + ["boss:how_much_to_wash"] = "Cuanto quieres lavar?", + ["boss:you_washed_money"] = "Has lavado ~g~$%s~s~", + ["boss:not_enough_dirty_money"] = "No tienes ~r~dinero negro~s~", + ["boss:couldnt_wash_money"] = "No puedes lavar el dinero ", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Pulsa ~INPUT_CONTEXT~ para abrir el garaje", + ["garage"] = "Garaje", + ["take_vehicle"] = "Coger vehículo", + ["park_vehicle"] = "Guardar vehículo", + ["no_vehicle"] = "No hay vehículo en el garaje", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Pulsa ~INPUT_CONTEXT~ para abrir la tienda", + ["job_shop"] = "Tienda de trabajo", + ['shop_item'] = "%s - $%d", + ['not_enough_money'] = "No tienes dinero", + ['you_bought'] = "Has comprado ~b~x%d~s~ ~y~%s~s~ por ~%s~$%s~s~", + ['shop_empty'] = "Tienda vacía", + ['shop:you_already_have_that_weapon'] = "Ya tienes una ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Comprar vehículo", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "Has ~g~comprado~s~ un vehículo", + ['are_you_sure'] = "Estás seguro de comprar %s por $%s?", + ['no_vehicles_in_garage'] = "No hay vehículos en el garaje", + ['vehicle_outside'] = "No hay vehículo en el garaje", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "No hay vehículos para comprar", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Presiona ~INPUT_CONTEXT~ para abrir el garaje", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Pulsa ~INPUT_CONTEXT~ para abrir la mesa de crafteo", + ['crafting_table'] = "Mesa de craft", + ['dont_have_ingredients'] = "No tienes todos los objetos ~r~requeridos~s~", + ['crafting'] = "Crafteando %s", + ['you_crafted'] = "Has crafteado ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Tienes ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Pulsa ~INPUT_CONTEXT~ para cancelar", + ['you_stopped'] = "Pararás cuadno termines la fabricación", + ['crafting_table:nothing_to_craft'] = "Nada que hacer", + + -- [[ Armory stuff ]] + ['open_armory'] = "Pulsa ~INPUT_CONTEXT~ para abrir el armario", + ['not_have_any_weapon'] = "No tienes ningún arma", + ['armory'] = "Armario", + ['armory_take'] = "Armario - Coger", + ['armory_deposit'] = "Armario - Depositar", + ['take_weapon'] = "Coger arma", + ['deposit_weapon'] = "Guardar arma", + ['you_dont_have_weapon'] = "No ~r~tienes~s~ esa arma", + ['no_weapons_in_armory'] = "No hay armas", + ['you_deposited_weapon'] = "Has ~g~guardado~s~ %s", + ['you_took_weapon'] = "Has ~r~cogido~s~ %s", + ['you_already_have_that_weapon'] = "Tienes ~g~%s~s~", + ['weapon_ammo'] = "Munición de arma", + ['weapon'] = "%s - x%d balas", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Pulsa ~INPUT_CONTEXT~ para abrir la ropa de trabajo", + ['job_outfit'] = "Ropa de trabajo", + ['no_outfits'] = "Ropa no disponible", + ['civilian_outfit'] = "Ropa civil", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Pulsa ~INPUT_CONTEXT~ para entrar", + ['teleport_to'] = "Pulsa ~INPUT_CONTEXT~ para ir a %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Pulsa ~INPUT_CONTEXT~ para abrir la caja", + ['account'] = "%s - $%s", + ['safe'] = "Caja", + ['empty_safe'] = "Caja vacía", + ['nothing_to_deposit'] = "No hay nada guardado aquí", + ['withdrawn_safe'] = "Has sacado %s$%s %s~s~", + ['deposited_safe'] = "Has depositado %s$%s %s~s~", + ['cash'] = "Dinero", + ['withdraw'] = "Sacar", + + -- [[ Market Stuff ]] + ['open_market'] = "Pulsa ~INPUT_CONTEXT~ para abrir la tienda", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Mercado", + ['not_enough_item'] = "No tienes esto %s", + ['you_sold'] = "Has vendido ~b~x%d~s~ ~y~%s~s~ for %s$%s", + ['nothing_can_be_sold_yet'] = "Nada para vender aquí", + ['market:how_many_to_sell'] = "Cuanto quieres vender?", + ['market:you_are_already_selling'] = "Ya estás vendiendo", + ['market:selling'] = "Vendiendo x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Pulsa ~INPUT_CONTEXT~ para recoger", + ['harvest:harvesting'] = "Recogiendo %s", + ['harvest:press_to_stop'] = "Presiona ~INPUT_CONTEXT~ para parar", + ['harvest:you_will_stop_on_finish'] = "Te detendrás en el final", + ['harvest:you_need_tool_count'] = "Necesitas ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Necesitas ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Pulsa ~INPUT_CONTEXT~ para abrir el mejorador de armas", + ['weapon_upgrader'] = "Mejoras de Armas", + ['owned_component'] = "%s - En propiedad", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Predeterminado", + ['tint_green'] = "Verde", + ['tint_gold'] = "Oro", + ['tint_pink'] = "Rosa", + ['tint_army'] = "Militar", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Naranja", + ['tint_platinum'] = "Plata", + ['components'] = "Componentes", + ['tints'] = "Tintes", + ['already_have_tint'] = "Ya tienes este tinte", + ['bought_tint'] = "Has comprado un tinte ~y~%s~s~ para ~g~%s~s~", + ['bought_component'] = "Has comprado un ~y~%s~s~ para ~g~%s~s~", + ['removed_component'] = "Has quitado ~y~%s~s~ a la ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Pulsa ~INPUT_CONTEXT~ para entrar de ~g~servicio~s~", + ['go_off_duty'] = "Pulsa ~INPUT_CONTEXT~ para salir de ~r~servicio~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Pulsa ~INPUT_CONTEXT~ para abrir la tienda", + ['job_owned_shop'] = "Tienda de trabajo", + ['shop'] = "Tienda", + ['put_on_sale'] = "Poner a la venta", + ['remove_from_sale'] = "Quitar de la venta", + ['item_price'] = "Precio del objeto", + ['invalid_price'] = "Precio inválido", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "Tienda vacía", + ['job_shop_quantity'] = "Cantidad - x%d -> $%s", + ['job_shop_cant_afford'] = "No ~r~puedes permitirte~s~ eso", + ['job_shop:bought_item'] = "~g~Has comprado~s~ x%d ~y~%s~s~ por ~g~$%s~s~", + ['job_shop:add_supplies'] = "Añadir objeto", + ['job_shop:what_to_put_on_sale'] = "Qué quieres poner a la venta?", + ['job_shop:what_to_remove_from_sale'] = "Qué quieres borrar de la venta?", + ['job_shop:what_to_restock'] = "Qué quieres reabastecer?", + ['job_shop:how_many_to_restock'] = "Cuanto quieres reabastecer?", + ['job_shop:added_to_supplies'] = "Agregado ~b~x%d~s~ ~y~%s~s~ al stock", + ['job_shop:you_put_on_sale'] = "Has puesto a vender ~b~x%d~s~ ~y~%s~s~ por ~g~$%s~s~", + ['job_shop:you_removed_from_sale'] = "Has quitado de la venta ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Tienes ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "No tienes para vender", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Pulsa ~INPUT_CONTEXT~ para procesar", + ['process:you_need'] = "Necesitas ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Procesando %s", + ['process:press_to_stop'] = "Presiona ~INPUT_CONTEXT~ para parar", + ['process:you_will_stop_on_finish'] = "Te detendrás en el final", + ['process:no_space'] = "No puedes llevar ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Nickname: %s\nIdentifier: %s\n\n%s", + + ['log_deposited_stash'] = "Depositado ítem", + ['log_deposited_stash_description'] = "Depositado x**%d** **%s** (**%s**) en mercado ID **%d**", + + ['log_took_stash'] = "Ítem cogido", + ['log_took_stash_description'] = "Cogido x**%d** **%s** (**%s**) del mercado ID **%d**", + + ['log_deposited_weapon'] = "Depositado armas", + ['log_deposited_weapon_description'] = "Depositado **%s** (**%s**) con x**%d** municion en el mercado ID **%d**", + + ['log_took_weapon'] = "Cogido armas", + ['log_took_weapon_description'] = "Cogido **%s** (**%s**) with x**%d** municion en el mercado ID **%d**", + + ['log_deposited_money'] = "Depositado dinero", + ['log_deposited_money_description'] = "Deposita $**%d** en la sociedad '**%s**'", + + ['log_withdrew_money'] = "Sacado dinero", + ['log_withdrew_money_description'] = "Saca $**%d** de la sociedad '**%s**'", + + ['log_updated_salary'] = "Modificado salario", + ['log_updated_salary_description'] = "Subio el salario del grado **%d** to **$%s**", + + ['log_fired_employee'] = "Empleado despedido", + ['log_fired_employee_description'] = "Ha despedido al empleado con identificador **%s**", + + ['log_recruited_employee'] = "Reclutar empleado", + ['log_recruited_employee_description'] = "Reclutado **%s** con el identificador **%s**", + + ['log_changed_grade_employee'] = "Cambiar rango del empleado", + ['log_changed_grade_employee_description'] = "Cambio el grado **%s** a **%d**", + + ['log_washed_money'] = "Dinero lavado", + ['log_washed_money_description'] = "Lavado $**%s**", + + ['log_sold_item'] = "Vender ítems", + ['log_sold_item_description'] = "Vendió **x%d** **%s** por **$%s**", + + ['log_bought_item'] = "Comprar ítem", + ['log_bought_item_description'] = "Compró x%d **%s** (**%s**) del marcador con ID **%d**", + + ['log_not_existing_item'] = "No existe el objeto", + ['log_not_existing_item_description'] = "Intentó comprar '**%s**' del marcador ID **%d**, pero no hay objeto en tienda", + + ['log_bought_vehicle'] = "Vehículo comprado", + ['log_bought_vehicle_description'] = "Compró '**%s**' for $**%d** del marcador ID **%d**", + + ['log_not_existing_vehicle'] = "No existe el vehículo", + ['log_not_existing_vehicle_description'] = "Intentó comprar '**%s**' del marcador ID **%d**, pero el vehículo no existe", + + ['log_crafted_item'] = "Ítem fabricado", + ['log_crafted_item_description'] = "Fabricó **x%d** **%s** (**%s**) en marcador ID **%d**", + + ['log_deposited_safe'] = "Deposito en la caja", + ['log_deposited_safe_description'] = "Depositó $**%s** **%s** en marcador ID **%d**", + + ['log_withdrew_safe'] = "Sacó de la caja", + ['log_withdrew_safe_description'] = "Sacó $**%s** **%s** del marcador ID **%d**", + + ['log_harvested'] = "Farmeo", + ['log_harvested_description'] = "Farmeo x**%d** **%s** del marcador ID **%d**", + + ['log_bought_tint'] = "Compró tinte", + ['log_bought_tint_description'] = "Compró el **%s** '**%s**' tinte por $**%d** del marcador ID **%d**", + + ['log_removed_component'] = "Quitó componente", + ['log_removed_component_description'] = "Quitó **%s** el **%s** del marcador ID **%d**", + + ['log_bought_component'] = "Compró componente", + ['log_bought_component_description'] = "Compró **%s** por **%s** del marcador ID **%d**", + + ['log_not_allowed_marker'] = "No tiene marcador en uso", + ['log_not_allowed_marker_description'] = "Intentó usar el marcador ID %d pero no es suyo", + + ['logs:process:title'] = "Procesado", + ['logs:process:description'] = "Procesado **x%d** **%s** to **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Puesto a la venta", + ['logs:job_shop:put_on_sale:description'] = "Puso a la venta **x%d** **%s** for **$%s** en el marcador ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Quitado de la venta", + ['logs:job_shop:remove_from_sale:description'] = "Elimino **x%d** **%s** for **$%s** del marcador ID **%d**", + + ['logs:job_shop:bought_item'] = "artículo comprado", + ['logs:job_shop:bought_item:description'] = "Compro **x%d** **%s** for **$%s** en el marcador ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Añadido a los suministros", + ['logs:job_shop:add_to_supplies:description'] = "Añadido **x%d** **%s** for **$%s** a los suministros en el marcador ID **%d**", +} diff --git a/resources/[creators]/jobs_creator/locales/fr.lua b/resources/[creators]/jobs_creator/locales/fr.lua new file mode 100644 index 0000000..aff79bf --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/fr.lua @@ -0,0 +1,385 @@ +locales['fr'] = { + -- [[ Generic ]] + ["interact"] = "Appuyez sur ~INPUT_CONTEXT~ pour interagir", + ["billing_reason"] = "Raison de la facturation", + ["billing_amount"] = "Montant de la facturation", + ["no_players_nearby"] = "Aucun joueur à proximité", + ["no_vehicles_nearby"] = "Aucun véhicule à proximité", + ["invoice_sent"] = "~g~$%s~s~ facture envoyée", + ["too_far"] = "Trop loin", + ["yes"] = "Oui", + ["no"] = "Non", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Ouvrir le menu des actions", + ['actions_menu'] = "Menu d'actions", + ['actions_billing'] = "Facturation", + ['actions_search'] = "Rechercher", + ['actions_put_handcuffs'] = "Menotter/Démenotter", + ['actions_start_dragging'] = "Escorter/Relâcher", + ['actions_put_in_car'] = "Mettre dans le véhicule", + ['actions_take_from_car'] = "Sortir de la voiture", + ['actions_menu_search'] = "Rechercher un citoyen", + ['actions_lockpick_car'] = "Déverouiller la voiture", + ['no_car_found'] = "Aucune voiture à proximité", + ['not_locked_vehicle'] = "Ce véhicule n'est pas verrouillé", + ['you_need_lockpick'] = "Vous avez besoin d'un ~r~lockpick~s~", + ['lockpick_used'] = "Vous avez utilisé un ~r~lockpick~s~", + ['actions:lockpick:lockpickingVehicle'] = "Véhicule de crochetage", + ['actions_menu_search_took'] = "Vous ~g~pris~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ vous a été ~r~volé~s~", + ['actions_menu_search_took_money'] = "Vous ~g~pris~s~ ~y~$%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~$%s %s~s~ vous a été ~r~volé~s~", + ['actions_menu_search_doesnt_have_weapon'] = "Le joueur ~r~n'a pas~s~ cette arme", + ['actions_menu_search_took_weapon'] = "Vous ~g~avez pris~s~ ~y~%s~s~ avec ~y~%d balles~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ avec ~y~%d balles~s~ vous a été ~r~volé~s~", + ['you_need_handcuffs'] = "Vous avez besoin de ~r~menottes~s~", + ['not_handcuffed'] = "Le joueur n'est pas ~r~menotté~s~", + ['cant_while_dragging'] = "Action impossible en escortant", + ['search_inventory_empty'] = "L'inventaire est vide", + ['actions_menu_being_searched'] = "Vous êtes recherché", + ['actions:wash_vehicle'] = "Nettoyer le véhicule", + ['actions:washing_vehicle'] = "Nettoyage du véhicule", + ['actions:repair_vehicle'] = "Réparer le véhicule", + ['actions:repairing_vehicle'] = "Réparation du véhicule", + ['actions:no_vehicles_close'] = "Aucun véhicule à proximité", + ['actions:impound_vehicle'] = "Véhicule mis en fourrière", + ['actions:impounding_vehicle'] = "Mise en fourrière du véhicule", + ['actions:you_need'] = "Vous avez besoin de ~y~%s~s~", + ['actions:check_identity'] = "Vérifier l'identité", + ['actions:check_vehicle_owner'] = "Vérifier le propriétaire du véhicule", + ['actions:checkVehicleOwner:owner'] = "Le véhicule appartient à ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Propriétaire du véhicule introuvable", + ['actions:checkVehicleOwner:car_not_found'] = "Aucun véhicule à proximité", + ['actions:no_player_found'] = "Aucun citoyen à proximité", + ['actions:checkIdentity:player_found'] = "Nom du citoyen trouvé : ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Quelqu'un~s~ a vérifié votre identité", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Permis", + ['actions:no_license_found'] = "Aucun permis trouvée", + ['actions:check_licenses'] = "Vérifier les permis", + ['actions:driving_license'] = "Permis de conduire", + ['actions:weapon_license'] = "P.P.A", + ['actions:license:give_remove'] = "Supprimer des licences", + ['actions:gave_license'] = "Vous ~g~donné~s~ ~y~%s~s~", + ['actions:removed_license'] = "Vous avez ~r~retirer~s~ ~y~%s~s~", + ['actions:heal_small'] = "Guérir les petites blessures", + ['actions:heal_big'] = "Traiter les blessures graves", + ['actions:you_need_bandage'] = "Vous avez besoin d'un ~r~bandage~s~", + ['actions:revive'] = "Réanimé", + ['actions:you_need_medikit'] = "Vous avez besoin d'une ~r~trousse médicale~s~", + + -- [[ Stash stuff ]] + ["open_stash"] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir la cachette", + ["deposited"] = "Vous avez déposé x%d %s", + ["not_enough"] = "Pas assez ~y~%s~s~", + ["no_space"] = "Vous n'avez pas d'espace", + ["took"] = "Vous avez pris ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Impossible d'obtenir x%d %s", + ["empty_inventory"] = "Votre inventaire est vide", + ["empty_stash"] = "La cachette est vide", + ['stash'] = "Cachette", + ['stash_take'] = "Cacher - Prendre", + ['stash_deposit'] = "Cacher - Déposer", + ['quantity'] = "Quantité", + ['invalid_quantity'] = "Quantité invalide", + ['deposit'] = "Déposer", + ['take'] = "Prendre", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir l'armoire", + ['player_clothes'] = "Vos tenues", + ['remove_cloth'] = "Supprimer la tenue", + ['save_cloth'] = "Enregistrer la tenue actuelle", + ['you_saved_outfit'] = "Tenue enregistrée", + ['delete_outfit'] = "Tenue supprimée", + ['clothes'] = "Vêtements", + ['outfit_label_empty'] = "Le nom de la tenue est invalide", + ['outfit_name'] = "Le nom de votre tenue", + ["wardrobe:empty"] = "L'armoire est vide", + ["wardrobe:delete"] = "%s - Supprimer", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir le menu du patron", + ["not_boss"] = "Vous n'êtes pas le patron", + ["boss_menu"] = "Menu du patron", + ["boss:society_money"] = "Argent de la société : $%s", + ["boss:withdraw"] = "Retirer l'argent de la société", + ["boss:deposit"] = "Dépôt de l'argent de la société", + ["boss:wash_money"] = "Laver de l'argent", + ["boss:grades"] = "Gérer les salaires des grades", + ["boss:employees"] = "Gérer les employés", + ["boss:withdraw_amount"] = "Montant retiré", + ["boss:deposit_amount"] = "Montant déposé", + ["boss:you_dont_have_enough_money"] = "Vous n'avez pas assez d'argent", + ["boss:invalid_amount"] = "Montant invalide", + ["boss:withdrew_money"] = "Vous avez retiré ~g~$%s~s~", + ["boss:deposited_money"] = "Vous avez déposé ~g~$%s~s~", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "Nouveau salaire de grade", + ["boss:grade_salary_updated"] = "~y~Salaire du grade~s~ ~g~updated~s~", + ["boss:grade_salary_not_updated"] = "~r~Impossible de mettre à jour~s~ ~y~salaire du grade~s~", + ["boss:employees_list"] = "Liste des employés", + ["boss:recruit"] = "Recruter", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Renvoyé", + ["boss:change_grade"] = "Changer de grade", + ["boss:are_you_sure"] = "Êtes-vous sûr ?", + ["boss:cancel"] = "Annuler", + ["boss:employee_fired"] = "Employé ~r~licencié~s~", + ["boss:you_got_hired"] = "Vous avez ~g~embauché~s~ dans ~b~%s~s~", + ["boss:you_hired"] = "Vous ~g~embauché~s~ %s", + ["boss:nobody_close"] = "Aucun citoyen à proximité", + ["boss:grade"] = "%d. %s - Salaire $%s", + ["boss:changed_grade_successfully"] = "Changement de grade avec succès", + ["boss:your_grade_changed_to"] = "Votre grade est passée à ~b~%s~s~", + ["boss:how_much_to_wash"] = "Combien d'argent voulez-vous laver ?", + ["boss:you_washed_money"] = "Vous avez lavé ~r~$%s~s~ et avez reçu ~g~$%s~s~", + ["boss:not_enough_dirty_money"] = "Vous n'avez pas assez d'~r~argent sale~s~", + ["boss:couldnt_wash_money"] = "Impossible de laver l'argent", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir le garage", + ["garage"] = "Garage", + ["take_vehicle"] = "Prendre le véhicule", + ["park_vehicle"] = "Ramasser le véhicule", + ["no_vehicle"] = "Il n'y a aucun véhicule dans ce garage", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir la boutique", + ["job_shop"] = "Boutique", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "Vous n'avez pas assez d'argent", + ['you_bought'] = "Vous avez acheté ~b~x%d~s~ ~y~%s~s~ pour ~%s~$%s~s~", + ['shop_empty'] = "Cette boutique est vide", + ['shop:you_already_have_that_weapon'] = "Vous avez déjà %s", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Acheter un véhicule", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "Vous ~g~acheté~s~ un véhicule", + ['are_you_sure'] = "Êtes-vous sûr de vouloir acheter %s pour $%s ?", + ['no_vehicles_in_garage'] = "Il n'y a aucun véhicule dans ce garage", + ['vehicle_outside'] = "Le véhicule n'est pas dans le garage", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Il n'y a aucun véhicule à acheter", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir le garage", + + -- [[ Objets de table d'artisanat ]] + ['open_crafting_table'] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir la table d'artisanat", + ['crafting_table'] = "Table d'artisanat", + ['dont_have_ingredients'] = "Vous n'avez pas tous les ingrédients ~r~requis~s~", + ['crafting'] = "Artisanat %s", + ['you_crafted'] = "Vous avez fabriqué ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Vous avez déjà ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Appuyez sur ~INPUT_CONTEXT~ pour arrêter", + ['you_stopped'] = "Vous arrêterez à la fin de la fabrication", + ['crafting_table:nothing_to_craft'] = "Rien à fabriquer", + + -- [[ Armory stuff ]] + ['open_armory'] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir l'armurerie", + ['not_have_any_weapon'] = "Vous n'avez pas d'arme", + ['armory'] = "Armurerie", + ['armory_take'] = "Armurerie - Prendre", + ['armory_deposit'] = "Armurerie - Dépôt", + ['take_weapon'] = "Prendre l'arme", + ['deposit_weapon'] = "Déposer d'arme", + ['you_dont_have_weapon'] = "Vous ~r~n'avez~s~ pas cette arme", + ['no_weapons_in_armory'] = "Il n'y a pas d'armes ici", + ['you_deposited_weapon'] = "Vous avez déposé %s", + ['you_took_weapon'] = "Vous avez pris %s", + ['you_already_have_that_weapon'] = "Vous avez déjà %s", + ['weapon_ammo'] = "Munitions d'armes", + ['weapon'] = "%s - x%d balles", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir les tenues de travail", + ['job_outfit'] = "Tenues de travail", + ['no_outfits'] = "Aucune tenue disponible", + ['civilian_outfit'] = "Tenue civile", + + -- [[ Trucs de téléportation ]] + ['teleport'] = "Appuyez sur ~INPUT_CONTEXT~ pour vous téléporter", + ['teleport_to'] = "Appuyez sur ~INPUT_CONTEXT~ pour aller à %s", + + -- [[ Trucs sûrs ]] + ['open_safe'] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir le coffre-fort", + ['account'] = "%s - $%s", + ['safe'] = "Coffre-Fort", + ['empty_safe'] = "Le coffre est vide", + ['nothing_to_deposit'] = "Vous n'avez rien à déposer ici", + ['withdrawn_safe'] = "Vous avez retiré %s$%s %s~s~", + ['deposited_safe'] = "Vous avez déposé %s$%s %s~s~", + ['cash'] = "Argent", + ['withdraw'] = "Retirer", + + -- [[ Marché ]] + ['open_market'] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir le marché", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Marché", + ['not_enough_item'] = "Vous n'avez pas assez de %s", + ['you_sold'] = "Vous avez vendu ~b~x%d~s~ ~y~%s~s~ pour %s$%s", + ['nothing_can_be_sold_yet'] = "Rien ne peut être vendu ici pour le moment", + ['market:how_many_to_sell'] = "Quelle quantité souhaitez-vous vendre ?", + ['market:you_are_already_selling'] = "Vous vendez déjà", + ['market:selling'] = "Vente x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Appuyez sur ~INPUT_CONTEXT~ pour récolter", + ['harvest:harvesting'] = "Récolte %s", + ['harvest:press_to_stop'] = "Appuyez sur ~INPUT_CONTEXT~ pour arrêter", + ['harvest:you_will_stop_on_finish'] = "Vous vous arrêterez à la fin", + ['harvest:you_need_tool_count'] = "Vous avez besoin de ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Vous avez besoin de ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir l'upgrade d'arme", + ['weapon_upgrader'] = "Améliorateur d'armes", + ['owned_component'] = "%s - Possédé", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Par défaut", + ['tint_green'] = "Vert", + ['tint_gold'] = "Or", + ['tint_pink'] = "Rose", + ['tint_army'] = "Armée", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Orange", + ['tint_platinum'] = "Platine", + ['composants'] = "Composantes", + ['teintes'] = "Teintes", + ['already_have_tint'] = "Vous avez déjà cette teinte", + ['bought_tint'] = "Vous avez acheté ~y~%s~s~ teinte pour ~g~%s~s~", + ['bought_component'] = "Vous avez acheté ~y~%s~s~ pour ~g~%s~s~", + ['removed_component'] = "Vous avez supprimé ~y~%s~s~ de ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Appuyez sur ~INPUT_CONTEXT~ vous mettre ~g~en service~s~", + ['go_off_duty'] = "Appuyez sur ~INPUT_CONTEXT~ vous mettre ~r~hors service~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Appuyez sur ~INPUT_CONTEXT~ pour ouvrir la boutique", + ['job_owned_shop'] = "Shop", + ['shop'] = "Boutique", + ['put_on_sale'] = "Mettre en vente", + ['remove_from_sale'] = "Supprimer de la vente", + ['item_price'] = "Prix de l'article", + ['invalid_price'] = "Prix invalide", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "La boutique est vide", + ['job_shop_quantity'] = "Quantité - x%d -> $%s", + ['job_shop_cant_afford'] = "Vous ~r~ne pouvez pas vous permettre~s~ ça", + ['job_shop:bought_item'] = "Vous ~g~acheté~s~ x%d ~y~%s~s~ pour ~g~$%s~s~", + ['job_shop:add_supplies'] = "Ajouter des fournitures", + ['job_shop:what_to_put_on_sale'] = "Que souhaiteriez-vous mettre en vente ?", + ['job_shop:what_to_remove_from_sale'] = "Que souhaitez-vous retirer de la vente ?", + ['job_shop:what_to_restock'] = "Que souhaitez-vous réapprovisionner ?", + ['job_shop:how_many_to_restock'] = "Combien ajouter au stock ?", + ['job_shop:added_to_supplies'] = "Ajout ~b~x%d~s~ ~y~%s~s~ aux fournitures", + ['job_shop:you_put_on_sale'] = "Vous avez mis en vente ~b~x%d~s~ ~y~%s~s~ pour ~g~$%s~s~", + ['job_shop:you_removed_from_sale'] = "Vous avez retiré de la vente ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Vous avez déjà %s", + ['job_shop:nothing_to_sell'] = "Vous n'avez rien à vendre", + + -- [[ Traiter des trucs ]] + ['process:press_to_process'] = "Appuyez sur ~INPUT_CONTEXT~ pour traiter", + ['process:you_need'] = "Vous avez besoin de ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Traitement %s", + ['process:press_to_stop'] = "Appuyez sur ~INPUT_CONTEXT~ pour arrêter", + ['process:you_will_stop_on_finish'] = "Vous vous arrêterez à la fin", + ['process:no_space'] = "Vous ne pouvez pas transporter ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Pseudo : %s\nIdentifiant : %s\n\n%s", + + ['log_deposited_stash'] = "Article déposé", + ['log_deposited_stash_description'] = "Dépôt x**%d** **%s** (**%s**) dans l'ID de marqueur **%d**", + + ['log_took_stash'] = "Objet pris", + ['log_took_stash_description'] = "A pris x**%d** **%s** (**%s**) à partir de l'ID de marqueur **%d**", + + ['log_deposited_weapon'] = "Arme déposée", + ['log_deposited_weapon_description'] = "Déposé **%s** (**%s**) avec x**%d** munitions dans l'ID de marqueur **%d**", + + ['log_took_weapon'] = "a pris l'arme", + ['log_took_weapon_description'] = "A pris **%s** (**%s**) avec x**%d** munitions dans l'ID de marqueur **%d**", + + ['log_deposited_money'] = "Déposer de l'argent", + ['log_deposited_money_description'] = "Déposé $**%d** dans la société '**%s**'", + + ['log_withdrew_money'] = "Retirer de l'argent", + ['log_withdrew_money_description'] = "Retiré $**%d** de la société '**%s**'", + + ['log_updated_salary'] = "Salaire mis à jour", + ['log_updated_salary_description'] = "Salaire mis à jour du grade **%d** à **$%s**", + + ['log_fired_employee'] = "Employé renvoyé", + ['log_fired_employee_description'] = "Joueur viré avec identifiant **%s**", + + ['log_recruited_employee'] = "Employé embauché", + ['log_recruited_employee_description'] = "Recruté **%s** dont l'identifiant est **%s**", + + ['log_changed_grade_employee'] = "Changement du grade de l'employé", + ['log_changed_grade_employee_description'] = "Changement du grade de l'employé **%s** en **%d**", + + ['log_washed_money'] = "Argent lavé", + ['log_washed_money_description'] = "Lavé $**%s**", + + ['log_sold_item'] = "Article vendu", + ['log_sold_item_description'] = "Vendu **x%d** **%s** pour **$%s**", + + ['log_bought_item'] = "Article acheté", + ['log_bought_item_description'] = "Acheté x%d **%s** (**%s**) à partir de l'ID de marqueur **%d**", + + ['log_not_existing_item'] = "Élément non existant", + ['log_not_existing_item_description'] = "J'ai essayé d'acheter '**%s**' à partir de l'ID de marqueur **%d**, mais l'article n'est pas dans la boutique", + + ['log_bought_vehicle'] = "Véhicule acheté", + ['log_bought_vehicle_description'] = "Acheté '**%s**' pour $**%d** à partir de l'ID de marqueur **%d**", + + ['log_not_existing_vehicle'] = "Véhicule non existant", + ['log_not_existing_vehicle_description'] = "J'ai essayé d'acheter '**%s**' à partir de l'ID de marqueur **%d**, mais le véhicule n'est pas dans le garage", + + ['log_crafted_item'] = "Objet fabriqué", + ['log_crafted_item_description'] = "Fabriqué **x%d** **%s** (**%s**) dans l'ID de marqueur **%d**", + + ['log_deposited_safe'] = "Déposer dans le coffre-fort", + ['log_deposited_safe_description'] = "Dépôt $**%s** **%s** dans l'ID de marqueur **%d**", + + ['log_withdrew_safe'] = "Retiré du coffre-fort", + ['log_withdrew_safe_description'] = "Retiré $**%s** **%s** de l'ID de marqueur **%d**", + + ['log_harvested'] = "Récolté", + ['log_harvested_description'] = "Récolté x**%d** **%s** à partir de l'ID de marqueur **%d**", + + ['log_bought_tint'] = "Teinte achetée", + ['log_bought_tint_description'] = "Acheté la teinte **%s** '**%s**' pour $**%d** à partir de l'ID de marqueur **%d**", + + ['log_removed_component'] = "Composante supprimée", + ['log_removed_component_description'] = "Retiré **%s** de **%s** de l'ID de marqueur **%d**", + + ['log_bought_component'] = "Composante achetée", + ['log_bought_component_description'] = "Acheté **%s** pour **%s** à partir de l'ID de marqueur **%d**", + + ['log_not_allowed_marker'] = "Utilisation du marqueur non autorisée", + ['log_not_allowed_marker_description'] = "J'ai essayé d'utiliser l'ID de marqueur %d mais il n'est pas autorisé", + + ['logs:process:title'] = "Traité", + ['logs:process:description'] = "Traité **x%d** **%s** à **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Mettre en vente", + ['logs:job_shop:put_on_sale:description'] = "Mettre en vente **x%d** **%s** pour **$%s** dans l'ID de marqueur **%d**", + + ['logs:job_shop:remove_from_sale'] = "Retiré de la vente", + ['logs:job_shop:remove_from_sale:description'] = "Retiré **x%d** **%s** pour **$%s** de l'ID de marqueur **%d**", + + ['logs:job_shop:bought_item'] = "Article acheté", + ['logs:job_shop:bought_item:description'] = "Acheté **x%d** **%s** pour **$%s** dans l'ID de marqueur **%d**", + + ['logs:job_shop:add_to_supplies'] = "Ajouté aux fournitures", + ['logs:job_shop:add_to_supplies:description'] = "Ajouté **x%d** **%s** pour **$%s** aux fournitures dans l'ID de marqueur **%d**", +} diff --git a/resources/[creators]/jobs_creator/locales/hu.lua b/resources/[creators]/jobs_creator/locales/hu.lua new file mode 100644 index 0000000..617174b --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/hu.lua @@ -0,0 +1,412 @@ +locales['hu'] = { + -- [[ Generic ]] + ["interact"] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy interakcióba lépj.", + ["billing_reason"] = "Számla indokja", + ["billing_amount"] = "Számla ára", + ["no_players_nearby"] = "Nincsen játékos a közlelben", + ["no_vehicles_nearby"] = "Nincsen jármü a közelben", + ["invoice_sent"] = "~g~$%s~s~ számla kiállitva", + ["too_far"] = "Túl messze", + ["yes"] = "Igen", + ["no"] = "Nem", + ["you_need_minimum_account_money"] = "Szükséged van legalább $~y~%d~s~ ebbe ~b~%s~s~", + ["bill"] = "Számla", + ["bill_received"] = "Kaptál egy számlát
    Ára: $%s
    Indokja: %s

    ", + ["bill_paid"] = "Befizetted a számlát $%s", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Menü megnyitása", + ['actions_menu'] = "Tevékenység Menü", + ['actions_billing'] = "Számlázás", + ['actions_search'] = "Keresés", + ['actions_start_dragging'] = "Vezető Szár", + ['actions_put_in_car'] = "Kocsiba rakás", + ['actions_take_from_car'] = "Kocsiból kivétel", + ['actions_menu_search'] = "Átkutatás", + ['actions_lockpick_car'] = "Autó zárfeltörés", + ['no_car_found'] = "Nincs a közeledben autó", + ['not_locked_vehicle'] = "Az autó nincs bezárva", + ['you_need_lockpick'] = "Szükséged van egy ~r~zárfeltörö~s~-re", + ['lockpick_used'] = "Elhasználtad a ~r~zárfeltörö~s~-t", + ['actions:lockpick:lockpickingVehicle'] = "Jármü Feltörése", + ['actions_menu_search_took'] = "Éppen ~g~Átkutatod~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ ezt ~r~elvették~s~ töled", + ['actions_menu_search_took_money'] = "Te ~g~Elvettél tőle ~s~ ~y~$%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~$%s %s~s~ ennyit ~r~elvett~s~ töled", + ['actions_menu_search_doesnt_have_weapon'] = "A Játékosnak ~r~nincsen~s~ ilyen fegyvere", + ['actions_menu_search_took_weapon'] = "Te ~g~elvettél~s~ ~y~%s~s~ ennyi ~y~%d lőszerrel~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ ennyi ~y~%d lőszerrel~s~ el lett ~r~véve~s~ tőled", + ['you_need_handcuffs'] = "Szükséged van ~r~bilincsre~s~", + ['not_handcuffed'] = "Nincsen ~r~megbilincselve~s~", + ['cant_while_dragging'] = "Vezetö száron ezt nem teheted meg", + ['search_inventory_empty'] = "A Játékosnál nincs semmi", + ['actions_menu_being_searched'] = "Jelenleg átkutatnak", + ['actions:wash_vehicle'] = "Jármü mosás", + ['actions:washing_vehicle'] = "Jármü mosása", + ['actions:repair_vehicle'] = "Jármü javitás", + ['actions:repairing_vehicle'] = "Jármü javitása", + ['actions:no_vehicles_close'] = "Nincs közelben jármü", + ['actions:impound_vehicle'] = "Jármü lefoglalás", + ['actions:impounding_vehicle'] = "Jármü lefoglalása", + ['actions:you_need'] = "Szükséged van ~y~%s~s~", + ['actions:check_identity'] = "Személyazonosság ellenörzése", + ['actions:check_vehicle_owner'] = "Jármü Tulajdonosa", + ['actions:checkVehicleOwner:owner'] = "Ez a jármü az ö tulajdona: ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Ennek a jármünek nincs tulajdonosa", + ['actions:checkVehicleOwner:car_not_found'] = "Nincs jármü a közelben", + ['actions:no_player_found'] = "Nics játékos a kzelben", + ['actions:checkIdentity:player_found'] = "Neve: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Valaki~s~ megnézte a személyazonosságod", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Engedélyek", + ['actions:no_license_found'] = "Nincsenek engedélyei", + ['actions:check_licenses'] = "Engedélyek megnézése", + ['actions:driving_license'] = "Vezetöi Engedély", + ['actions:weapon_license'] = "Fegyver Engedély", + ['actions:license:give_remove'] = "Elvett engedélyt", + ['actions:gave_license'] = "Te ~g~kaptál~s~ ~y~%s~s~", + ['actions:removed_license'] = "Töled ~r~elvettek~s~ ~y~%s~s~", + ['actions:heal_small'] = "Kisebb sebek gyógyitása", + ['actions:heal_big'] = "Nagyobb sebek gyógyitása", + ['actions:you_need_bandage'] = "Szükséged van ~r~kötszerre~s~", + ['actions:revive'] = "Újraélesztés", + ['actions:revive:not_dead'] = "A játékos nincs meghalva", + ['actions:you_need_medikit'] = "Szükséged van ~r~elsösegélycsomagra~s~", + ['actions:the_player_must_be_handcuffed'] = "Megkell bilicselned vagy fel kell tennie a kezét", + + -- [[ Stash stuff ]] + ["open_stash"] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy megnyisd a tárolót.", + ["deposited"] = "Betettél ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "Nincs elég ~y~%s~s~", + ["no_space"] = "Nincs elég helyed", + ["took"] = "Kivettél ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Nem lehet kivenni x%d %s", + ["empty_inventory"] = "Nincs semmi nálad", + ["empty_stash"] = "Nincs semmi a tárolóba", + ['stash'] = "Tároló", + ['stash_take'] = "Tárolóból - Kivétel", + ['stash_deposit'] = "Tárolóból - Betétel", + ['quantity'] = "Mennyiség", + ['invalid_quantity'] = "Érvénytelen mennyiség", + ['deposit'] = "Berakás", + ['take'] = "Kivétel", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Nyomd meg a ~INPUT_CONTEXT~ hogy megnyisd a wardrobe-ot", + ['player_clothes'] = "Saját Ruhák", + ['remove_cloth'] = "Ruha Törlés", + ['save_cloth'] = "Jelenlegi ruha mentése", + ['you_saved_outfit'] = "Ruha elmentve", + ['delete_outfit'] = "Ruha Törölve", + ['clothes'] = "Ruhák", + ['outfit_label_empty'] = "Ruha neve üres!", + ['outfit_name'] = "Ruha neve", + ["wardrobe:empty"] = "Wardrobe üres!", + ["wardrobe:delete"] = "%s - Törlés", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Nyomd meg a ~INPUT_CONTEXT~ hogy megnyisd a Fönöki menüt!", + ["not_boss"] = "Nem vagy Fönök!", + ["boss_menu"] = "Fönök Menü", + ["boss:society_money"] = "Frakció Pénz: $%s", + ["boss:withdraw"] = "Pénz Kivétel", + ["boss:deposit"] = "Pénz Betétel", + ["boss:wash_money"] = "Pénz Mosás", + ["boss:grades"] = "Fizetések kezelése", + ["boss:employees"] = "Tagok Kezelése", + ["boss:withdraw_amount"] = "Kivétel Mennyiség", + ["boss:deposit_amount"] = "Betétel Mennyiség", + ["boss:you_dont_have_enough_money"] = "Nincs elég pénzed", + ["boss:invalid_amount"] = "Érvénytelen mennyiség", + ["boss:withdrew_money"] = "Kivettél ~g~$%s~s~", + ["boss:deposited_money"] = "Betettél ~g~$%s~s~", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "Új fizetés", + ["boss:grade_salary_updated"] = "~y~Rang Fizetése~s~ ~g~frissitve~s~", + ["boss:grade_salary_not_updated"] = "~r~Nembirod Frissiteni~s~ ~y~a fizetést~s~", + ["boss:employees_list"] = "Tagok listája", + ["boss:recruit"] = "Új Tag felvétele", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Kirugás", + ["boss:change_grade"] = "Rang Megváltoztatás", + ["boss:are_you_sure"] = "Biztos vagy benne?", + ["boss:cancel"] = "Mégse", + ["boss:employee_fired"] = "Tag ~r~Kirugva~s~", + ["boss:you_got_hired"] = "Kilettél ~g~rúgva~s~ innen ~b~%s~s~", + ["boss:you_hired"] = "Fel ~g~lettél véve~s~ %s", + ["boss:nobody_close"] = "Senki sincs közel", + ["boss:grade"] = "%d. %s - Fizetés $%s", + ["boss:changed_grade_successfully"] = "Sikeres rangváltoztatás", + ["boss:your_grade_changed_to"] = "Rangod módositva lett ~b~%s~s~", + ["boss:how_much_to_wash"] = "Mennyi pénzt szeretnél kimosni?", + ["boss:you_washed_money"] = "Mostál ennyit ~r~$%s~s~ és ennyit kaptál ~g~$%s~s~", + ["boss:not_enough_dirty_money"] = "Nincs elég ~r~Piszkos pénzed~s~", + ["boss:couldnt_wash_money"] = "Nem tudsz pénz mosni!", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Nyomd meg a ~INPUT_CONTEXT~ to open garage", + ["garage"] = "Garázs", + ["take_vehicle"] = "Jármü Kivétel", + ["park_vehicle"] = "Jármü Tárolása", + ["no_vehicle"] = "Nincs jármü a garázsodba!", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Nyomd meg a ~INPUT_CONTEXT~ hogy megnyisd a boltot", + ["job_shop"] = "Munka Bolt", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "Nincs elég pénzed", + ['you_bought'] = "Vettél ~b~x%d~s~ ~y~%s~s~ ennyiért ~%s~$%s~s~", + ['shop_empty'] = "Ez a bolt üres!", + ['shop:you_already_have_that_weapon'] = "Neked már van ilyened ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Jármü Vétel", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "~g~Vettél~s~ egy kocsit", + ['are_you_sure'] = "Biztos megveszed ezt %s ennyiért $%s?", + ['no_vehicles_in_garage'] = "Nincs jármüved a garázsban", + ['vehicle_outside'] = "Nincs a jármü a garázsban!", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Nincs semmi amit megtudnál venni.", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Nyomd meg a ~INPUT_CONTEXT~ hogy megnyisd a garázst.", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy megnyisd a craft asztalt", + ['crafting_table'] = "Craft Asztal", + ['dont_have_ingredients'] = "Nincsen meg az összes ~r~szükséges~s~ tárgy", + ['crafting'] = "Craftolás %s", + ['you_crafted'] = "Craftoltál ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Neked már van ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy megállisd", + ['you_stopped'] = "Megszakitottad a craftolást", + ['crafting_table:nothing_to_craft'] = "Nincs semmid a craftoláshoz", + ["craft_amount"] = "Craft mennyiség", + + -- [[ Armory stuff ]] + ['open_armory'] = "Nyomd meg a ~INPUT_CONTEXT~ hogy megnyisd a fegyver raktárat.", + ['not_have_any_weapon'] = "Nincsen fegyvered", + ['armory'] = "Fegyver Raktár", + ['armory_take'] = "Fegyver Raktár - Kivétel", + ['armory_deposit'] = "Fegyver raktár - Betétel", + ['take_weapon'] = "Fegyver kivétele", + ['deposit_weapon'] = "Fegyver betétele", + ['you_dont_have_weapon'] = "Neked ~r~nincs~s~ ilyen fegyvered", + ['no_weapons_in_armory'] = "Nincs bent fegyver.", + ['you_deposited_weapon'] = "Te ~g~leraktad~s~ %s", + ['you_took_weapon'] = "Te ~r~felvetted~s~ %s", + ['you_already_have_that_weapon'] = "Neked már van egy ~g~%s~s~", + ['weapon_ammo'] = "Fegyver löszer", + ['weapon'] = "%s - x%d löszer", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Nyomd meg a ~INPUT_CONTEXT~ megnyisd a öltözöt", + ['job_outfit'] = "Munka ruhák", + ['no_outfits'] = "Nincsen semmilyen ruha", + ['civilian_outfit'] = "Civil Öltözet", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot a teleportáláshoz", + ['teleport_to'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy teleportálj ide %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy megnyisd a széfet", + ['account'] = "%s - $%s", + ['safe'] = "Széf", + ['empty_safe'] = "Üres a széf", + ['nothing_to_deposit'] = "Nincs semmi amit betehetnél ide", + ['withdrawn_safe'] = "Kivettél ennyit %s$%s %s~s~", + ['deposited_safe'] = "Betettél ennyit %s$%s %s~s~", + ['cash'] = "Készpénz", + ['withdraw'] = "Kivétel", + + -- [[ Market Stuff ]] + ['open_market'] = "Nyomd meg a ~INPUT_CONTEXT~ to open market", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Piac", + ['not_enough_item'] = "Nincsen neked elég ebből %s", + ['you_sold'] = "Eladtál ~b~x%d~s~ ~y~%s~s~ ennyiért %s$%s", + ['nothing_can_be_sold_yet'] = "Nincs semmi amit elbirnál adni", + ['market:how_many_to_sell'] = "Mennyit szeretnél eladni", + ['market:you_are_already_selling'] = "Jelenleg eladsz", + ['market:selling'] = "Eladás x%d - %s", + + -- [[ Harvest Stuff ]] + + ['harvest'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot az aratáshoz", + ['harvest:harvesting'] = "Aratás %s", + ['harvest:press_to_stop'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy befejezd", + ['harvest:you_will_stop_on_finish'] = "Sikeresen befejezted", + ['harvest:you_need_tool_count'] = "Szükséged van erre ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Szükséged van erre ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Nyomd meg a ~INPUT_CONTEXT~ hogy megnyisd a fegyver upgradet", + ['weapon_upgrader'] = "Fegyver Upgrader", + ['owned_component'] = "%s - Saját", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Alap", + ['tint_green'] = "Zöld", + ['tint_gold'] = "Arany", + ['tint_pink'] = "Rózsaszin", + ['tint_army'] = "Army", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Narancssárga", + ['tint_platinum'] = "Platinum", + ['components'] = "Alkatrészek", + ['tints'] = "Árnyalatok", + ['already_have_tint'] = "Neked már van ilyen árnyalatod", + ['bought_tint'] = "Vettél ilyen ~y~%s~s~ árnyalatod ennyiért ~g~%s~s~", + ['bought_component'] = "Vettél ~y~%s~s~ ennyiért ~g~%s~s~", + ['removed_component'] = "Eltávolitottad ezt ~y~%s~s~ erröl ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy ~g~felvedd a szolgálatot~s~", + ['go_off_duty'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy ~r~leadd a szolgálatot~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy megnyisd a boltot", + ['job_owned_shop'] = "Munka Bolt", + ['shop'] = "Bolt", + ['put_on_sale'] = "Eladásra kinálás", + ['remove_from_sale'] = "Eladásról eltávolitás", + ['item_price'] = "Tárgy Ára", + ['invalid_price'] = "Érvénytelen ár", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "Üres a bolt", + ['job_shop_quantity'] = "Mennyiség - x%d -> $%s", + ['job_shop_cant_afford'] = "Nem ~r~teheted meg~s~ ezt", + ['job_shop:bought_item'] = "~g~Vettél~s~ x%d ~y~%s~s~ ennyiért ~g~$%s~s~", + ['job_shop:add_supplies'] = "Kellékek hozzáadása", + ['job_shop:what_to_put_on_sale'] = "Mit szeretnél eladni?", + ['job_shop:what_to_remove_from_sale'] = "Mit szeretnél kivenni?", + ['job_shop:what_to_restock'] = "Mit szeretnél utánpotlásba rakni?", + ['job_shop:how_many_to_restock'] = "Mennyit szeretnél eladásra kinálni?", + ['job_shop:added_to_supplies'] = "Hozzáadva ~b~x%d~s~ ~y~%s~s~ a utánpotláshoz", + ['job_shop:you_put_on_sale'] = "Eladásra kináltál ~b~x%d~s~ ~y~%s~s~ ennyiért ~g~$%s~s~", + ['job_shop:you_removed_from_sale'] = "Eladásból eltávolitottad ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Már van ilyened ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Nincs semmi amit elbirnál adni", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot a folyamathoz", + ['process:you_need'] = "Neked szükséged van ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Folyamat %s", + ['process:press_to_stop'] = "Nyomd meg a ~INPUT_CONTEXT~ gombot hogy megszakisd", + ['process:you_will_stop_on_finish'] = "Sikeresen megszakitottad", + ['process:no_space'] = "Nem tudod cipelni ezt ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Nickname: %s\nIdentifier: %s\n\n%s", + + ['log_deposited_stash'] = "Berakott Tárgy", + ['log_deposited_stash_description'] = "Berakott x**%d** **%s** (**%s**) in marker ID **%d**", + + ['log_took_stash'] = "Vett tárgy", + ['log_took_stash_description'] = "Vett x**%d** **%s** (**%s**) from marker ID **%d**", + + ['log_deposited_weapon'] = "Berakott fegyver", + ['log_deposited_weapon_description'] = "Berakott **%s** (**%s**) with x**%d** ammo in marker ID **%d**", + + ['log_took_weapon'] = "Vett Fegyver", + ['log_took_weapon_description'] = "Vett **%s** (**%s**) with x**%d** ammo in marker ID **%d**", + + ['log_deposited_money'] = "Berakott pénz", + ['log_deposited_money_description'] = "Berakott $**%d** in society '**%s**'", + + ['log_withdrew_money'] = "Kivett pénz", + ['log_withdrew_money_description'] = "Kivett $**%d** from society '**%s**'", + + ['log_updated_salary'] = "Fizetés Szerkesztve", + ['log_updated_salary_description'] = "Fizetés szerkesztve ebbe a rendfokozatba **%d** to **$%s**", + + ['log_fired_employee'] = "Ember kirugás", + ['log_fired_employee_description'] = "Kirugott egy embert azonositója **%s**", + + ['log_recruited_employee'] = "Ember felvétele", + ['log_recruited_employee_description'] = "Felvett **%s** azonositója **%s**", + + ['log_changed_grade_employee'] = "Rangja megváltoztatva", + ['log_changed_grade_employee_description'] = "Megváltoztatta a rangját neki **%s** to **%d**", + + ['log_washed_money'] = "Pénz Mosás", + ['log_washed_money_description'] = "Mosott $**%s**", + + ['log_sold_item'] = "Eladott tárgy", + ['log_sold_item_description'] = "Eladott **x%d** **%s** for **$%s**", + + ['log_bought_item'] = "Vett tárgy", + ['log_bought_item_description'] = "Vett x%d **%s** (**%s**) marker ID **%d**", + + ['log_not_existing_item'] = "Nem megfelő item", + ['log_not_existing_item_description'] = "Megprobált venni '**%s**' from marker ID **%d**, ami nincs a boltba", + + ['log_bought_vehicle'] = "Vett autót", + ['log_bought_vehicle_description'] = "Vett '**%s**' for $**%d** from marker ID **%d**", + + ['log_not_existing_vehicle'] = "Nem megfelelő autó", + ['log_not_existing_vehicle_description'] = "Megprobált venni '**%s**' from marker ID **%d**, ami nincs a garázsban", + + ['log_crafted_item'] = "Craftolt Tárgy", + ['log_crafted_item_description'] = "Craftolt **x%d** **%s** (**%s**) in marker ID **%d**", + + ['log_deposited_safe'] = "Berakott a széfbe", + ['log_deposited_safe_description'] = "Berakott $**%s** **%s** in marker ID **%d**", + + ['log_withdrew_safe'] = "Kivett a széfből", + ['log_withdrew_safe_description'] = "Kivett $**%s** **%s** from marker ID **%d**", + + ['log_harvested'] = "Aratott", + ['log_harvested_description'] = "Aratott x**%d** **%s** from marker ID **%d**", + + ['log_bought_tint'] = "Vásárolt árnyalatot", + ['log_bought_tint_description'] = "Megvette a **%s** '**%s**' árnyalatot erre $**%d** from marker ID **%d**", + + ['log_removed_component'] = "Alkatrész eltávolitva", + ['log_removed_component_description'] = "Eltávolitott **%s** erről **%s** from marker ID **%d**", + + ['log_bought_component'] = "Alkatrészt vett", + ['log_bought_component_description'] = "Vett **%s** for **%s** from marker ID **%d**", + + ['log_not_allowed_marker'] = "Nincs hozzá joga hogy használja", + ['log_not_allowed_marker_description'] = "Használni probálta a CP-t ID %d amihez nincs joga", + + ['logs:process:title'] = "Feldolgozott", + ['logs:process:description'] = "Feldolgozott **x%d** **%s** erre **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Eladásra kinálta", + ['logs:job_shop:put_on_sale:description'] = "Eladásra kinált **x%d** **%s** enyiért **$%s** in marker ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Kivette az eladásból", + ['logs:job_shop:remove_from_sale:description'] = "Eltávolitotta **x%d** **%s** ennyiért **$%s** from marker ID **%d**", + + ['logs:job_shop:bought_item'] = "Vett tárgyat", + ['logs:job_shop:bought_item:description'] = "Vett **x%d** **%s** Ennyiért **$%s** in marker ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Hozzáadva a kellékekhez", + ['logs:job_shop:add_to_supplies:description'] = "Hozzáadta **x%d** **%s** ennyiért **$%s** to supplies in marker ID **%d**", + + -- Steal action + ['logs:actions:stolen_item'] = "Elvett tárgy", + ['logs:actions:stolen_item:description'] = "Elvett **x%d** **%s** tőle **%s** (%s)", + + ['logs:actions:stolen_account'] = "Elvett felhasználó", + ['logs:actions:stolen_account:description'] = "Elvett $**%d** **%s** tőle **%s** (%s)", + + ['logs:actions:stolen_weapon'] = "Elvett fegyver", + ['logs:actions:stolen_weapon:description'] = "Elvett **%s** ennyi **x%s** lőszerrel tőle **%s** (%s)", + + -- Other + ["you_cant_do_this_in_a_vehicle"] = "Ezt nem csinálhatod jármüben", + ["society_received_money_from_your_sale"] = "Munkáltatód elküldte a fizetésedet: ~g~$%s~s~", + ["actions_put_soft_handcuffs"] = "Megbilincselés", + ["actions_put__hard_handcuffs"] = "Eloldozás", + ["now_you_are_on_duty"] = "Szolgálatba léptél", + ["now_you_are_off_duty"] = "Kiléptél a szolgálatból", + + ["item_received"] = "Kaptál ~b~x%d~s~ ~y~%s~s~" +} diff --git a/resources/[creators]/jobs_creator/locales/it.lua b/resources/[creators]/jobs_creator/locales/it.lua new file mode 100644 index 0000000..cf6c3ca --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/it.lua @@ -0,0 +1,385 @@ +locales['it'] = { + -- [[ Generic ]] + ["interact"] = "Premi ~INPUT_CONTEXT~ per interagire", + ["billing_reason"] = "Motivo fattura", + ["billing_amount"] = "Importo fattura", + ["no_players_nearby"] = "Nessun giocatore vicino", + ["no_vehicles_nearby"] = "Nessun veicolo vicino", + ["invoice_sent"] = "~g~$%s~s~ fattura inviata", + ["too_far"] = "Troppo lontano", + ["yes"] = "Si", + ["no"] = "No", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Apri menu azioni", + ['actions_menu'] = "Menu azioni", + ['actions_billing'] = "Fattura", + ['actions_search'] = "Perquisisci", + ['actions_put_handcuffs'] = "Ammanetta", + ['actions_start_dragging'] = "Trascina", + ['actions_put_in_car'] = "Metti nel veicolo", + ['actions_take_from_car'] = "Prendi dal veicolo", + ['actions_menu_search'] = "Perquisisci giocatore", + ['actions_lockpick_car'] = "Scassina veicolo", + ['no_car_found'] = "Nessun veicolo vicino", + ['not_locked_vehicle'] = "Questo veicolo non è chiuso", + ['you_need_lockpick'] = "Hai bisogno di un ~r~grimaldello~s~", + ['lockpick_used'] = "Hai usato un ~r~grimaldello~s~", + ['actions:lockpick:lockpickingVehicle'] = "Scassinando veicolo", + ['actions_menu_search_took'] = "Hai ~g~preso~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ ti è stato ~r~preso~s~", + ['actions_menu_search_took_money'] = "Hai ~g~preso~s~ ~y~$%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~$%s %s~s~ ti sono stati ~r~presi~s~", + ['actions_menu_search_doesnt_have_weapon'] = "Il giocatore non ~r~non't~s~ ha quell'arma", + ['actions_menu_search_took_weapon'] = "Hai ~g~preso~s~ ~y~%s~s~ con ~y~%d proiettili~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ con ~y~%d proiettili~s~ ti sono stati ~r~rubati~s~", + ['you_need_handcuffs'] = "Hai bisogno delle ~r~manette~s~", + ['not_handcuffed'] = "Il giocatore non è ~r~ammanettato~s~", + ['cant_while_dragging'] = "Non puoi farlo mentre trascini", + ['search_inventory_empty'] = "Inventario vuoto", + ['actions_menu_being_searched'] = "Stai venendo perquisito", + ['actions:wash_vehicle'] = "Lava veicolo", + ['actions:washing_vehicle'] = "Lavando veicolo", + ['actions:repair_vehicle'] = "Ripara veicolo", + ['actions:repairing_vehicle'] = "Riparando veicolo", + ['actions:no_vehicles_close'] = "Nessun veicolo vicino", + ['actions:impound_vehicle'] = "Sequestra veicolo", + ['actions:impounding_vehicle'] = "Sequestrando veicolo", + ['actions:you_need'] = "Hai bisogno di ~y~%s~s~", + ['actions:check_identity'] = "Controlla identità", + ['actions:check_vehicle_owner'] = "Controlla proprietario veicolo", + ['actions:checkVehicleOwner:owner'] = "Il veicolo è di ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Proprietario veicolo non trovato", + ['actions:checkVehicleOwner:car_not_found'] = "Nessun veicolo vicino", + ['actions:no_player_found'] = "Nessuno vicino", + ['actions:checkIdentity:player_found'] = "Nome cittadino trovato: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Qualcuno~s~ ha controllato la tua identità", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Licenze", + ['actions:no_license_found'] = "Nessuna licenza trovata", + ['actions:check_licenses'] = "Controlla licenze", + ['actions:driving_license'] = "Patente", + ['actions:weapon_license'] = "Porto d'armi", + ['actions:license:give_remove'] = "Rimuovi licenze", + ['actions:gave_license'] = "Hai ~g~dato~s~ ~y~%s~s~", + ['actions:removed_license'] = "Hai ~r~rimosso~s~ ~y~%s~s~", + ['actions:heal_small'] = "Cura ferite lievi", + ['actions:heal_big'] = "Cura ferite serie", + ['actions:you_need_bandage'] = "Hai bisogno di ~r~benda~s~", + ['actions:revive'] = "Rianima", + ['actions:you_need_medikit'] = "Hai bisogno di ~r~kit medico~s~", + + -- [[ Stash stuff ]] + ["open_stash"] = "Premi ~INPUT_CONTEXT~ per aprire l'inventario", + ["deposited"] = "Hai depositato ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "Non abbastanza ~y~%s~s~", + ["no_space"] = "Non hai spazio", + ["took"] = "Hai preso ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Impossibile prendere x%d %s", + ["empty_inventory"] = "Il tuo inventario è vuoto", + ["empty_stash"] = "L'inventario è vuoto", + ['stash'] = "Inventario", + ['stash_take'] = "Inventario - Prendi", + ['stash_deposit'] = "Inventario - Deposita", + ['quantity'] = "Quantità", + ['invalid_quantity'] = "Quantità non valida", + ['deposit'] = "Deposita", + ['take'] = "Prendi", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Premi ~INPUT_CONTEXT~ per aprire il guardaroba", + ['player_clothes'] = "I tuoi completi", + ['remove_cloth'] = "Cancella completo", + ['save_cloth'] = "Salva completo corrente", + ['you_saved_outfit'] = "Completo salvato", + ['delete_outfit'] = "Completo cancellato", + ['clothes'] = "Vestiti", + ['outfit_label_empty'] = "Il nome del completo non può essere vuoto", + ['outfit_name'] = "Nome del completo", + ["wardrobe:empty"] = "Il guardaroba è vuoto", + ["wardrobe:delete"] = "%s - Cancella", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Premi ~INPUT_CONTEXT~ per aprire il menu boss", + ["not_boss"] = "Non sei il boss", + ["boss_menu"] = "Menu boss", + ["boss:society_money"] = "Soldi società: $%s", + ["boss:withdraw"] = "Ritira soldi dalla società", + ["boss:deposit"] = "Deposita soldi nella società", + ["boss:wash_money"] = "Pulisci soldi", + ["boss:grades"] = "Imposta salari per gradi", + ["boss:employees"] = "Gestisci dipendenti", + ["boss:withdraw_amount"] = "Quantità da ritirare", + ["boss:deposit_amount"] = "Quantità da depositare", + ["boss:you_dont_have_enough_money"] = "Non hai abbastanza soldi", + ["boss:invalid_amount"] = "Importo non valido", + ["boss:withdrew_money"] = "Hai ritirato ~g~$%s~s~", + ["boss:deposited_money"] = "Hai depositato ~g~$%s~s~", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "Nuovo salario per il grado", + ["boss:grade_salary_updated"] = "~y~Salario per il grado~s~ ~g~aggiornato~s~", + ["boss:grade_salary_not_updated"] = "~r~Impossibile aggiornare~s~ ~y~salario per il grado~s~", + ["boss:employees_list"] = "Lista dipendenti", + ["boss:recruit"] = "Assumi", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Licenzia", + ["boss:change_grade"] = "Cambia grado", + ["boss:are_you_sure"] = "Sei sicuro?", + ["boss:cancel"] = "Cancella", + ["boss:employee_fired"] = "Impiegato ~r~licenziato~s~", + ["boss:you_got_hired"] = "Sei stato ~g~assunto~s~ in ~b~%s~s~", + ["boss:you_hired"] = "Hai ~g~assunto~s~ %s", + ["boss:nobody_close"] = "Nessuno vicino", + ["boss:grade"] = "%d. %s - Salario $%s", + ["boss:changed_grade_successfully"] = "Cambiato grado con successo", + ["boss:your_grade_changed_to"] = "Il tuo grado è cambiato a ~b~%s~s~", + ["boss:how_much_to_wash"] = "Quanti soldi devi pulire?", + ["boss:you_washed_money"] = "Hai pulito ~r~$%s~s~ e hai ricevuto ~g~$%s~s~", + ["boss:not_enough_dirty_money"] = "Non hai abbastanza ~r~soldi sporchi~s~", + ["boss:couldnt_wash_money"] = "Impossibile pulire i soldi", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Premi ~INPUT_CONTEXT~ per aprire il garage", + ["garage"] = "Garage", + ["take_vehicle"] = "Prendi veicolo", + ["park_vehicle"] = "Parcheggia veicolo", + ["no_vehicle"] = "Non ci sono veicoli in questo garage", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Premi ~INPUT_CONTEXT~ per aprire il negozio", + ["job_shop"] = "Negozio del lavoro", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "Non hai abbastanza soldi", + ['you_bought'] = "Hai comprato ~b~x%d~s~ ~y~%s~s~ a ~%s~$%s~s~", + ['shop_empty'] = "Il negozio è vuoto", + ['shop:you_already_have_that_weapon'] = "Hai già ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Compra veicolo", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "Hai ~g~comprato~s~ un veicolo", + ['are_you_sure'] = "Sei sicuro di voler comprare %s a $%s?", + ['no_vehicles_in_garage'] = "Non ci sono veicoli in questo garage", + ['vehicle_outside'] = "Il veicolo non è in garage", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Non ci sono veicoli da comprare", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Premi ~INPUT_CONTEXT~ per aprire il garage", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Premi ~INPUT_CONTEXT~ per aprire la tavola da lavoro", + ['crafting_table'] = "Tavola da lavoro", + ['dont_have_ingredients'] = "Non hai tutti gli oggetti ~r~richiesti~s~", + ['crafting'] = "Creando %s", + ['you_crafted'] = "Hai creato ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Hai già ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Premi ~INPUT_CONTEXT~ per fermarti", + ['you_stopped'] = "Ti fermerai al termine di questo craft", + ['crafting_table:nothing_to_craft'] = "Niente da creare", + + -- [[ Armory stuff ]] + ['open_armory'] = "Premi ~INPUT_CONTEXT~ per aprire il deposito armi", + ['not_have_any_weapon'] = "Non hai nessun'arma", + ['armory'] = "Deposito armi", + ['armory_take'] = "Deposito armi - Prendi", + ['armory_deposit'] = "Deposito armi - Deposita", + ['take_weapon'] = "Prendi arma", + ['deposit_weapon'] = "Deposita arma", + ['you_dont_have_weapon'] = "~r~Non hai~s~ quell'arma", + ['no_weapons_in_armory'] = "Non ci sono armi", + ['you_deposited_weapon'] = "Hai ~g~depositato~s~ %s", + ['you_took_weapon'] = "Hai ~r~preso~s~ %s", + ['you_already_have_that_weapon'] = "Hai già ~g~%s~s~", + ['weapon_ammo'] = "Munizioni arma", + ['weapon'] = "%s - x%d proiettili", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Premi ~INPUT_CONTEXT~ per aprire i completi da lavoro", + ['job_outfit'] = "Completi da lavoro", + ['no_outfits'] = "Nessun completo disponibile", + ['civilian_outfit'] = "Completo da cittadino", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Premi ~INPUT_CONTEXT~ per teletrasportarti", + ['teleport_to'] = "Premi ~INPUT_CONTEXT~ per andare a %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Premi ~INPUT_CONTEXT~ per aprire la cassaforte", + ['account'] = "%s - $%s", + ['safe'] = "Cassaforte", + ['empty_safe'] = "La cassaforte è vuota", + ['nothing_to_deposit'] = "Non hai niente da depositare qui", + ['withdrawn_safe'] = "Hai ritirato %s$%s %s~s~", + ['deposited_safe'] = "Hai depositato %s$%s %s~s~", + ['cash'] = "Contanti", + ['withdraw'] = "Ritira", + + -- [[ Market Stuff ]] + ['open_market'] = "Premi ~INPUT_CONTEXT~ per accedere al mercato", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Mercato", + ['not_enough_item'] = "Non hai abbastanza %s", + ['you_sold'] = "Hai venduto ~b~x%d~s~ ~y~%s~s~ per %s$%s", + ['nothing_can_be_sold_yet'] = "Niente può ancora essere venduto qui", + ['market:how_many_to_sell'] = "Quanti ne vuoi vendere?", + ['market:you_are_already_selling'] = "Stai già vendendo", + ['market:selling'] = "Vendendo x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Premi ~INPUT_CONTEXT~ per raccogliere", + ['harvest:harvesting'] = "Raccogliendo %s", + ['harvest:press_to_stop'] = "Premi ~INPUT_CONTEXT~ per fermarti", + ['harvest:you_will_stop_on_finish'] = "Ti fermerai alla fine", + ['harvest:you_need_tool_count'] = "Hai bisogno di ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Hai bisogno di ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Premi ~INPUT_CONTEXT~ per aprire gli accessori per armi", + ['weapon_upgrader'] = "Accessori per armi", + ['owned_component'] = "%s - Posseduto", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Predefinito", + ['tint_green'] = "Verde", + ['tint_gold'] = "Oro", + ['tint_pink'] = "Rosa", + ['tint_army'] = "Militare", + ['tint_lspd'] = "Polizia", + ['tint_orange'] = "Arancione", + ['tint_platinum'] = "Platino", + ['components'] = "Accessori", + ['tints'] = "Colorazioni", + ['already_have_tint'] = "Hai già questa colorazione", + ['bought_tint'] = "Hai comprato la mimetica ~y~%s~s~ per ~g~%s~s~", + ['bought_component'] = "Hai comprato ~y~%s~s~ per ~g~%s~s~", + ['removed_component'] = "Hai tolto ~y~%s~s~ da ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Premi ~INPUT_CONTEXT~ per andare ~g~in servizio~s~", + ['go_off_duty'] = "Premi ~INPUT_CONTEXT~ per andare ~r~fuori servizio~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Premi ~INPUT_CONTEXT~ per aprire il negozio", + ['job_owned_shop'] = "Negozio lavoro", + ['shop'] = "Negozio", + ['put_on_sale'] = "Metti in vendita", + ['remove_from_sale'] = "Togli dalla vendita", + ['item_price'] = "Prezzo oggetto", + ['invalid_price'] = "Prezzo non valido", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "Il negozio è vuoto", + ['job_shop_quantity'] = "Quantità - x%d -> $%s", + ['job_shop_cant_afford'] = "~r~Non~s~ puoi permettertelo", + ['job_shop:bought_item'] = "Hai ~g~comprato~s~ x%d ~y~%s~s~ a ~g~$%s~s~", + ['job_shop:add_supplies'] = "Aggiungi scorte", + ['job_shop:what_to_put_on_sale'] = "Cosa vorresti mettere in vendita?", + ['job_shop:what_to_remove_from_sale'] = "Cosa vorresti togliere dalla vendita?", + ['job_shop:what_to_restock'] = "Cosa vorresti rifornire?", + ['job_shop:how_many_to_restock'] = "Quanti da aggiungere alla scorta?", + ['job_shop:added_to_supplies'] = "Aggiunti ~b~x%d~s~ ~y~%s~s~ alla scorta", + ['job_shop:you_put_on_sale'] = "Hai messo in vendita ~b~x%d~s~ ~y~%s~s~ a ~g~$%s~s~", + ['job_shop:you_removed_from_sale'] = "Hai tolto dalla vendita ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Hai già ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Non hai niente da vendere", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Premi ~INPUT_CONTEXT~ per processare", + ['process:you_need'] = "Hai bisogno di ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Processando %s", + ['process:press_to_stop'] = "Premi ~INPUT_CONTEXT~ per fermarti", + ['process:you_will_stop_on_finish'] = "Ti fermerai alla fine", + ['process:no_space'] = "Non puoi portare ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Nickname: %s\nIdentifier: %s\n\n%s", + + ['log_deposited_stash'] = "Oggetto depositato", + ['log_deposited_stash_description'] = "Depositato x**%d** **%s** (**%s**) nel marker ID **%d**", + + ['log_took_stash'] = "Oggetto preso", + ['log_took_stash_description'] = "Preso x**%d** **%s** (**%s**) dal marker ID **%d**", + + ['log_deposited_weapon'] = "Arma depositata", + ['log_deposited_weapon_description'] = "Depositata **%s** (**%s**) con x**%d** proiettili nel marker ID **%d**", + + ['log_took_weapon'] = "Arma presa", + ['log_took_weapon_description'] = "Presa **%s** (**%s**) con x**%d** proiettili nel marker ID **%d**", + + ['log_deposited_money'] = "Soldi depositati", + ['log_deposited_money_description'] = "Depositato $**%d** nella società '**%s**'", + + ['log_withdrew_money'] = "Soldi ritirati", + ['log_withdrew_money_description'] = "Ritirato $**%d** dalla società '**%s**'", + + ['log_updated_salary'] = "Salario aggiornato", + ['log_updated_salary_description'] = "Aggiornato salario del grado **%d** a **$%s**", + + ['log_fired_employee'] = "Dipendente licenziato", + ['log_fired_employee_description'] = "Licenziato dipendente con identifier **%s**", + + ['log_recruited_employee'] = "Dipendente assunto", + ['log_recruited_employee_description'] = "Assunto **%s** il cui identifier è **%s**", + + ['log_changed_grade_employee'] = "Cambiato grado al dipendente", + ['log_changed_grade_employee_description'] = "Cambiato grado al dipendente **%s** a **%d**", + + ['log_washed_money'] = "Puliti soldi", + ['log_washed_money_description'] = "Puliti $**%s**", + + ['log_sold_item'] = "Venduto oggetto", + ['log_sold_item_description'] = "Venduto **x%d** **%s** a **$%s**", + + ['log_bought_item'] = "Comprato oggetto", + ['log_bought_item_description'] = "Comprato x%d **%s** (**%s**) dal marker ID **%d**", + + ['log_not_existing_item'] = "Oggetto non esistente", + ['log_not_existing_item_description'] = "Ha cercato di comprare '**%s**' dal marker ID **%d**, ma l'oggetto non è nel negozio", + + ['log_bought_vehicle'] = "Comprato veicolo", + ['log_bought_vehicle_description'] = "Ha comprato '**%s**' a $**%d** dal marker ID **%d**", + + ['log_not_existing_vehicle'] = "Veicolo non esistente", + ['log_not_existing_vehicle_description'] = "Ha provato a comprare '**%s**' dal marker ID **%d**, ma il veicolo non è nel garage", + + ['log_crafted_item'] = "Oggetto craftato", + ['log_crafted_item_description'] = "Ha craftato **x%d** **%s** (**%s**) nel marker ID **%d**", + + ['log_deposited_safe'] = "Deposito nella cassaforte", + ['log_deposited_safe_description'] = "Ha depositato $**%s** **%s** nel marker ID **%d**", + + ['log_withdrew_safe'] = "Prelievo dalla cassaforte", + ['log_withdrew_safe_description'] = "Ha ritirato $**%s** **%s** dal marker ID **%d**", + + ['log_harvested'] = "Raccolto", + ['log_harvested_description'] = "Ha raccolto x**%d** **%s** dal marker ID **%d**", + + ['log_bought_tint'] = "Comprata colorazione", + ['log_bought_tint_description'] = "Ha comprato la colorazione **%s** '**%s**' a $**%d** dal marker ID **%d**", + + ['log_removed_component'] = "Rimosso un accessorio", + ['log_removed_component_description'] = "Ha rimosso **%s** da **%s** dal marker ID **%d**", + + ['log_bought_component'] = "Comprato un accessorio", + ['log_bought_component_description'] = "Ha comprato **%s** a **%s** dal marker ID **%d**", + + ['log_not_allowed_marker'] = "Uso non autorizzato di marker", + ['log_not_allowed_marker_description'] = "Ha provato ad usare il marker ID %d ma non ha il permesso", + + ['logs:process:title'] = "Processato", + ['logs:process:description'] = "Ha processato **x%d** **%s** in **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Messo in vendita", + ['logs:job_shop:put_on_sale:description'] = "Ha messo in vendita **x%d** **%s** a **$%s** nel marker ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Tolto dalla vendita", + ['logs:job_shop:remove_from_sale:description'] = "Ha tolto dalla vendita **x%d** **%s** a **$%s** dal marker ID **%d**", + + ['logs:job_shop:bought_item'] = "Comprato oggetto", + ['logs:job_shop:bought_item:description'] = "Ha comprato **x%d** **%s** per **$%s** nel marker ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Aggiunto alle scorte", + ['logs:job_shop:add_to_supplies:description'] = "Ha aggiunto **x%d** **%s** per **$%s** alle scorte nel marker ID **%d**", +} diff --git a/resources/[creators]/jobs_creator/locales/pl.lua b/resources/[creators]/jobs_creator/locales/pl.lua new file mode 100644 index 0000000..3fdebfa --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/pl.lua @@ -0,0 +1,401 @@ +locales['pl'] = { + -- [[ Generic ]] + ["interact"] = "Naciśnij przycisk ~INPUT_CONTEXT~, aby wejść w interakcję", + ["billing_reason"] = "Powód wystawienia faktury", + ["billing_amount"] = "Kwota na fakturze", + ["no_players_nearby"] = "Brak graczy w pobliżu", + ["no_vehicles_nearby"] = "Brak pojazdów w pobliżu", + ["invoice_sent"] = "~g~$%s~s~ faktura wysłana", + ["too_far"] = "Za daleko", + ["yes"] = "Tak", + ["no"] = "Nie", + ["you_need_minimum_account_money"] = "Potrzebujesz co najmniej $~y~%d~s~ w ~b~%s~s~.", + ["bill"] = "Bill", + ["bill_received"] = "Otrzymałeś fakturę
    Kwota: $%s
    Powód: %s

    Naciśnij poniższy przycisk, aby zaakceptować rachunek", + ["bill_paid"] = "Zapłaciłeś fakturę za $%s", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Otwórz menu akcji", + ['actions_menu'] = "Menu Akcji", + ['actions_billing'] = "Rachunki", + ['actions_search'] = "Przeszukaj", + ['actions_put_handcuffs'] = "Kajdanki", + ['actions_start_dragging'] = "Nieś", + ['actions_put_in_car'] = "Włóż do samochodu", + ['actions_take_from_car'] = "Wyjmij z auta", + ['actions_menu_search'] = "Wyszukaj gracza", + ['actions_lockpick_car'] = "Zablokuj Samochód", + ['no_car_found'] = "Nie znaleziono samochodu w pobliżu.", + ['not_locked_vehicle'] = "Ten pojazd nie jest zablokowany", + ['you_need_lockpick'] = "Potrzebujesz ~r~Wytrych~s~", + ['lockpick_used'] = "Użyto ~r~wytrych~s~", + ['actions:lockpick:lockpickingVehicle'] = "Włamywanie do auta", + ['actions_menu_search_took'] = " ~g~Wziąłeś~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ zostało ~r~ukradzione~s~ tobie", + ['actions_menu_search_took_money'] = " ~g~wzięto~s~ ~y~$%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~$%s %s~s~ zostało ~r~ukradzione~s~ tobie", + ['actions_menu_search_doesnt_have_weapon'] = "Gracz ~r~nie~s~ posiada tej broni", + ['actions_menu_search_took_weapon'] = "Ty ~g~zabrałeś~s~ ~y~%s~s~ z ~y~%d nabojami~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ z ~y~%d nabojami~s~ zostały ~r~ukradzione~s~ tobie", + ['you_need_handcuffs'] = "potrzebujesz ~r~kajdanek~s~", + ['not_handcuffed'] = "Gracz nie jest ~r~zakuty~s~", + ['cant_while_dragging'] = "Nie można tego zrobić podczas przenoszenia", + ['search_inventory_empty'] = "Pusty ekwipunek", + ['actions_menu_being_searched'] = "Jesteś przeszukiwany", + ['actions:wash_vehicle'] = "Umyj pojazd", + ['actions:washing_vehicle'] = "Mycie pojazdy", + ['actions:repair_vehicle'] = "Napraw pojazd", + ['actions:repairing_vehicle'] = "Naprawianie pojazdy", + ['actions:no_vehicles_close'] = "Brak pojazdu w pobliżu", + ['actions:impound_vehicle'] = "Skonfiskuj pojazd", + ['actions:impounding_vehicle'] = "Konfiskowanie pojazdu", + ['actions:you_need'] = "Potrzebujesz ~y~%s~s~", + ['actions:check_identity'] = "Sprawdź tożsamość", + ['actions:check_vehicle_owner'] = "Sprawdź właściciela pojazdu", + ['actions:checkVehicleOwner:owner'] = "Właścicielem pojazdu jest ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Właściciel pojazdy nie znaleziony", + ['actions:checkVehicleOwner:car_not_found'] = "Brak pojazdu w pobliżu", + ['actions:no_player_found'] = "Nikt w pobliżu", + ['actions:checkIdentity:player_found'] = "Znaleziono nazwę obywatela: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Ktoś~s~ sprawdził Twoją tożsamość", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Licencja", + ['actions:no_license_found'] = "Nie znaleziono licencje", + ['actions:check_licenses'] = "Sprawdź licencje", + ['actions:driving_license'] = "Prawo jazdy", + ['actions:weapon_license'] = "Pozwolenie na broń", + ['actions:license:give_remove'] = "Zabierz licencja", + ['actions:gave_license'] = " ~g~podałeś~s~ ~y~%s~s~", + ['actions:removed_license'] = " ~r~usunąłeś~s~ ~y~%s~s~", + ['actions:heal_small'] = "Opatrz małe rany", + ['actions:heal_big'] = "Leczenie poważnych urazów", + ['actions:you_need_bandage'] = "Potrzebujesz ~r~badaż~s~", + ['actions:revive'] = "Revive", + ['actions:revive:not_dead'] = "Ta osoba nie jest martwa", + ['actions:you_need_medikit'] = "Potrzebujesz ~r~Apteczki~s~", + + -- [[ Stash stuff ]] + ["open_stash"] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć schowek", + ["deposited"] = "Zdeponowałeś ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "Nie wystarczająca ilość ~y~%s~s~", + ["no_space"] = "Nie masz miejsca", + ["took"] = "Zabrałeś ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Niemożliwa do zdobycia x%d %s", + ["empty_inventory"] = "Twój ekwipunek jest pusty", + ["empty_stash"] = "Schowek jest pusty", + ['stash'] = "Schowek", + ['stash_take'] = "Schowek - weź", + ['stash_deposit'] = "Ekwipunek - Zdeponuj", + ['quantity'] = "Ilość", + ['invalid_quantity'] = "Nie prawidłowa ilość", + ['deposit'] = "Zdeponuj", + ['take'] = "Schowaj", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Wciśnij ~INPUT_CONTEXT~ aby otworzyć garderobe", + ['player_clothes'] = "Twoje stroje", + ['remove_cloth'] = "Usuń strój", + ['save_cloth'] = "Zapisz aktualny strój", + ['you_saved_outfit'] = "Strój zapisany", + ['delete_outfit'] = "Strój usunięty", + ['clothes'] = "Ubrania", + ['outfit_label_empty'] = "Nazwa stroju nie może być pusta", + ['outfit_name'] = "Nazwa twojego stroju", + ["wardrobe:empty"] = "Garderoba jest pusta", + ["wardrobe:delete"] = "%s - Usuń", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć menu szeda", + ["not_boss"] = "Nie jesteś szefem", + ["boss_menu"] = "Menu szefa", + ["boss:society_money"] = "Saldo konta: $%s", + ["boss:withdraw"] = "Wypłać z salda konta", + ["boss:deposit"] = "Wypłać pięniądze z salda", + ["boss:wash_money"] = "Wypierz pieniądze", + ["boss:grades"] = "Zarządzaj wypłatami rang", + ["boss:employees"] = "Zarządzaj pracownikami", + ["boss:withdraw_amount"] = "Wypłać kwotę", + ["boss:deposit_amount"] = "Kwota wpłaty", + ["boss:you_dont_have_enough_money"] = "Nie masz wystarczająco dużo pieniędzy", + ["boss:invalid_amount"] = "Nieprawidłowa kwota", + ["boss:withdrew_money"] = "Wypłaciłeś ~g~$%s~s~", + ["boss:deposited_money"] = "Zdeponowałeś ~g~$%s~s~", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "Nowe wynagrodzenie rangi", + ["boss:grade_salary_updated"] = "~y~Wynagrodzenie rangi~s~ ~g~Zaktualizowane~s~", + ["boss:grade_salary_not_updated"] = "~r~Nie można zaktualizować~s~ ~y~wynagrodzenia rangi~s~", + ["boss:employees_list"] = "Lista pracowników", + ["boss:recruit"] = "Zatrudnij", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Zwolniłeś", + ["boss:change_grade"] = "Zmień range", + ["boss:are_you_sure"] = "Na pewno?", + ["boss:cancel"] = "Anuluj", + ["boss:employee_fired"] = "Pracownik ~r~zwolniony~s~", + ["boss:you_got_hired"] = "Zostałeś ~g~zatrudniony~s~ w ~b~%s~s~", + ["boss:you_hired"] = " ~g~Zatrudniłeś~s~ %s", + ["boss:nobody_close"] = "Nikogo nie ma w pobliżu", + ["boss:grade"] = "%d. %s - Wynagrodzenie $%s", + ["boss:changed_grade_successfully"] = "Zmieniono range z powodzeniem", + ["boss:your_grade_changed_to"] = "Ranga została zmieniona na ~b~%s~s~", + ["boss:how_much_to_wash"] = "Ile pięniędzy chcesz wyprać?", + ["boss:you_washed_money"] = "Wyprałeś ~r~$%s~s~ i otrzymałeś ~g~$%s~s~", + ["boss:not_enough_dirty_money"] = "Nie masz wystarczającej ilości ~r~brudnej gotówki~s~", + ["boss:couldnt_wash_money"] = "Nie można wyprać pieniędzy", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć garaż", + ["garage"] = "Garaż", + ["take_vehicle"] = "Wyjmij pojazd", + ["park_vehicle"] = "Zaparkuj pojazd", + ["no_vehicle"] = "Nie ma pojazdu w tym garażu", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć sklep", + ["job_shop"] = "Zakład pracy", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "Nie masz wystarczającej ilości pieniędzy", + ['you_bought'] = "Kupiłeś ~b~x%d~s~ ~y~%s~s~ za ~%s~$%s~s~", + ['shop_empty'] = "Sklep jest pusty", + ['shop:you_already_have_that_weapon'] = "Już posiadasz ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Zakup pojazd", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = " ~g~kupiłeś~s~ pojazd", + ['are_you_sure'] = "Jesteś pewny aby zakupić %s for $%s?", + ['no_vehicles_in_garage'] = "W tym garażu nie ma żadnych pojazdów.", + ['vehicle_outside'] = "Pojazdu nie ma w garażu", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Nie ma pojazdów do kupienia", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć garaż", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć stół rzemieślniczy", + ['crafting_table'] = "Stół rzemieślniczy", + ['dont_have_ingredients'] = "Nie posiadasz wszystkich ~r~wymaganych~s~ rzeczy", + ['crafting'] = "Tworzenie %s", + ['you_crafted'] = "Stworzyłeś ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Już posiadasz ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Naciśnij ~INPUT_CONTEXT~ aby przestać", + ['you_stopped'] = "Przestaniesz gdy skończysz tworzyć", + ['crafting_table:nothing_to_craft'] = "Nic do stworzenia", + ["craft_amount"] = "Wytwórz ilość", + + -- [[ Armory stuff ]] + ['open_armory'] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć zbrojownie", + ['not_have_any_weapon'] = "Nie posiadasz żadnej broni", + ['armory'] = "Zbrojownia", + ['armory_take'] = "Zbrojownia - weź", + ['armory_deposit'] = "Zbrojownia - Zdeponuj", + ['take_weapon'] = "Weź broń", + ['deposit_weapon'] = "Zdeponuj broń", + ['you_dont_have_weapon'] = " ~r~Nie~s~ posiadasz tej broni", + ['no_weapons_in_armory'] = "Nie ma tu broni", + ['you_deposited_weapon'] = " ~g~Zdeponowałeś~s~ %s", + ['you_took_weapon'] = " ~r~wziąłeś~s~ %s", + ['you_already_have_that_weapon'] = "Już posiadasz ~g~%s~s~", + ['weapon_ammo'] = "Amunicja broni", + ['weapon'] = "%s - x%d kule", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć szafke roboczą", + ['job_outfit'] = "Stroje robocze", + ['no_outfits'] = "Brak dostępnych strojów", + ['civilian_outfit'] = "Strój prywatny", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Naciśnij ~INPUT_CONTEXT~ aby teleportować", + ['teleport_to'] = "Naciśnij ~INPUT_CONTEXT~ udać się do %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć sejf", + ['account'] = "%s - $%s", + ['safe'] = "Sejf", + ['empty_safe'] = "Sejf jest pusty", + ['nothing_to_deposit'] = "Nie masz nic do zdeponowania", + ['withdrawn_safe'] = "Wypłaciłeś %s$%s %s~s~", + ['deposited_safe'] = "Zdeponowałeś %s$%s %s~s~", + ['cash'] = "Gotówka", + ['withdraw'] = "anuluj", + + -- [[ Market Stuff ]] + ['open_market'] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć sklep", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Sklep", + ['not_enough_item'] = "Nie posiadasz wystarczająco %s", + ['you_sold'] = "Sprzedałeś ~b~x%d~s~ ~y~%s~s~ za %s$%s", + ['nothing_can_be_sold_yet'] = "Nie można tu jeszcze nic sprzedać", + ['market:how_many_to_sell'] = "Ile chcesz sprzedać?", + ['market:you_are_already_selling'] = "Już sprzedajesz", + ['market:selling'] = "Sprzedawanie x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Naciśnij ~INPUT_CONTEXT~ aby zebrać", + ['harvest:harvesting'] = "Zbieranie %s", + ['harvest:press_to_stop'] = "Naciśnij ~INPUT_CONTEXT~ aby przestać", + ['harvest:you_will_stop_on_finish'] = "Przestaniesz po zakończeniu", + ['harvest:you_need_tool_count'] = "Potrzebujesz ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Potrzebujesz ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć moduł ulepszania broni", + ['weapon_upgrader'] = "Ulepszanie broni", + ['owned_component'] = "%s - Posiadane", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Domyślne", + ['tint_green'] = "Zielony", + ['tint_gold'] = "Złoty", + ['tint_pink'] = "Różowy", + ['tint_army'] = "wojskowy", + ['tint_lspd'] = "Policyjny", + ['tint_orange'] = "Pomarańczowy", + ['tint_platinum'] = "Platynowy", + ['components'] = "Elementy", + ['tints'] = "Odcień", + ['already_have_tint'] = "Masz już ten odcień", + ['bought_tint'] = "Kupiłeś ~y~%s~s~ barwe za ~g~%s~s~", + ['bought_component'] = "Kupiłeś ~y~%s~s~ za ~g~%s~s~", + ['removed_component'] = "Usunąłeś ~y~%s~s~ z ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Naciśnij ~INPUT_CONTEXT~ aby wejść ~g~na służbe~s~", + ['go_off_duty'] = "Naciśnij ~INPUT_CONTEXT~ aby zejść ~r~ze służby~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Naciśnij ~INPUT_CONTEXT~ aby otworzyć sklep", + ['job_owned_shop'] = "Sklep pracy", + ['shop'] = "Sklep", + ['put_on_sale'] = "Wystaw na sprzedaż", + ['remove_from_sale'] = "Usuń ze sprzedaży", + ['item_price'] = "Koszt przedmiotu", + ['invalid_price'] = "Nieznana cena", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "Sklep jest pusty", + ['job_shop_quantity'] = "Ilość - x%d -> $%s", + ['job_shop_cant_afford'] = " ~r~nie stać cię na~s~ to", + ['job_shop:bought_item'] = " ~g~kupiłeś~s~ x%d ~y~%s~s~ za ~g~$%s~s~", + ['job_shop:add_supplies'] = "Dodaj zasoby", + ['job_shop:what_to_put_on_sale'] = "Co chcesz wystawić na sprzedaż?", + ['job_shop:what_to_remove_from_sale'] = "Co chcesz usunąć ze sprzedaży?", + ['job_shop:what_to_restock'] = "Co chciałbyś uzupełnić?", + ['job_shop:how_many_to_restock'] = "Ile należy dodać do zapasów?", + ['job_shop:added_to_supplies'] = "Dodano ~b~x%d~s~ ~y~%s~s~ do zasobów", + ['job_shop:you_put_on_sale'] = "Wystawiłeś na sprzedaż ~b~x%d~s~ ~y~%s~s~ za ~g~$%s~s~", + ['job_shop:you_removed_from_sale'] = "Usunąłeś ze sprzedaży ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Już posiadasz ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Nie masz nic na sprzedaż", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Naciśnij ~INPUT_CONTEXT~ aby przetworzyć", + ['process:you_need'] = "Potrzebujesz ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Przetwarzanue %s", + ['process:press_to_stop'] = "Naciśnij ~INPUT_CONTEXT~ aby przestać", + ['process:you_will_stop_on_finish'] = "Przestaniesz po zakończeniu", + ['process:no_space'] = "Nie masz miejsca ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Nazwa: %s\nIdentyfikator: %s\n\n%s", + + ['log_deposited_stash'] = "Zdeponuj przedmiot", + ['log_deposited_stash_description'] = "Zdeponowano x**%d** **%s** (**%s**) w znaczniku ID **%d**", + + ['log_took_stash'] = "Wizięto przedmiot", + ['log_took_stash_description'] = "Wzięto x**%d** **%s** (**%s**) w znaczniku ID **%d**", + + ['log_deposited_weapon'] = "Zdeponowano broń", + ['log_deposited_weapon_description'] = "Zdeponowano **%s** (**%s**) z x**%d** amunicją w znaczniku ID **%d**", + + ['log_took_weapon'] = "Wzięto broń", + ['log_took_weapon_description'] = "Zabrano **%s** (**%s**) z x**%d** amunicji w znaczniku ID **%d**", + + ['log_deposited_money'] = "Zdeponowano pieniądze", + ['log_deposited_money_description'] = "Zdeponowano $**%d** w society '**%s**'", + + ['log_withdrew_money'] = "Wypałacanie pięniędzy", + ['log_withdrew_money_description'] = "Wypłacono $**%d** z society '**%s**'", + + ['log_updated_salary'] = "Zaktualizowano wynagrodzenie", + ['log_updated_salary_description'] = "Zaktualizowano wynagrodzenie rangi **%d** to **$%s**", + + ['log_fired_employee'] = "Zwolniony pracownik", + ['log_fired_employee_description'] = "Zwolniono gracza z znacznikiem **%s**", + + ['log_recruited_employee'] = "Zatrudniono pracownika", + ['log_recruited_employee_description'] = "Zatrudniono **%s** którego identyfikator to **%s**", + + ['log_changed_grade_employee'] = "Zmiana stopnia pracownika", + ['log_changed_grade_employee_description'] = "Zmieniono stopień pracownikowi **%s** to **%d**", + + ['log_washed_money'] = "Wyprana gotówka", + ['log_washed_money_description'] = "Wyprano $**%s**", + + ['log_sold_item'] = "Sprzedano przedmiot", + ['log_sold_item_description'] = "Sprzedano **x%d** **%s** z **$%s**", + + ['log_bought_item'] = "Kupowanie przedmiotów", + ['log_bought_item_description'] = "Kupiono x%d **%s** (**%s**) z identifikatorem **%d**", + + ['log_not_existing_item'] = "Nie istniejący przedmiot", + ['log_not_existing_item_description'] = "Spróbowano kupić '**%s**' ze znacznikiem ID **%d**, ale rzecy nie ma w sklepie", + + ['log_bought_vehicle'] = "Kupiono pojazd", + ['log_bought_vehicle_description'] = "Zakupiono '**%s**' for $**%d** od znacznika ID **%d**", + + ['log_not_existing_vehicle'] = "Nie istniejący pojazd", + ['log_not_existing_vehicle_description'] = "Próbowano kupić pojazd '**%s**' od znacznika ID **%d**, ale pojazdu nie ma w garażu", + + ['log_crafted_item'] = "Stworzono item", + ['log_crafted_item_description'] = "Stworzono **x%d** **%s** (**%s**) w znaczniku ID **%d**", + + ['log_deposited_safe'] = "Zdeponowane w sejfie", + ['log_deposited_safe_description'] = "Zdeponowano $**%s** **%s** w znaczniku ID **%d**", + + ['log_withdrew_safe'] = "Wypłacono z sejfu", + ['log_withdrew_safe_description'] = "Wypłacono $**%s** **%s** z znacznika ID **%d**", + + ['log_harvested'] = "Zebrano", + ['log_harvested_description'] = "Zebrano x**%d** **%s** z znacznika ID **%d**", + + ['log_bought_tint'] = "Kupiono odcień", + ['log_bought_tint_description'] = "Kupiono **%s** '**%s**' odcień za $**%d** z znacznika ID **%d**", + + ['log_removed_component'] = "Usunięto dodatek", + ['log_removed_component_description'] = "Usunięto **%s** z **%s** z znacznika ID **%d**", + + ['log_bought_component'] = "Kupiono dodatek", + ['log_bought_component_description'] = "Kupiono **%s** za **%s** z znacznika ID **%d**", + + ['log_not_allowed_marker'] = "Niedozwolone użycie markera", + ['log_not_allowed_marker_description'] = "Probowano użyć znacznik ID %d ale nie wolno mu", + + ['logs:process:title'] = "Przetworzone", + ['logs:process:description'] = "Przetworzono **x%d** **%s** do **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Wystaw na sprzedaż", + ['logs:job_shop:put_on_sale:description'] = "Wystawiono na sprzedaż **x%d** **%s** za **$%s** w znaczniku ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Usunięto ze sprzedaży.", + ['logs:job_shop:remove_from_sale:description'] = "Usunięto **x%d** **%s** for **$%s** w znaczniku ID **%d**", + + ['logs:job_shop:bought_item'] = "Zakupiono item", + ['logs:job_shop:bought_item:description'] = "Zakupiono **x%d** **%s** za **$%s** w znaczniku ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Dodano do zasobów", + ['logs:job_shop:add_to_supplies:description'] = "Dodano **x%d** **%s** za **$%s** do zasobów w znacznku ID **%d**", + + -- Stolen Actions + ['logs:actions:stolen_item'] = "Stolen item", + ['logs:actions:stolen_item:description'] = "Has stolen x%d %s from %s (%s)", + + ['logs:actions:stolen_account'] = "Stolen account", + ['logs:actions:stolen_account:description'] = "Has stolen $%d %s from %s (%s)", + + ['logs:actions:stolen_weapon'] = "Stolen weapon", + ['logs:actions:stolen_weapon:description'] = "Has stolen %s with x%s bullets from %s (%s)", +} diff --git a/resources/[creators]/jobs_creator/locales/pt.lua b/resources/[creators]/jobs_creator/locales/pt.lua new file mode 100644 index 0000000..cc01f27 --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/pt.lua @@ -0,0 +1,385 @@ +locales['pt'] = { + -- [[ Generic ]] + ["interact"] = "Pressiona ~INPUT_CONTEXT~ para interagir", + ["billing_reason"] = "Motivo Da Fatura", + ["billing_amount"] = "Montante Da Fatura", + ["no_players_nearby"] = "Nenhum jogador por perto", + ["no_vehicles_nearby"] = "Nenhum veículo por perto", + ["invoice_sent"] = "~g~€%s~s~ Fatura enviada", + ["too_far"] = "Muito longe", + ["yes"] = "Sim", + ["no"] = "Não", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Abra o menu de ações", + ['actions_menu'] = "Menu De Ações", + ['actions_billing'] = "Fatura", + ['actions_search'] = "Procurar", + ['actions_put_handcuffs'] = "Algemar", + ['actions_start_dragging'] = "Arrastar", + ['actions_put_in_car'] = "Por no carro", + ['actions_take_from_car'] = "Tirar do carro", + ['actions_menu_search'] = "Revistar", + ['actions_lockpick_car'] = "Destrancar carro", + ['no_car_found'] = "Nenhum carro próximo encontrado", + ['not_locked_vehicle'] = "Este veículo não está trancado", + ['you_need_lockpick'] = "Tu precisas de um ~r~Destrancador~s~", + ['lockpick_used'] = "Tu usas-te um ~r~Destrancador~s~", + ['actions:lockpick:lockpickingVehicle'] = "Destrancando viatura", + ['actions_menu_search_took'] = "Tu ~g~retiras-te~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ foi ~r~roubado~s~ de ti", + ['actions_menu_search_took_money'] = "Tu ~g~tiras-te~s~ ~y~€%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~€%s %s~s~ foi ~r~roubado~s~ de ti", + ['actions_menu_search_doesnt_have_weapon'] = "O Jogador ~r~não tem~s~ essa arma", + ['actions_menu_search_took_weapon'] = "Tu ~g~tiras-te~s~ ~y~%s~s~ com ~y~%d balas~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ com ~y~%d balas~s~ foi ~r~roubado~s~ de ti", + ['you_need_handcuffs'] = "Tu precisas ~r~desalgemar~s~", + ['not_handcuffed'] = "Jogar nao esta ~r~algemado~s~", + ['cant_while_dragging'] = "Tu não pode fazer isso enquanto arrasta", + ['search_inventory_empty'] = "Inventario Vazio", + ['actions_menu_being_searched'] = "Estas a ser revistado", + ['actions:wash_vehicle'] = "Lavar veiculo", + ['actions:washing_vehicle'] = "Lavando veiculo", + ['actions:repair_vehicle'] = "Reparar veiculo", + ['actions:repairing_vehicle'] = "Reparando veiculo", + ['actions:no_vehicles_close'] = "Nenhum veículo fechado", + ['actions:impound_vehicle'] = "Veículo apreendido", + ['actions:impounding_vehicle'] = "Apreendendo veiculo", + ['actions:you_need'] = "Tu precisas ~y~%s~s~", + ['actions:check_identity'] = "Verificar identidade", + ['actions:check_vehicle_owner'] = "Verifique o proprietário do veículo", + ['actions:checkVehicleOwner:owner'] = "O veículo é propriedade de ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Proprietário do veículo não encontrado", + ['actions:checkVehicleOwner:car_not_found'] = "Nenhum veiculo perto", + ['actions:no_player_found'] = "Ninguem por perto", + ['actions:checkIdentity:player_found'] = "Nome de cidadão encontrado: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Alguem~s~ verificou a sua identidade", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Licensas", + ['actions:no_license_found'] = "Licensa nao encontrada", + ['actions:check_licenses'] = "Check licenses", + ['actions:driving_license'] = "Carta de condução", + ['actions:weapon_license'] = "Porte de armas", + ['actions:license:give_remove'] = "Remover licenses", + ['actions:gave_license'] = "Tu ~g~des-te~s~ ~y~%s~s~", + ['actions:removed_license'] = "Ty ~r~removes-te~s~ ~y~%s~s~", + ['actions:heal_small'] = "Tratar pequenas feridas", + ['actions:heal_big'] = "Tratar ferimentos graves", + ['actions:you_need_bandage'] = "Tu precisas de ~r~bandagem~s~", + ['actions:revive'] = "Reviver", + ['actions:you_need_medikit'] = "Tu precisas do ~r~kitmedico~s~", + + -- [[ Stash stuff ]] + ["open_stash"] = "Pressiona ~INPUT_CONTEXT~ para abrir o armario", + ["deposited"] = "Tu depositas-te ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "Insuficiente ~y~%s~s~", + ["no_space"] = "Nao tens espaço", + ["took"] = "Tu tiras-te ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Impossível obter x%d %s", + ["empty_inventory"] = "O teu inventario está vazio", + ["empty_stash"] = "O armario esta vazio", + ['stash'] = "Armario", + ['stash_take'] = "Armario - Retirar", + ['stash_deposit'] = "Armario - Depositar", + ['quantity'] = "Quantidade", + ['invalid_quantity'] = "Quantidade invalida", + ['deposit'] = "Depositar", + ['take'] = "Retirar", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Pressiona ~INPUT_CONTEXT~ para abrir o guarda-roupa", + ['player_clothes'] = "Tuas roupas", + ['remove_cloth'] = "Apagar roupas", + ['save_cloth'] = "Salvar roupa", + ['you_saved_outfit'] = "Roupa salva", + ['delete_outfit'] = "Roupa apagada", + ['clothes'] = "Roupas", + ['outfit_label_empty'] = "O nome da roupa nao pode ser estar em branco", + ['outfit_name'] = "Nome da roupa", + ["wardrobe:empty"] = "O guarda-roupa está vazio", + ["wardrobe:delete"] = "%s - Apagar", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Pressiona ~INPUT_CONTEXT~ para abrir o menu de chefe", + ["not_boss"] = "Tu nao es o chefe", + ["boss_menu"] = "Menu Chefe", + ["boss:society_money"] = "Dinheiro da sociedade: €%s", + ["boss:withdraw"] = "Retirar dinheiro da sociedade", + ["boss:deposit"] = "Depositar dinheiro da sociedade", + ["boss:wash_money"] = "Lavar dinheiro", + ["boss:grades"] = "Gerenciar salarios", + ["boss:employees"] = "Gerenciar empregados", + ["boss:withdraw_amount"] = "Retirar quantidade", + ["boss:deposit_amount"] = "Depositar quantidade", + ["boss:you_dont_have_enough_money"] = "Tu nao tens dinheiro suficiente", + ["boss:invalid_amount"] = "Quantidade invalida", + ["boss:withdrew_money"] = "Tu retiras-te ~g~€%s~s~", + ["boss:deposited_money"] = "Tu depositas-te ~g~€%s~s~", + ["boss:rank_salary"] = "%s - €%s", + ["boss:new_salary"] = "Novo salário", + ["boss:grade_salary_updated"] = "~y~Salario~s~ ~g~atualizado~s~", + ["boss:grade_salary_not_updated"] = "~r~impossivel atualizar~s~ ~y~salario~s~", + ["boss:employees_list"] = "Lista Empregados", + ["boss:recruit"] = "recrutar", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Despedir", + ["boss:change_grade"] = "Mudar posto", + ["boss:are_you_sure"] = "Tem a certeza?", + ["boss:cancel"] = "Cancelar", + ["boss:employee_fired"] = "Empregado ~r~despedido~s~", + ["boss:you_got_hired"] = "Foste ~g~contratado~s~ em ~b~%s~s~", + ["boss:you_hired"] = "Tu ~g~contratas-te~s~ %s", + ["boss:nobody_close"] = "Ninguem perto", + ["boss:grade"] = "%d. %s - Salario €%s", + ["boss:changed_grade_successfully"] = "Posto alterada com sucesso", + ["boss:your_grade_changed_to"] = "O teu posto mudou para ~b~%s~s~", + ["boss:how_much_to_wash"] = "Quanto dinheiro queres lavar?", + ["boss:you_washed_money"] = "Tu lavas-te ~r~€%s~s~ e recebes-te ~g~€%s~s~", + ["boss:not_enough_dirty_money"] = "Tu nao tens dinheiro ~r~sujo suficiente~s~", + ["boss:couldnt_wash_money"] = "Impossivel lavar dinheiro", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Pressiona ~INPUT_CONTEXT~ para abrir a garagem", + ["garage"] = "Garagem", + ["take_vehicle"] = "Retirar veiculo", + ["park_vehicle"] = "Estacionar veiculo", + ["no_vehicle"] = "Não há veículos nesta garagem", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Pressiona ~INPUT_CONTEXT~ para abrir a loja", + ["job_shop"] = "Loja de trabalho", + ['shop:item'] = "%s - €%d", + ['not_enough_money'] = "Tu nao tem dinheiro suficiente", + ['you_bought'] = "Tu compras-te ~b~x%d~s~ ~y~%s~s~ por ~%s~€%s~s~", + ['shop_empty'] = "A loja esta vazia", + ['shop:you_already_have_that_weapon'] = "Tu ja tens ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Comprar veiculo", + ['buyable_vehicle'] = "%s - €%s", + ['bought_vehicle'] = "Tu ~g~compras-te~s~ um veiculo", + ['are_you_sure'] = "Tens a certesa de comprar %s por €%s?", + ['no_vehicles_in_garage'] = "Não há veículos nesta garagem", + ['vehicle_outside'] = "O veículo não está na garagem", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Não há veículos para comprar", + + -- [[ Garage Owned stuff ]] + ['garage_owned:press_to_open'] = "Pressiona ~INPUT_CONTEXT~ para abrir a garagem", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Pressiona ~INPUT_CONTEXT~ para abrir a mensa de craft", + ['crafting_table'] = "Mensa de Craft", + ['dont_have_ingredients'] = "Tu nao tens todos os ~r~items~s~ requeridos", + ['crafting'] = "Fabricando %s", + ['you_crafted'] = "Tu fabricas-te ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Tu ja tens ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['press_to_stop'] = "Pressiona ~INPUT_CONTEXT~ para parar", + ['you_stopped'] = "Você vai parar quando a elaboração terminar", + ['crafting_table:nothing_to_craft'] = "Nada para fabricar", + + -- [[ Armory stuff ]] + ['open_armory'] = "Pressina ~INPUT_CONTEXT~ para abrir o arsenal", + ['not_have_any_weapon'] = "Tu nao tens nenhuma arma", + ['armory'] = "Arsenal", + ['armory_take'] = "Arsenal - Retirar", + ['armory_deposit'] = "Arsenal - Depositar", + ['take_weapon'] = "Retirar arma", + ['deposit_weapon'] = "Depositar arma", + ['you_dont_have_weapon'] = "Tu ~r~nao~s~ tens essa arma", + ['no_weapons_in_armory'] = "Não há armas aqui", + ['you_deposited_weapon'] = "Tu ~g~depositas-te~s~ %s", + ['you_took_weapon'] = "Tu ~r~retiras-te~s~ %s", + ['you_already_have_that_weapon'] = "tu ja tens ~g~%s~s~", + ['weapon_ammo'] = "Munições", + ['weapon'] = "%s - x%d balas", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Pressiona ~INPUT_CONTEXT~ para abrir as roupas do trabalho", + ['job_outfit'] = "Roupa de trabalho", + ['no_outfits'] = "Sem roupas disponíveis", + ['civilian_outfit'] = "Roupa civil", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Pressiona ~INPUT_CONTEXT~ para ir", + ['teleport_to'] = "Pressiona ~INPUT_CONTEXT~ para ir %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Pressiona ~INPUT_CONTEXT~ para abrir o cofre", + ['account'] = "%s - €%s", + ['safe'] = "Cofre", + ['empty_safe'] = "O cofre está vazio", + ['nothing_to_deposit'] = "Nao tens nada para depositar", + ['withdrawn_safe'] = "Tu retiras-te %s€%s %s~s~", + ['deposited_safe'] = "Tu depositas-te %s€%s %s~s~", + ['cash'] = "Dinheiro", + ['withdraw'] = "Retirar", + + -- [[ Market Stuff ]] + ['open_market'] = "Pressiona ~INPUT_CONTEXT~ para abrir o mercado", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Mercado", + ['not_enough_item'] = "Tu nao tens suficiente %s", + ['you_sold'] = "Tu vendes-te ~b~x%d~s~ ~y~%s~s~ por %s€%s", + ['nothing_can_be_sold_yet'] = "Nada pode ser vendido aqui ainda", + ['market:how_many_to_sell'] = "Quanto que quer vender?", + ['market:you_are_already_selling'] = "Tu ja estas a vender", + ['market:selling'] = "Vendendo x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Pressiona ~INPUT_CONTEXT~ para colher", + ['harvest:harvesting'] = "Colhendo %s", + ['harvest:press_to_stop'] = "Pressiona ~INPUT_CONTEXT~ para parar", + ['harvest:you_will_stop_on_finish'] = "Vais parar no final", + ['harvest:you_need_tool_count'] = "Tu precisas ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Tu precisas ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Press ~INPUT_CONTEXT~ to open weapon upgrader", + ['weapon_upgrader'] = "Weapon Upgrader", + ['owned_component'] = "%s - Owned", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Default", + ['tint_green'] = "Green", + ['tint_gold'] = "Gold", + ['tint_pink'] = "Pink", + ['tint_army'] = "Army", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Orange", + ['tint_platinum'] = "Platinum", + ['components'] = "Components", + ['tints'] = "Tints", + ['already_have_tint'] = "You already have this tint", + ['bought_tint'] = "You bought ~y~%s~s~ tint for ~g~%s~s~", + ['bought_component'] = "You bought ~y~%s~s~ for ~g~%s~s~", + ['removed_component'] = "You removed ~y~%s~s~ from ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Pressiona ~INPUT_CONTEXT~ para entrar ~g~ao serviço~s~", + ['go_off_duty'] = "Pressiona ~INPUT_CONTEXT~ para sair ~r~do serviço~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Pressiona ~INPUT_CONTEXT~ para abrir a loja", + ['job_owned_shop'] = "Trabalho da loja", + ['shop'] = "Loja", + ['put_on_sale'] = "Meter a venda", + ['remove_from_sale'] = "Remover da venda", + ['item_price'] = "preço do item", + ['invalid_price'] = "preço invalido", + ['job_shop_item'] = "%s - x%d - €%s", + ['job_shop_empty'] = "a loja esta vazia", + ['job_shop_quantity'] = "Quantidade - x%d -> $%s", + ['job_shop_cant_afford'] = "Tu ~r~nao podes pagar~s~ isto", + ['job_shop:bought_item'] = "tu ~g~compras-te~s~ x%d ~y~%s~s~ por ~g~€%s~s~", + ['job_shop:add_supplies'] = "Adicionar suprimentos", + ['job_shop:what_to_put_on_sale'] = "O que gostarias de por a venda?", + ['job_shop:what_to_remove_from_sale'] = "O que gostaria de remover da venda?", + ['job_shop:what_to_restock'] = "O que você gostaria de reabastecer?", + ['job_shop:how_many_to_restock'] = "Quanto quer adicionar ao estoque?", + ['job_shop:added_to_supplies'] = "Adicionado ~b~x%d~s~ ~y~%s~s~ aos suprimentos", + ['job_shop:you_put_on_sale'] = "Tu puses-te a venda ~b~x%d~s~ ~y~%s~s~ por ~g~€%s~s~", + ['job_shop:you_removed_from_sale'] = "Tu removes-te da veda ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Tu ja tens ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Nao tens nada para vender", + + -- [[ Process stuff ]] + ['process:press_to_process'] = "Pressiona ~INPUT_CONTEXT~ para processar", + ['process:you_need'] = "Tu precisas ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Processando %s", + ['process:press_to_stop'] = "Pressiona ~INPUT_CONTEXT~ para parar", + ['process:you_will_stop_on_finish'] = "Vais parar ao terminar", + ['process:no_space'] = "Nao podes carregar ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Nickname: %s\nIdentifier: %s\n\n%s", + + ['log_deposited_stash'] = "Deposited item", + ['log_deposited_stash_description'] = "Deposited x**%d** **%s** (**%s**) in marker ID **%d**", + + ['log_took_stash'] = "Took item", + ['log_took_stash_description'] = "Took x**%d** **%s** (**%s**) from marker ID **%d**", + + ['log_deposited_weapon'] = "Deposited weapon", + ['log_deposited_weapon_description'] = "Deposited **%s** (**%s**) with x**%d** ammo in marker ID **%d**", + + ['log_took_weapon'] = "Took weapon", + ['log_took_weapon_description'] = "Took **%s** (**%s**) with x**%d** ammo in marker ID **%d**", + + ['log_deposited_money'] = "Deposited money", + ['log_deposited_money_description'] = "Deposited $**%d** in society '**%s**'", + + ['log_withdrew_money'] = "Withdrew money", + ['log_withdrew_money_description'] = "Withdrew $**%d** from society '**%s**'", + + ['log_updated_salary'] = "Updated salary", + ['log_updated_salary_description'] = "Updated salary of grade **%d** to **$%s**", + + ['log_fired_employee'] = "Employee fired", + ['log_fired_employee_description'] = "Fired player with identifier **%s**", + + ['log_recruited_employee'] = "Recruited employee", + ['log_recruited_employee_description'] = "Recruited **%s** whose identifier is **%s**", + + ['log_changed_grade_employee'] = "Changed grade to employee", + ['log_changed_grade_employee_description'] = "Changed grade to employee **%s** to **%d**", + + ['log_washed_money'] = "Washed money", + ['log_washed_money_description'] = "Washed $**%s**", + + ['log_sold_item'] = "Sold item", + ['log_sold_item_description'] = "Sold **x%d** **%s** for **$%s**", + + ['log_bought_item'] = "Bought item", + ['log_bought_item_description'] = "Bought x%d **%s** (**%s**) from marker ID **%d**", + + ['log_not_existing_item'] = "Not existing item", + ['log_not_existing_item_description'] = "Tried to buy '**%s**' from marker ID **%d**, but the item it's not in the shop", + + ['log_bought_vehicle'] = "Bought vehicle", + ['log_bought_vehicle_description'] = "Bought '**%s**' for $**%d** from marker ID **%d**", + + ['log_not_existing_vehicle'] = "Not existing vehicle", + ['log_not_existing_vehicle_description'] = "Tried to buy '**%s**' from marker ID **%d**, but the vehicle it's not in the garage", + + ['log_crafted_item'] = "Crafted item", + ['log_crafted_item_description'] = "Crafted **x%d** **%s** (**%s**) in marker ID **%d**", + + ['log_deposited_safe'] = "Deposit in safe", + ['log_deposited_safe_description'] = "Deposited $**%s** **%s** in marker ID **%d**", + + ['log_withdrew_safe'] = "Withdrew from safe", + ['log_withdrew_safe_description'] = "Withdrew $**%s** **%s** from marker ID **%d**", + + ['log_harvested'] = "Harvested", + ['log_harvested_description'] = "Harvested x**%d** **%s** from marker ID **%d**", + + ['log_bought_tint'] = "Bought tint", + ['log_bought_tint_description'] = "Bought the **%s** '**%s**' tint for $**%d** from marker ID **%d**", + + ['log_removed_component'] = "Removed component", + ['log_removed_component_description'] = "Removed **%s** from **%s** from marker ID **%d**", + + ['log_bought_component'] = "Bought component", + ['log_bought_component_description'] = "Bought **%s** for **%s** from marker ID **%d**", + + ['log_not_allowed_marker'] = "Not allowed marker use", + ['log_not_allowed_marker_description'] = "Tried to use marker ID %d but he's not allowed", + + ['logs:process:title'] = "Processed", + ['logs:process:description'] = "Processed **x%d** **%s** to **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Put on sale", + ['logs:job_shop:put_on_sale:description'] = "Put on sale **x%d** **%s** for **$%s** in marker ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Removed from sale", + ['logs:job_shop:remove_from_sale:description'] = "Removed **x%d** **%s** for **$%s** from marker ID **%d**", + + ['logs:job_shop:bought_item'] = "Bought item", + ['logs:job_shop:bought_item:description'] = "Bought **x%d** **%s** for **$%s** in marker ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Added to supplies", + ['logs:job_shop:add_to_supplies:description'] = "Added **x%d** **%s** for **$%s** to supplies in marker ID **%d**", +} diff --git a/resources/[creators]/jobs_creator/locales/sk.lua b/resources/[creators]/jobs_creator/locales/sk.lua new file mode 100644 index 0000000..5845b2a --- /dev/null +++ b/resources/[creators]/jobs_creator/locales/sk.lua @@ -0,0 +1,391 @@ +locales['sk'] = { + -- [[ Generic ]] + ["interact"] = "Klikni ~INPUT_CONTEXT~ pre akciu", + ["billing_reason"] = "Faktura popis", + ["billing_amount"] = "Faktura suma", + ["no_players_nearby"] = "Ziaden hrac na blizku", + ["no_vehicles_nearby"] = "Ziadne vozidlo na blizku", + ["invoice_sent"] = "~g~$%s~s~ Faktura bola odoslana", + ["too_far"] = "Prilis daleko", + ["yes"] = "Ano", + ["no"] = "Nie", + ["you_need_minimum_account_money"] = "Minimalna suma $~y~%d~s~ je ~b~%s~s~", + ["bill"] = "Faktura", + ["bill_received"] = "Obdrzal si fakturu
    Suma: $%s
    Dovod: %s

    Klikni pre potvrdenie fakktury", + ["bill_paid"] = "Zaplatil si fakturu za $%s", + + -- [[ Actions menu ]] + ['open_actions_menu'] = "Ovorit akcne mmenu", + ['actions_menu'] = "Job menu", + ['actions_billing'] = "Faktury", + ['actions_search'] = "Prehladat", + ['actions_put_handcuffs'] = "Sputat", + ['actions_start_dragging'] = "Presunut", + ['actions_put_in_car'] = "Vlozit do auta", + ['actions_take_from_car'] = "Vybrat z auta", + ['actions_menu_search'] = "Prehladavanie", + ['actions_lockpick_car'] = "Vypacit vozidlo", + ['no_car_found'] = "Vozidlo sa nenaslo", + ['not_locked_vehicle'] = "Toto vozidlo nieje zamknute", + ['you_need_lockpick'] = "Potrebujes ~r~lockpick~s~", + ['lockpick_used'] = "Pouzil si ~r~lockpick~s~", + ['actions:lockpick:lockpickingVehicle'] = "Vypacovanie zamku", + ['actions_menu_search_took'] = "zobral ~g~si~s~ ~y~x%d %s~s~", + ['actions_menu_search_stolen'] = "~y~x%d %s~s~ bol ~r~okradnuty~s~ ", + ['actions_menu_search_took_money'] = "Ziskal ~g~si~s~ ~y~$%s %s~s~", + ['actions_menu_search_stolen_money'] = "~y~$%s %s~s~ bol ~r~okradnuty~s~ ", + ['actions_menu_search_doesnt_have_weapon'] = "Hrac ~r~nema~s~ ziadne zbrane", + ['actions_menu_search_took_weapon'] = "Vzal ~g~si~s~ ~y~%s~s~ aj ~y~%d naboje~s~", + ['actions_menu_search_stolen_weapon'] = "~y~%s~s~ s ~y~%d nabojmi~s~ was ~r~okradnuty~s~ ", + ['you_need_handcuffs'] = "Potrebujes ~r~puta~s~", + ['not_handcuffed'] = "Hrac nieje ~r~sputany~s~", + ['cant_while_dragging'] = "Pocas presunu to nemozes urobit", + ['search_inventory_empty'] = "Inventar prazdny", + ['actions_menu_being_searched'] = "Prehladavanie . . .", + ['actions:wash_vehicle'] = "Umyt vozidlo", + ['actions:washing_vehicle'] = "Umyvanie vozidla", + ['actions:repair_vehicle'] = "Oprava vozidla", + ['actions:repairing_vehicle'] = "Opravuje vozidlo", + ['actions:no_vehicles_close'] = "Vozidlo je daleko", + ['actions:impound_vehicle'] = "Odtiahnut vozidlo", + ['actions:impounding_vehicle'] = "Odtahuje vozidlo", + ['actions:you_need'] = "Potrebujes ~y~%s~s~", + ['actions:check_identity'] = "Skontroluj doklady", + ['actions:check_vehicle_owner'] = "Skotrolovat majitela vozidla", + ['actions:checkVehicleOwner:owner'] = "Vlastnik vozidla ~y~%s~s~", + ['actions:checkVehicleOwner:owner_not_found'] = "Majitel sa nenasiel", + ['actions:checkVehicleOwner:car_not_found'] = "Vozidlo je prilis daleko", + ['actions:no_player_found'] = "Nikto na blizku", + ['actions:checkIdentity:player_found'] = "najdeny obcan: ~y~%s~s~", + ['actions:checkIdentity:somebody_checked_your_id'] = "~y~Kontrola~s~ tvojej ID karty", + ['actions:license'] = "[+] %s", + ['actions:licenses'] = "Licencie", + ['actions:no_license_found'] = "Licencia nenajdena", + ['actions:check_licenses'] = "Pozriet licencie", + ['actions:driving_license'] = "Vodicsky preukaz", + ['actions:weapon_license'] = "Zbrojny preukaz", + ['actions:license:give_remove'] = "Odobrat licenses", + ['actions:gave_license'] = "Dal ~g~si~s~ ~y~%s~s~", + ['actions:removed_license'] = "Odstranil ~r~si~s~ ~y~%s~s~", + ['actions:heal_small'] = "Vyliecit male rany", + ['actions:heal_big'] = "Vyliecit velke rany", + ['actions:you_need_bandage'] = "Potrebujes ~r~bandaze~s~", + ['actions:revive'] = "Ozivit hraca", + ['actions:revive:not_dead'] = "Osoba nieje mrtva", + ['actions:you_need_medikit'] = "Potrebujes ~r~lekarnicku alebo medkit~s~", + + -- [[ Stash stuff ]] + ["open_stash"] = "Klikni ~INPUT_CONTEXT~ pre akciu", + ["deposited"] = "Vlozil si ~b~x%d~s~ ~y~%s~s~", + ["not_enough"] = "nedostatok miesta ~y~%s~s~", + ["no_space"] = "Nemate uz miesto", + ["took"] = "Zobral si zo skladu ~b~x%d~s~ ~y~%s~s~", + ["impossible_take"] = "Nemozes vybrat x%d %s", + ["empty_inventory"] = "Tvoj inventar je prazdny", + ["empty_stash"] = "Sklad je prazdny", + ['stash'] = "Sklad", + ['stash_take'] = "Vybrat", + ['stash_deposit'] = "Vlozitt", + ['quantity'] = "Mnozstvo", + ['invalid_quantity'] = "Neplatne mnozstvo", + ['deposit'] = "Vlozit", + ['take'] = "Vybrat", + + -- [[ Wardrobe stuff ]] + ["open_wardrobe"] = "Klikni ~INPUT_CONTEXT~ pre satnu", + ['player_clothes'] = "Tvoje outfity", + ['remove_cloth'] = "Vymazat outfit", + ['save_cloth'] = "Ulozit outfit", + ['you_saved_outfit'] = "Outfit ulozeny", + ['delete_outfit'] = "Outfit vymazany", + ['clothes'] = "Oblecenie", + ['outfit_label_empty'] = "Musis zadat meno outfitu", + ['outfit_name'] = "Meno outfitu", + ["wardrobe:empty"] = "Satna je prazdna", + ["wardrobe:delete"] = "%s - Vymazat", + + -- [[ Boss Stuff ]] + ["open_boss"] = "Klikni ~INPUT_CONTEXT~ pre otvorenie boss menu", + ["not_boss"] = "Niesi boss", + ["boss_menu"] = "Boss menu", + ["boss:society_money"] = "Frakcia peniaze: $%s", + ["boss:withdraw"] = "Vybrat peniaze", + ["boss:deposit"] = "Vlozit peniaze", + ["boss:wash_money"] = "Vyprat peniaze", + ["boss:grades"] = "Spravovat platy zamestnancov", + ["boss:employees"] = "Spravovat zamestnancov", + ["boss:withdraw_amount"] = "Vybrat sumu", + ["boss:deposit_amount"] = "Vlozit sumu", + ["boss:you_dont_have_enough_money"] = "Nemas peniaze", + ["boss:invalid_amount"] = "Neplatna suma", + ["boss:withdrew_money"] = "Vybral si ~g~$%s~s~", + ["boss:deposited_money"] = "Vlozil si ~g~$%s~s~", + ["boss:rank_salary"] = "%s - $%s", + ["boss:new_salary"] = "Plat uprava", + ["boss:grade_salary_updated"] = "~y~Plat bol~s~ ~g~upraveny~s~", + ["boss:grade_salary_not_updated"] = "~r~Nepodarilo sa~s~ ~y~upravit vyplaty~s~", + ["boss:employees_list"] = "Zoznam zamestnancov", + ["boss:recruit"] = "Prijat noveho zamestnanca", + ["boss:employee"] = "%s %s - %s", + ["boss:fire"] = "Vyhodit", + ["boss:change_grade"] = "Zmenit poziciu", + ["boss:are_you_sure"] = "Si si isty?", + ["boss:cancel"] = "Zrusit", + ["boss:employee_fired"] = "Zamestnanec ~r~prepusteny~s~", + ["boss:you_got_hired"] = "Zamestnat ~g~noveho~s~ uchadzaca ~b~%s~s~", + ["boss:you_hired"] = "Zamestnal ~g~si~s~ %s", + ["boss:nobody_close"] = "Nikto na blizku", + ["boss:grade"] = "%d. %s - Platy $%s", + ["boss:changed_grade_successfully"] = "Zmena pozicie uspesna", + ["boss:your_grade_changed_to"] = "Tvoja pozicia bola zmenena ~b~%s~s~", + ["boss:how_much_to_wash"] = "Kolko penazi chcete vyprat?", + ["boss:you_washed_money"] = "Vypral si ~r~$%s~s~ a obdrzal ~g~$%s~s~", + ["boss:not_enough_dirty_money"] = "Nemas ~r~spinave peniaze~s~", + ["boss:couldnt_wash_money"] = "Nepodarilo sa vyprat peniaze", + + -- [[ Garage Stuff ]] + ["open_garage"] = "Klikni ~INPUT_CONTEXT~ pre akciu", + ["garage"] = "Garaz", + ["take_vehicle"] = "Vybrat vozilo", + ["park_vehicle"] = "Zaprakovat vozidlo", + ["no_vehicle"] = "V tejto garazi nie su zoadne vozidla", + + -- [[ Shop Stuff ]] + ["open_shop"] = "Klikni ~INPUT_CONTEXT~ pre ponuku obchodu", + ["job_shop"] = "Obchod", + ['shop:item'] = "%s - $%d", + ['not_enough_money'] = "Nemas peniaze", + ['you_bought'] = "Kupil si ~b~x%d~s~ ~y~%s~s~ za ~%s~$%s~s~", + ['shop_empty'] = "Tento obchod je prazdny", + ['shop:you_already_have_that_weapon'] = "Uz mate ~y~%s~s~", + + -- [[ Garage Buyable stuff ]] + ['buy_vehicle'] = "Kupit vozidlo", + ['buyable_vehicle'] = "%s - $%s", + ['bought_vehicle'] = "Uspesne ~g~kupene~s~ vozidlo", + ['are_you_sure'] = "Chces kupit %s za $%s?", + ['no_vehicles_in_garage'] = "V tejto garazi nie su zoadne vozidla", + ['vehicle_outside'] = "Vozidlo sa nenachadza v garazi", + ['buyable_vehicle:outside'] = "%s", + ['permanent_garage:no_vehicle_to_buy'] = "Ziadne vozidla na zakupenie", + + -- [[ Garage Owned stuff ]] + ['garage_owned:Klikni_to_open'] = "Klikni ~INPUT_CONTEXT~ pre otvorenie garaze", + + -- [[ Crafting Table Stuff ]] + ['open_crafting_table'] = "Klikni ~INPUT_CONTEXT~ pre craftenie", + ['crafting_table'] = "Pracovny stol", + ['dont_have_ingredients'] = "Nemate vsetky potrebne ~r~required~s~ itemy", + ['crafting'] = "Vyrabanie %s", + ['you_crafted'] = "Vyrobil si ~b~x%d~s~ ~g~%s~s~", + ['already_have'] = "Uz mate ~g~%s~s~", + ['ingredient'] = "%s - %d/%d", + ['craft_item_label'] = "%s", + ['Klikni_to_stop'] = "Klikni ~INPUT_CONTEXT~ pre zastavenie", + ['you_stopped'] = "Bude ukoncene po vyrobeni", + ['crafting_table:nothing_to_craft'] = "Nic na vyrobenie", + ["craft_amount"] = "Pocet", + + -- [[ Armory stuff ]] + ['open_armory'] = "Klikni ~INPUT_CONTEXT~ pre zbrane ", + ['not_have_any_weapon'] = "Nemate ziadnu zbran", + ['armory'] = "Zbrojnica", + ['armory_take'] = "Zbrojnica - Vybrat", + ['armory_deposit'] = "Zbrojnica - Vlozit", + ['take_weapon'] = "Zobrat zbran", + ['deposit_weapon'] = "Vlozit zbran", + ['you_dont_have_weapon'] = "Nemas ~r~ziadnu~s~ zbran", + ['no_weapons_in_armory'] = "Nie su tu ziadne zbrane", + ['you_deposited_weapon'] = "Vlozil ~g~si~s~ %s", + ['you_took_weapon'] = "Vybral ~r~si~s~ %s", + ['you_already_have_that_weapon'] = "Uz mate ~g~%s~s~", + ['weapon_ammo'] = "Naboje", + ['weapon'] = "%s - x%d nabojov", + + -- [[ Job outfit stuff ]] + ['open_job_outfit'] = "Klikni ~INPUT_CONTEXT~ pre otvorenie satne", + ['job_outfit'] = "Pracovne oblecenie", + ['no_outfits'] = "Oblecenie nedostupne", + ['civilian_outfit'] = "Civilne oblecenie", + + -- [[ Teleport Stuff ]] + ['teleport'] = "Klikni ~INPUT_CONTEXT~ pre teleport", + ['teleport_to'] = "Klikni ~INPUT_CONTEXT~ a chod %s", + + -- [[ Safe Stuff ]] + ['open_safe'] = "Klikni ~INPUT_CONTEXT~ pre otvorenie trezoru", + ['account'] = "%s - $%s", + ['safe'] = "Trezor", + ['empty_safe'] = "Trezor je prazdny", + ['nothing_to_deposit'] = "Nemate pri sebe nic co by ste vlozili do trezora", + ['withdrawn_safe'] = "Vybral si %s$%s %s~s~", + ['deposited_safe'] = "Vlozil si %s$%s %s~s~", + ['cash'] = "Peniaze", + ['withdraw'] = "Withdraw", + + -- [[ Market Stuff ]] + ['open_market'] = "Klikni ~INPUT_CONTEXT~ pre akciu", + ['market_item'] = "%s - $%s - $%s", + ['market'] = "Obchod", + ['not_enough_item'] = "Nemas pozadovany item %s", + ['you_sold'] = "Predal si ~b~x%d~s~ ~y~%s~s~ for %s$%s", + ['nothing_can_be_sold_yet'] = "Momentalne nic na predaj", + ['market:how_many_to_sell'] = "Kolko chces predat?", + ['market:you_are_already_selling'] = "Uz predavas", + ['market:selling'] = "Pradava x%d - %s", + + -- [[ Harvest Stuff ]] + ['harvest'] = "Klikni ~INPUT_CONTEXT~ pre akciu", + ['harvest:harvesting'] = "Zber %s", + ['harvest:Klikni_to_stop'] = "Klikni ~INPUT_CONTEXT~ pre ukoncenie", + ['harvest:you_will_stop_on_finish'] = "Bude ukonceny po dokonceni zberu", + ['harvest:you_need_tool_count'] = "Potrebujete ~b~x%d~s~ ~y~%s~s~", + ['harvest:you_need_tool'] = "Potrebujes ~y~%s~s~", + + -- [[ Weapon upgrader ]] + ['open_weapon_upgrader'] = "Klikni ~INPUT_CONTEXT~ pre upgrade zbrani", + ['weapon_upgrader'] = "Zbrane Vylepsenie", + ['owned_component'] = "%s - Vlastnene", + ['buy_component'] = "%s - $%s", + ['tint_default'] = "Zakladna", + ['tint_green'] = "Zelena", + ['tint_gold'] = "Zlata", + ['tint_pink'] = "Ruzova", + ['tint_army'] = "Armadna", + ['tint_lspd'] = "LSPD", + ['tint_orange'] = "Oranzova", + ['tint_platinum'] = "Platinum", + ['components'] = "Komponenty", + ['tints'] = "Odtiene", + ['already_have_tint'] = "Uz mate tento odtien", + ['bought_tint'] = "Obdrzal ~y~%s~s~ si odtien za ~g~%s~s~", + ['bought_component'] = "Obdrzal ~y~%s~s~ za ~g~%s~s~", + ['removed_component'] = "Odstranil si ~y~%s~s~ z ~g~%s~s~", + + -- [[ Duty Stuff]] + ['go_on_duty'] = "Klikni ~INPUT_CONTEXT~ pre ~g~on duty~s~", + ['go_off_duty'] = "Klikni ~INPUT_CONTEXT~ pre ~r~off duty~s~", + + -- [[ Job Shop Stuff ]] + ['open_job_shop'] = "Klikni ~INPUT_CONTEXT~ otvorenie obchodu", + ['job_owned_shop'] = "Job Obchod", + ['shop'] = "Obchod", + ['put_on_sale'] = "Dat do predaja", + ['remove_from_sale'] = "Odstranit z predaja", + ['item_price'] = "Item cena", + ['invalid_price'] = "Neplatna cena", + ['job_shop_item'] = "%s - x%d - $%s", + ['job_shop_empty'] = "Obchod je prazdny", + ['job_shop_quantity'] = "Mnozstvo - x%d -> $%s", + ['job_shop_cant_afford'] = "Toto ~r~si nemozes~s~ dovolit", + ['job_shop:bought_item'] = "Obdrzal ~g~si~s~ x%d ~y~%s~s~ za ~g~$%s~s~", + ['job_shop:add_supplies'] = "Pridat zasoby", + ['job_shop:what_to_put_on_sale'] = "Co by ste chceli dat do predaja?", + ['job_shop:what_to_remove_from_sale'] = "Co by ste chceli odstranit z predaja?", + ['job_shop:what_to_restock'] = "Co chcete doplnit?", + ['job_shop:how_many_to_restock'] = "Ake mnozstvo pridat?", + ['job_shop:added_to_supplies'] = "Pridane ~b~x%d~s~ ~y~%s~s~ do zásob", + ['job_shop:you_put_on_sale'] = "Dane do predaja ~b~x%d~s~ ~y~%s~s~ za ~g~$%s~s~", + ['job_shop:you_removed_from_sale'] = "Odstranene z predaja ~b~x%d~s~ ~y~%s~s~", + ['job_shop:item'] = "x%d - %s", + ['job_shop:you_already_have_that_weapon'] = "Uz mate ~y~%s~s~", + ['job_shop:nothing_to_sell'] = "Nemas co predavat", + + -- [[ Process stuff ]] + ['process:Klikni_to_process'] = "Klikni ~INPUT_CONTEXT~ pre spracovanie", + ['process:you_need'] = "Potrebujes ~b~x%d~s~ ~y~%s~s~", + ['process:processing'] = "Spracovanie %s", + ['process:Klikni_to_stop'] = "Klikni ~INPUT_CONTEXT~ pre ukoncenie", + ['process:you_will_stop_on_finish'] = "Bude za chvilku ukoncene", + ['process:no_space'] = "Nemozete niest ~b~x%d~s~ ~y~%s~s~", + + -- [[ Logs stuff ]] + ['log:generic'] = "Nickname: %s\nIdentifier: %s\n\n%s", + + ['log_deposited_stash'] = "Vlozeny item", + ['log_deposited_stash_description'] = "Vlozene x**%d** **%s** (**%s**) v marker ID **%d**", + + ['log_took_stash'] = "Vybral item", + ['log_took_stash_description'] = "Vybral x**%d** **%s** (**%s**) marker ID **%d**", + + ['log_deposited_weapon'] = "Vlozene zbrane", + ['log_deposited_weapon_description'] = "Vlozene **%s** (**%s**) with x**%d** zbrane **%d**", + + ['log_took_weapon'] = "Vybrane zbrane", + ['log_took_weapon_description'] = "Vybral **%s** (**%s**) with x**%d** marker ID **%d**", + + ['log_deposited_money'] = "Vlozene peniaze", + ['log_deposited_money_description'] = "Vlozene $**%d** do spolocnosti '**%s**'", + + ['log_withdrew_money'] = "Vybrane peniaze", + ['log_withdrew_money_description'] = "Vybrazne $**%d** z spolocnosti '**%s**'", + + ['log_updated_salary'] = "Zmeneny plat", + ['log_updated_salary_description'] = "Plat bol upraveny u **%d** na **$%s**", + + ['log_fired_employee'] = "Zamestnanec prepustneny", + ['log_fired_employee_description'] = "Prepusteny hrac **%s**", + + ['log_recruited_employee'] = "Prijaty zamestnanec", + ['log_recruited_employee_description'] = "Prijaty **%s** a jeho id **%s**", + + ['log_changed_grade_employee'] = "Zmenan pozicie zamestnanca", + ['log_changed_grade_employee_description'] = "Zmena zamestnania u **%s** na **%d**", + + ['log_washed_money'] = "Vyprate peniaze", + ['log_washed_money_description'] = "Vypral $**%s**", + + ['log_sold_item'] = "Predal item", + ['log_sold_item_description'] = "Predal **x%d** **%s** za **$%s**", + + ['log_bought_item'] = "Kupil item", + ['log_bought_item_description'] = "Kupil x%d **%s** (**%s**) z marker ID **%d**", + + ['log_not_existing_item'] = "Neexistujuci item", + ['log_not_existing_item_description'] = "Pokusil sa kupit '**%s**' from marker ID **%d**, ale item nieje v obchode", + + ['log_bought_vehicle'] = "Kupil vozidlo", + ['log_bought_vehicle_description'] = "Kupil '**%s**' za $**%d** z marker ID **%d**", + + ['log_not_existing_vehicle'] = "Neexistujuce vozidlo", + ['log_not_existing_vehicle_description'] = "Pokusil sa kupit '**%s**' z marker ID **%d**, ale vozidlo neije v garazi", + + ['log_crafted_item'] = "Vyrobeny item", + ['log_crafted_item_description'] = "Vyrobil **x%d** **%s** (**%s**) z marker ID **%d**", + + ['log_deposited_safe'] = "Vlozil do trezora", + ['log_deposited_safe_description'] = "Vybral $**%s** **%s** v marker ID **%d**", + + ['log_withdrew_safe'] = "Vybral z trezora", + ['log_withdrew_safe_description'] = "Vybral $**%s** **%s** z marker ID **%d**", + + ['log_harvested'] = "Zber", + ['log_harvested_description'] = "Pozbieral x**%d** **%s** z marker ID **%d**", + + ['log_bought_tint'] = "Kupil odtien", + ['log_bought_tint_description'] = "Kupil **%s** '**%s**' odtien za $**%d** z marker ID **%d**", + + ['log_removed_component'] = "Odstranil komponent", + ['log_removed_component_description'] = "Odstranil **%s** z **%s** z marker ID **%d**", + + ['log_bought_component'] = "Kupil komponent", + ['log_bought_component_description'] = "Kupil **%s** za **%s** z marker ID **%d**", + + ['log_not_allowed_marker'] = "Nepovoleny marker", + ['log_not_allowed_marker_description'] = "Pokusil sa pouzitt marker %d ale nie je povoleny", + + ['logs:process:title'] = "Vyroba", + ['logs:process:description'] = "Vyrobene **x%d** **%s** to **x%d** **%s**", + + ['logs:job_shop:put_on_sale'] = "Vlozil do predaja", + ['logs:job_shop:put_on_sale:description'] = "Dal do predaja **x%d** **%s** z **$%s** in marker ID **%d**", + + ['logs:job_shop:remove_from_sale'] = "Odstranil z predaja", + ['logs:job_shop:remove_from_sale:description'] = "Odstranil **x%d** **%s** z **$%s** z marker ID **%d**", + + ['logs:job_shop:bought_item'] = "Kupil item", + ['logs:job_shop:bought_item:description'] = "Kupil **x%d** **%s** for **$%s** z marker ID **%d**", + + ['logs:job_shop:add_to_supplies'] = "Pridane do zasob", + ['logs:job_shop:add_to_supplies:description'] = "Pridane **x%d** **%s** z **$%s** do zasob v marker ID **%d**", +} diff --git a/resources/[creators]/jobs_creator/server/actions.lua b/resources/[creators]/jobs_creator/server/actions.lua new file mode 100644 index 0000000..56abb29 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/actions.lua differ diff --git a/resources/[creators]/jobs_creator/server/code_integrator.lua b/resources/[creators]/jobs_creator/server/code_integrator.lua new file mode 100644 index 0000000..84135c3 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/code_integrator.lua differ diff --git a/resources/[creators]/jobs_creator/server/functions.lua b/resources/[creators]/jobs_creator/server/functions.lua new file mode 100644 index 0000000..29beba9 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/functions.lua differ diff --git a/resources/[creators]/jobs_creator/server/main.lua b/resources/[creators]/jobs_creator/server/main.lua new file mode 100644 index 0000000..8b44e24 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/main.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/armory.lua b/resources/[creators]/jobs_creator/server/markers/armory.lua new file mode 100644 index 0000000..ca02204 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/armory.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/boss.lua b/resources/[creators]/jobs_creator/server/markers/boss.lua new file mode 100644 index 0000000..bc80558 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/boss.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/crafting_table.lua b/resources/[creators]/jobs_creator/server/markers/crafting_table.lua new file mode 100644 index 0000000..45c4a1f Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/crafting_table.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/duty.lua b/resources/[creators]/jobs_creator/server/markers/duty.lua new file mode 100644 index 0000000..dae6bd9 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/duty.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/garage_owned.lua b/resources/[creators]/jobs_creator/server/markers/garage_owned.lua new file mode 100644 index 0000000..18410ea --- /dev/null +++ b/resources/[creators]/jobs_creator/server/markers/garage_owned.lua @@ -0,0 +1,112 @@ +local function parkAllVehicles() + if(not config.parkAllOwnedVehiclesOnRestart) then return end + + if(Framework.getFramework() == "ESX") then + MySQL.Async.execute("UPDATE owned_vehicles SET `stored` = 1 WHERE `stored` = 0") + elseif(Framework.getFramework() == "QB-core") then + MySQL.Async.execute("UPDATE player_vehicles SET `state` = 1 WHERE `state` = 0") + end +end +RegisterNetEvent(Utils.eventsPrefix .. ":framework:ready", parkAllVehicles) + +local function getPlayerOwnedVehicles(playerId, cb, markerId) + local identifier = Framework.getPlayerCharIdentifier(playerId) + + local spawnPoints = JobsCreator.Markers[markerId].data.spawnPoints + + if(Framework.getFramework() == "ESX") then + MySQL.Async.fetchAll("SELECT * FROM owned_vehicles WHERE `owner`=@identifier", { + ["@identifier"] = identifier + }, function(results) + cb(results, spawnPoints) + end) + elseif(Framework.getFramework() == "QB-core") then + MySQL.Async.fetchAll("SELECT * FROM player_vehicles WHERE citizenid=@citizenid", { + ["@citizenid"] = identifier + }, function(results) + cb(results, spawnPoints) + end) + end +end +RegisterServerCallback(Utils.eventsPrefix .. ":garage_owned:getVehicles", getPlayerOwnedVehicles) + +local function garageOwnedUpdateVehicleProps(playerId, cb, markerId, props, plate) + local identifier = Framework.getPlayerCharIdentifier(playerId) + + local trimmedPlate = Framework.trim(plate) + + if(Framework.getFramework() == "ESX") then + MySQL.Async.fetchScalar("SELECT vehicle FROM owned_vehicles WHERE (plate=@plate OR plate=@trimmedPlate) AND `owner`=@identifier", { + ["@identifier"] = identifier, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }, function(oldProps) + if(oldProps) then + oldProps = json.decode(oldProps) + + if(oldProps.model ~= props.model) then + cb(false) + return + end + + MySQL.Async.execute("UPDATE owned_vehicles SET vehicle=@props, `stored`=1 WHERE (plate=@plate OR plate=@trimmedPlate) AND `owner`=@identifier", { + ["@props"] = json.encode(props), + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate, + ["@identifier"] = identifier, + }, function(affectedRows) + cb(affectedRows > 0) + end) + + else + cb(false) + end + end) + elseif(Framework.getFramework() == "QB-core") then + MySQL.Async.fetchScalar("SELECT mods FROM player_vehicles WHERE (plate=@plate OR plate=@trimmedPlate) AND `citizenid`=@citizenid", { + ["@citizenid"] = identifier, + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate + }, function(oldProps) + if(oldProps) then + oldProps = json.decode(oldProps) + + if(oldProps.model ~= props.model) then + cb(false) + return + end + + MySQL.Async.execute("UPDATE player_vehicles SET mods = @props, state = 1 WHERE (plate=@plate OR plate=@trimmedPlate) AND citizenid=@citizenid", { + ["@props"] = json.encode(props), + ["@plate"] = plate, + ["@trimmedPlate"] = trimmedPlate, + ["@citizenid"] = identifier, + }, function(affectedRows) + cb(affectedRows > 0) + end) + + else + cb(false) + end + end) + end +end +RegisterServerCallback(Utils.eventsPrefix .. ":garage_owned:updateVehicleProps", garageOwnedUpdateVehicleProps) + +local function spawnedVehicle(plate) + local playerId = source + local identifier = Framework.getPlayerCharIdentifier(playerId) + + if(Framework.getFramework() == "ESX") then + MySQL.Async.execute("UPDATE owned_vehicles SET `stored`=0 WHERE plate=@plate AND `owner`=@identifier", { + ["@plate"] = plate, + ["@identifier"] = identifier, + }) + elseif(Framework.getFramework() == "QB-core") then + MySQL.Async.execute("UPDATE player_vehicles SET `state`=0 WHERE citizenid=@citizenid AND plate=@plate", { + ["@citizenid"] = identifier, + ["@plate"] = plate, + }) + end +end +RegisterNetEvent(Utils.eventsPrefix .. ':garage_owned:spawnedVehicle', spawnedVehicle) diff --git a/resources/[creators]/jobs_creator/server/markers/harvest.lua b/resources/[creators]/jobs_creator/server/markers/harvest.lua new file mode 100644 index 0000000..2443a40 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/harvest.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/job_outfit.lua b/resources/[creators]/jobs_creator/server/markers/job_outfit.lua new file mode 100644 index 0000000..581627c Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/job_outfit.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/job_shop.lua b/resources/[creators]/jobs_creator/server/markers/job_shop.lua new file mode 100644 index 0000000..1f598bd Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/job_shop.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/market.lua b/resources/[creators]/jobs_creator/server/markers/market.lua new file mode 100644 index 0000000..9c12c0f Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/market.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/permanent_garage.lua b/resources/[creators]/jobs_creator/server/markers/permanent_garage.lua new file mode 100644 index 0000000..23a8375 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/permanent_garage.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/process.lua b/resources/[creators]/jobs_creator/server/markers/process.lua new file mode 100644 index 0000000..1a2835a Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/process.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/safe.lua b/resources/[creators]/jobs_creator/server/markers/safe.lua new file mode 100644 index 0000000..c4cff7f Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/safe.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/shop.lua b/resources/[creators]/jobs_creator/server/markers/shop.lua new file mode 100644 index 0000000..e6b3b03 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/shop.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/stash.lua b/resources/[creators]/jobs_creator/server/markers/stash.lua new file mode 100644 index 0000000..ac1511e Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/stash.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/teleport.lua b/resources/[creators]/jobs_creator/server/markers/teleport.lua new file mode 100644 index 0000000..e470196 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/teleport.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/temporary_garage.lua b/resources/[creators]/jobs_creator/server/markers/temporary_garage.lua new file mode 100644 index 0000000..058a17f Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/temporary_garage.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/wardrobe.lua b/resources/[creators]/jobs_creator/server/markers/wardrobe.lua new file mode 100644 index 0000000..6d9453f Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/wardrobe.lua differ diff --git a/resources/[creators]/jobs_creator/server/markers/weapon_upgrader.lua b/resources/[creators]/jobs_creator/server/markers/weapon_upgrader.lua new file mode 100644 index 0000000..a000ae3 Binary files /dev/null and b/resources/[creators]/jobs_creator/server/markers/weapon_upgrader.lua differ diff --git a/resources/[creators]/jobs_creator/shared/shared.lua b/resources/[creators]/jobs_creator/shared/shared.lua new file mode 100644 index 0000000..050dd10 Binary files /dev/null and b/resources/[creators]/jobs_creator/shared/shared.lua differ diff --git a/resources/[creators]/jobs_creator/sql/items_limit.sql b/resources/[creators]/jobs_creator/sql/items_limit.sql new file mode 100644 index 0000000..e77b8ac --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/items_limit.sql @@ -0,0 +1,12 @@ +/* + Only for ESX with "limit" for items + For QBCore check documentation +*/ + +INSERT IGNORE `items` (`name`, `label`, `limit`, `rare`, `can_remove`) VALUES + ('fixkit', 'Fix kit', 100, 0, 1), + ('medikit', 'Medikit', 100, 0, 1), + ('sponge', 'Sponge', 100, 0, 1), + ('handcuffs', 'Handcuffs', 100, 0, 1), + ('lockpick', 'Lockpick', 100, 0, 1), + ('bandage', 'Bandage', 100, 0, 1); \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/items_weight.sql b/resources/[creators]/jobs_creator/sql/items_weight.sql new file mode 100644 index 0000000..97c2adb --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/items_weight.sql @@ -0,0 +1,12 @@ +/* + Only for ESX with "weight" for items + For QBCore check documentation +*/ + +INSERT IGNORE `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES + ('fixkit', 'Fix kit', 1, 0, 1), + ('medikit', 'Medikit', 1, 0, 1), + ('sponge', 'Sponge', 1, 0, 1), + ('handcuffs', 'Handcuffs', 1, 0, 1), + ('lockpick', 'Lockpick', 1, 0, 1), + ('bandage', 'Bandage', 1, 0, 1); \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/job_grades_auto_increment.sql b/resources/[creators]/jobs_creator/sql/job_grades_auto_increment.sql new file mode 100644 index 0000000..729a8c9 --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/job_grades_auto_increment.sql @@ -0,0 +1 @@ +ALTER TABLE job_grades MODIFY COLUMN id INT auto_increment; \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/job_grades_esx.sql b/resources/[creators]/jobs_creator/sql/job_grades_esx.sql new file mode 100644 index 0000000..27bb43e --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/job_grades_esx.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS `job_grades` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `job_name` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `grade` INT(11) NOT NULL, + `name` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `label` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `salary` INT(11) NOT NULL, + `skin_male` longtext NOT NULL, + `skin_female` longtext NOT NULL, + PRIMARY KEY (`id`) USING BTREE, + INDEX `id` (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/job_grades_qbcore.sql b/resources/[creators]/jobs_creator/sql/job_grades_qbcore.sql new file mode 100644 index 0000000..9d948c3 --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/job_grades_qbcore.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS `job_grades` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `job_name` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `grade` INT(11) NOT NULL, + `name` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `label` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `salary` INT(11) NOT NULL, + PRIMARY KEY (`id`) USING BTREE, + INDEX `id` (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/jobs.sql b/resources/[creators]/jobs_creator/sql/jobs.sql new file mode 100644 index 0000000..af1a81d --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/jobs.sql @@ -0,0 +1,24 @@ +CREATE TABLE IF NOT EXISTS `jobs` ( + `name` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `label` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `whitelisted` INT(1) NOT NULL DEFAULT '0', + `enable_billing` INT(1) NULL DEFAULT '0', + `can_rob` INT(1) NULL DEFAULT '0', + `can_handcuff` INT(1) NULL DEFAULT '0', + `can_lockpick_cars` INT(1) NULL DEFAULT '0', + `can_wash_vehicles` INT(1) NULL DEFAULT '0', + `can_repair_vehicles` INT(1) NULL DEFAULT '0', + `can_impound_vehicles` INT(1) NULL DEFAULT '0', + `can_check_identity` INT(1) NULL DEFAULT '0', + `can_check_vehicle_owner` INT(1) NULL DEFAULT '0', + `can_check_driving_license` INT(1) NULL DEFAULT '0', + `can_check_weapon_license` INT(1) NULL DEFAULT '0', + `can_heal` INT(1) NULL DEFAULT '0', + `can_revive` INT(1) NULL DEFAULT '0', + `actions_menu_enabled` INT(1) NULL DEFAULT '1', + `placeable_objects` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin', + PRIMARY KEY (`name`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=InnoDB +; diff --git a/resources/[creators]/jobs_creator/sql/jobs_armories.sql b/resources/[creators]/jobs_creator/sql/jobs_armories.sql new file mode 100644 index 0000000..b91befb --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/jobs_armories.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS `jobs_armories` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `weapon` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `components` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin', + `ammo` INT(10) UNSIGNED NOT NULL, + `tint` INT(11) NOT NULL, + `marker_id` INT(11) NOT NULL, + `identifier` VARCHAR(80) NOT NULL COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`id`) USING BTREE, + INDEX `id` (`id`, `marker_id`, `identifier`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/jobs_data.sql b/resources/[creators]/jobs_creator/sql/jobs_data.sql new file mode 100644 index 0000000..c0dca28 --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/jobs_data.sql @@ -0,0 +1,37 @@ +CREATE TABLE IF NOT EXISTS `jobs_data` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `job_name` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `type` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `coords` VARCHAR(300) NOT NULL DEFAULT '' COLLATE 'utf8mb4_general_ci', + + `grades_type` VARCHAR(20) DEFAULT NULL, + `specific_grades` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin', + `min_grade` SMALLINT(6) NULL DEFAULT NULL, + + `data` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin', + + `blip_id` INT(11) NULL DEFAULT NULL, + `blip_color` INT(11) NULL DEFAULT '0', + `blip_scale` FLOAT(12) NULL DEFAULT '1', + + `label` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + + `marker_type` INT(11) NULL DEFAULT '1', + + `marker_scale_x` FLOAT(12) NULL DEFAULT '1.5', + `marker_scale_y` FLOAT(12) NULL DEFAULT '1.5', + `marker_scale_z` FLOAT(12) NULL DEFAULT '0.5', + + `marker_color_red` INT(3) NULL DEFAULT '150', + `marker_color_green` INT(3) NULL DEFAULT '150', + `marker_color_blue` INT(3) NULL DEFAULT '0', + `marker_color_alpha` INT(3) NULL DEFAULT '50', + + `ped` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `ped_heading` FLOAT(12) NULL DEFAULT NULL, + + `object` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + `object_heading` FLOAT(12) NULL DEFAULT NULL, + + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/jobs_data_specific_grades_fix.sql b/resources/[creators]/jobs_creator/sql/jobs_data_specific_grades_fix.sql new file mode 100644 index 0000000..0792790 --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/jobs_data_specific_grades_fix.sql @@ -0,0 +1,2 @@ +ALTER TABLE `jobs_data` +MODIFY COLUMN `specific_grades` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin'; diff --git a/resources/[creators]/jobs_creator/sql/jobs_employee_hours.sql b/resources/[creators]/jobs_creator/sql/jobs_employee_hours.sql new file mode 100644 index 0000000..68960cf --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/jobs_employee_hours.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS `jobs_employee_hours` ( + `job_name` VARCHAR(50) NOT NULL, + `char_identifier` VARCHAR(100) NOT NULL, + `total_minutes` INT(11) NOT NULL DEFAULT '0', + `date` DATE NOT NULL, + PRIMARY KEY (`job_name`, `char_identifier`, `date`) +) ENGINE=InnoDB; \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/jobs_garages.sql b/resources/[creators]/jobs_creator/sql/jobs_garages.sql new file mode 100644 index 0000000..ca69b76 --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/jobs_garages.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS `jobs_garages` ( + `vehicle_id` INT(11) NOT NULL AUTO_INCREMENT, + `identifier` VARCHAR(100) NOT NULL COLLATE 'utf8mb4_general_ci', + `marker_id` INT(11) NOT NULL, + `vehicle` VARCHAR(50) NOT NULL DEFAULT '' COLLATE 'utf8mb4_bin', + `vehicle_props` LONGTEXT NOT NULL COLLATE 'utf8mb4_bin', + `plate` VARCHAR(10) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`vehicle_id`) USING BTREE, + INDEX `identifier` (`identifier`, `marker_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/jobs_shops.sql b/resources/[creators]/jobs_creator/sql/jobs_shops.sql new file mode 100644 index 0000000..754e040 --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/jobs_shops.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS `jobs_shops` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `marker_id` INT(11) NOT NULL, + `item_name` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `item_type` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `item_quantity` INT(11) NOT NULL, + `price` INT(11) NOT NULL, + PRIMARY KEY (`id`) USING BTREE, + INDEX `marker_id` (`marker_id`) USING BTREE, + INDEX `id` (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/sql/jobs_wardrobes.sql b/resources/[creators]/jobs_creator/sql/jobs_wardrobes.sql new file mode 100644 index 0000000..3951859 --- /dev/null +++ b/resources/[creators]/jobs_creator/sql/jobs_wardrobes.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS `jobs_wardrobes` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `identifier` VARCHAR(100) NOT NULL COLLATE 'utf8mb4_general_ci', + `label` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci', + `outfit` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin', + PRIMARY KEY (`id`) USING BTREE, + INDEX `identifier` (`identifier`) USING BTREE +) +COLLATE='utf8mb4_general_ci' +ENGINE=INNODB; \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/stream/L1_1.ydr b/resources/[creators]/jobs_creator/stream/L1_1.ydr new file mode 100644 index 0000000..cbf9798 Binary files /dev/null and b/resources/[creators]/jobs_creator/stream/L1_1.ydr differ diff --git a/resources/[creators]/jobs_creator/stream/L1_1.ytyp b/resources/[creators]/jobs_creator/stream/L1_1.ytyp new file mode 100644 index 0000000..b2dc998 Binary files /dev/null and b/resources/[creators]/jobs_creator/stream/L1_1.ytyp differ diff --git a/resources/[creators]/jobs_creator/utils/callbacks/cl_callbacks.lua b/resources/[creators]/jobs_creator/utils/callbacks/cl_callbacks.lua new file mode 100644 index 0000000..5c4157e Binary files /dev/null and b/resources/[creators]/jobs_creator/utils/callbacks/cl_callbacks.lua differ diff --git a/resources/[creators]/jobs_creator/utils/callbacks/sv_callbacks.lua b/resources/[creators]/jobs_creator/utils/callbacks/sv_callbacks.lua new file mode 100644 index 0000000..6197fbd Binary files /dev/null and b/resources/[creators]/jobs_creator/utils/callbacks/sv_callbacks.lua differ diff --git a/resources/[creators]/jobs_creator/utils/dialogs/announcements/announcements.js b/resources/[creators]/jobs_creator/utils/dialogs/announcements/announcements.js new file mode 100644 index 0000000..a239ab3 --- /dev/null +++ b/resources/[creators]/jobs_creator/utils/dialogs/announcements/announcements.js @@ -0,0 +1,91 @@ +let announcements = []; + +const secondsBetweenAnnouncement = 20; +let currentAnnouncementIndex = 0; + +function hideAnnouncements() { + $("#nexus-announcements-div").remove(); +} + +function setAnnouncement(index) { + const announcement = announcements[index]; + if(!announcement) { + hideAnnouncements(); + return; + } + + const animationsTime = 1000; + $("#nexus-announcements-div").fadeOut(animationsTime); + + setTimeout(() => { + if(!announcement) return; + + const scriptColor = $(".script-name").css("color"); + + if(announcement.url) { + const div = $(` + + ${announcement.id} +

    ${announcement.message}

    + +
    + `); + + div.click(function() { + $.post(`https://${resName}/nexusAnnouncementClicked`, JSON.stringify({ announcementId: announcement.id })); + }); + + $("#nexus-announcements-div").replaceWith(div).fadeIn(animationsTime); + } else { + $("#nexus-announcements-div").replaceWith(` +
    + ${announcement.id} +

    ${announcement.message}

    + +
    + `).fadeIn(animationsTime); + } + + $("#nexus-announcements-div").find(".btn-close").click((event) => { + event.stopPropagation(); + + markAnnouncementAsHidden(announcement.id); + }); + + $.post(`https://${resName}/nexusAnnouncementSeen`, JSON.stringify({ announcementId: announcement.id })); + }, animationsTime); +} + +function processAnnouncements() { + currentAnnouncementIndex = (currentAnnouncementIndex + 1) % announcements.length; + + setAnnouncement(currentAnnouncementIndex); +} + +async function markAnnouncementAsHidden(announcementId) { + await $.post(`https://${resName}/nexusMarkAnnouncementAsHidden`, JSON.stringify({ announcementId })); + refreshAnnouncements(); +} + +let announcementsIntervalId; + +async function refreshAnnouncements() { + hideAnnouncements(); + + clearInterval(announcementsIntervalId); + announcementsIntervalId = setInterval(processAnnouncements, secondsBetweenAnnouncement * 1000); + + announcements = await $.post(`https://${resName}/nexusGetAnnouncements`); + if(!announcements || announcements.length == 0) return; + + currentAnnouncementIndex = Math.floor(Math.random() * announcements.length); + + const div = $(` +
    + `); + + processAnnouncements() + $("#main-bar").prepend(div); +} \ No newline at end of file diff --git a/resources/[creators]/jobs_creator/utils/dialogs/announcements/cl_announcements.lua b/resources/[creators]/jobs_creator/utils/dialogs/announcements/cl_announcements.lua new file mode 100644 index 0000000..312d106 Binary files /dev/null and b/resources/[creators]/jobs_creator/utils/dialogs/announcements/cl_announcements.lua differ diff --git a/resources/[creators]/jobs_creator/utils/dialogs/announcements/sv_announcements.lua b/resources/[creators]/jobs_creator/utils/dialogs/announcements/sv_announcements.lua new file mode 100644 index 0000000..36f3392 Binary files /dev/null and b/resources/[creators]/jobs_creator/utils/dialogs/announcements/sv_announcements.lua differ diff --git a/resources/[creators]/jobs_creator/utils/dialogs/choose_object/choose_object.js b/resources/[creators]/jobs_creator/utils/dialogs/choose_object/choose_object.js new file mode 100644 index 0000000..861f16c --- /dev/null +++ b/resources/[creators]/jobs_creator/utils/dialogs/choose_object/choose_object.js @@ -0,0 +1,348 @@ +const ITEM_TYPES = { + item: {icon: "bi bi-box", color: "#b8e994"}, + weapon: {icon: "bi bi-radioactive", color: "#d35400"}, + account: {icon: "bi bi-wallet2", color: "#f1c40f"}, +} + +let previousObject = null; +let isMetadataDisabled = false; +let isDialogOpen = false; + +function addDivForMetadataField(parentDiv, fieldId, fieldValue, fieldType="string") { + const div = $(` +
    + + +
    + + + + + + + +
    +
    + `); + + if (fieldId) div.find(".field-id").val(fieldId); + + if (fieldValue !== undefined && fieldValue !== null) { + fieldType = typeof fieldValue; + div.find(`.field-value-input[data-field-type='${fieldType}']`).val(fieldValue.toString()); + } + + if (fieldType) { + div.find(".field-type-select").val(fieldType); + div.find(`.field-value-input[data-field-type='${fieldType}']`).prop("required", true).show(); + } + + div.find(".field-type-select").change(function() { + const fieldType = $(this).val(); + + div.find(".field-value-input").prop("required", false).hide(); + div.find(`.field-value-input[data-field-type='${fieldType}']`).prop("required", true).show(); + }); + + div.find(".btn-close").click(function() { div.remove(); }); + + parentDiv.append(div); +} + +async function metadataDialog(oldMetadata={}) { + let resolve = null; + const promise = new Promise((res) => { resolve = res; }); + + const div = $(` +