├── README.md
├── bridge
├── framework
│ ├── server
│ │ ├── esx.lua
│ │ └── qbcore.lua
│ └── client
│ │ ├── esx.lua
│ │ └── qbcore.lua
└── inventory
│ ├── client
│ ├── ox_inventory.lua
│ ├── qb-inventory.lua
│ └── quasargago.lua
│ └── server
│ ├── ox_inventory.lua
│ ├── qb-inventory.lua
│ └── quasargago.lua
├── renzu_clotheshop.sql
├── fxmanifest.lua
├── html
├── index.html
├── styleblue.css
├── stylebluex.css
└── script.js
├── server
├── main.lua
└── old
│ └── server.lua
├── client
└── main.lua
└── LICENSE
/README.md:
--------------------------------------------------------------------------------
1 | # renzu_clothes
2 | - Fivem Advanced Clotheshop and Wardrobe
3 |
4 | TODO
5 |
6 |
--------------------------------------------------------------------------------
/bridge/framework/server/esx.lua:
--------------------------------------------------------------------------------
1 | if not ESX then return end
2 |
3 | GetPlayerFromId = function(src)
4 | if type(src) == 'string' then
5 | return ESX.GetPlayerFromIdentifier(src)
6 | end
7 | return ESX.GetPlayerFromId(src)
8 | end
--------------------------------------------------------------------------------
/renzu_clotheshop.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE `users` ADD COLUMN `skin` LONGTEXT NULL DEFAULT NULL;
2 |
3 | CREATE TABLE IF NOT EXISTS `renzu_clothes` (
4 | `identifier` varchar(64) NOT NULL DEFAULT '',
5 | `wardrobe` longtext NULL,
6 | `inventory` longtext NULL,
7 | PRIMARY KEY (`identifier`)
8 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--------------------------------------------------------------------------------
/bridge/inventory/client/ox_inventory.lua:
--------------------------------------------------------------------------------
1 | if GetResourceState('ox_inventory') ~= 'started' then return end
2 |
3 | OpenStash = function(data,identifier)
4 | TriggerEvent('ox_inventory:openInventory', 'stash', {id = 'stash_'..data.motel..'_'..identifier..'_'..data.index, name = 'Storage', slots = 70, weight = 70000, coords = GetEntityCoords(cache.ped)})
5 | end
--------------------------------------------------------------------------------
/bridge/inventory/server/ox_inventory.lua:
--------------------------------------------------------------------------------
1 | if GetResourceState('ox_inventory') ~= 'started' then return end
2 |
3 | AddItem = function(src, item, count, metadata)
4 | return exports.ox_inventory:AddItem(src, item, count, metadata)
5 | end
6 |
7 | RemoveItem = function(src, item, count, metadata)
8 | return exports.ox_inventory:RemoveItem(src, item, count, metadata)
9 | end
--------------------------------------------------------------------------------
/bridge/inventory/server/qb-inventory.lua:
--------------------------------------------------------------------------------
1 | if GetResourceState('qb-inventory') ~= 'started' then return end
2 |
3 | AddItem = function(src, item, count, metadata)
4 | return exports['qb-inventory']:AddItem(src, item, count, slot, metadata)
5 | end
6 |
7 | RemoveItem = function(src, item, count, metadata)
8 | return exports['qb-inventory']:RemoveItem(src, item, count, slot, metadata)
9 | end
--------------------------------------------------------------------------------
/bridge/inventory/client/qb-inventory.lua:
--------------------------------------------------------------------------------
1 | if GetResourceState('qb-inventory') ~= 'started' then return end
2 |
3 | OpenStash = function(data,identifier)
4 | TriggerServerEvent('inventory:server:OpenInventory', 'stash', 'stash_'..data.motel..'_'..identifier..'_'..data.index, {})
5 | TriggerServerEvent("InteractSound_SV:PlayOnSource", "StashOpen", 0.4)
6 | TriggerEvent("inventory:client:SetCurrentStash", 'stash_'..data.motel..'_'..identifier..'_'..data.index)
7 | end
--------------------------------------------------------------------------------
/bridge/inventory/client/quasargago.lua:
--------------------------------------------------------------------------------
1 | if GetResourceState('qs-inventory') ~= 'started' then return end
2 |
3 | OpenStash = function(data,identifier)
4 | TriggerServerEvent('inventory:server:OpenInventory', 'stash', 'stash_'..data.motel..'_'..identifier..'_'..data.index, {})
5 | TriggerServerEvent("InteractSound_SV:PlayOnSource", "StashOpen", 0.4)
6 | TriggerEvent("inventory:client:SetCurrentStash", 'stash_'..data.motel..'_'..identifier..'_'..data.index)
7 | end
--------------------------------------------------------------------------------
/bridge/inventory/server/quasargago.lua:
--------------------------------------------------------------------------------
1 | if GetResourceState('qs-inventory') ~= 'started' then return end
2 |
3 | AddItem = function(src, item, count, metadata)
4 | if metadata then metadata.showAllDescriptions = true end
5 | return TriggerEvent('inventory:server:addItem', src, item, count, false, metadata)
6 | end
7 |
8 | RemoveItem = function(src, item, count, metadata)
9 | return TriggerEvent('inventory:server:removeItem', src, item, count, false, metadata)
10 | end
--------------------------------------------------------------------------------
/fxmanifest.lua:
--------------------------------------------------------------------------------
1 | -- MADE BY Renzuzu
2 |
3 | fx_version 'bodacious'
4 | game 'gta5'
5 |
6 | use_experimental_fxv2_oal 'yes'
7 | lua54 'yes'
8 | ui_page {
9 | 'html/index.html',
10 | }
11 |
12 | shared_script '@renzu_shield/init.lua'
13 | shared_script '@ox_lib/init.lua'
14 |
15 | server_scripts {
16 | 'bridge/framework/server/*.lua',
17 | '@mysql-async/lib/MySQL.lua',
18 | 'server/**.lua',
19 | }
20 |
21 | client_scripts {
22 | 'bridge/framework/client/*.lua',
23 | 'components.lua',
24 | 'client/**.lua',
25 | }
26 |
27 | shared_script 'config.lua'
28 |
29 | files {
30 | 'html/index.html',
31 | 'html/script.js',
32 | 'html/*.css',
33 | 'html/img/**/*.png',
34 | 'gago.json',
35 | }
36 |
--------------------------------------------------------------------------------
/bridge/framework/client/esx.lua:
--------------------------------------------------------------------------------
1 | if not ESX then return end
2 | PlayerData = ESX.GetPlayerData()
3 |
4 | RegisterNetEvent('esx:playerLoaded')
5 | AddEventHandler('esx:playerLoaded',function(playerData)
6 | PlayerData = playerData
7 | end)
8 |
9 | RegisterNetEvent('esx:setJob')
10 | AddEventHandler('esx:setJob', function(job)
11 | PlayerData.job = job
12 | end)
13 |
14 | GetInventoryItems = function(name)
15 | local PlayerData = ESX.GetPlayerData()
16 | local data = {}
17 | local itemdata = {}
18 | for _, item in pairs(PlayerData.inventory) do
19 | for k,v in pairs(items) do
20 | if v == item.name then
21 | if not itemdata[item.name] then
22 | itemdata[item.name] = item
23 | else
24 | itemdata[item.name].count += item.count
25 | end
26 | table.insert(data,itemdata)
27 | end
28 | end
29 | end
30 | return data
31 | end
--------------------------------------------------------------------------------
/bridge/framework/server/qbcore.lua:
--------------------------------------------------------------------------------
1 | if not QBCORE then return end
2 |
3 | GetPlayerFromId = function(src)
4 | local self = QBCORE.Functions.GetPlayer(src)
5 | if not self then return end
6 |
7 | if self.identifier == nil then
8 | self.identifier = self.PlayerData.citizenid
9 | end
10 |
11 | self.getMoney = function(value)
12 | return self.PlayerData.money['cash']
13 | end
14 |
15 | self.removeMoney = function(value)
16 | self.Functions.RemoveMoney('cash',tonumber(value))
17 | return true
18 | end
19 | self.name = self.PlayerData.charinfo.firstname
20 |
21 | self.addMoney = function(value)
22 | return self.Functions.AddMoney('cash',tonumber(value))
23 | end
24 |
25 | self.removeAccountMoney = function(type,val)
26 | if type == 'money' then type = 'cash' end
27 | self.Functions.RemoveMoney(type,tonumber(val))
28 | return true
29 | end
30 |
31 | self.getAccount = function(type)
32 | if type == 'money' then type = 'cash' end
33 | return {money = self.PlayerData.money[type]}
34 | end
35 |
36 | return self
37 | end
--------------------------------------------------------------------------------
/bridge/framework/client/qbcore.lua:
--------------------------------------------------------------------------------
1 | if not QBCORE then return end
2 | PlayerData = QBCORE.Functions.GetPlayerData()
3 |
4 | if PlayerData.job ~= nil then
5 | PlayerData.job.grade = PlayerData.job.grade.level
6 | end
7 |
8 | if PlayerData.identifier == nil then
9 | PlayerData.identifier = PlayerData.citizenid
10 | end
11 |
12 | RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
13 | Wait(1500)
14 | PlayerData = QBCORE.Functions.GetPlayerData()
15 |
16 | if PlayerData.job ~= nil then
17 | PlayerData.job.grade = PlayerData.job.grade.level
18 | end
19 |
20 | if PlayerData.identifier == nil then
21 | PlayerData.identifier = PlayerData.citizenid
22 | end
23 | end)
24 |
25 | RegisterNetEvent('QBCore:Client:OnJobUpdate', function(job)
26 | PlayerData.job = job
27 |
28 | PlayerData.job.grade = PlayerData.job.grade.level
29 | end)
30 |
31 | GetInventoryItems = function(name)
32 | local data = {}
33 | local PlayerData = QBCORE.Functions.GetPlayerData()
34 | for _, item in pairs(PlayerData.items) do
35 | if name == item.name then
36 | item.metadata = item.info
37 | table.insert(data,item)
38 | end
39 | end
40 | return data
41 | end
--------------------------------------------------------------------------------
/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Renzu Clothes
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
37 |
38 |
39 |
40 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/server/main.lua:
--------------------------------------------------------------------------------
1 | if Config.old then return end
2 |
3 | if not lib then warn('ox_lib is required in this version') return end
4 |
5 | lib.callback.register('renzu_clothes:Pay', function(src,total,appearance)
6 | local xPlayer = GetPlayerFromId(src)
7 | local money = xPlayer.getAccount('money').money
8 | if money >= total then
9 | xPlayer.removeMoney(total)
10 | SaveAppearance(xPlayer,appearance)
11 | return true
12 | end
13 | return false
14 | end)
15 |
16 | SaveOutfit = function(xPlayer,name,appearance)
17 | local str = 'SELECT %s FROM %s WHERE %s = ?'
18 | local query = MySQL.query.await(str:format('outfits','renzu_clothes_outfits','identifier'),{xPlayer.identifier})
19 | if query[1] then
20 | local outfits = json.decode(query[1].outfits)
21 | outfits[name] = appearance
22 | return MySQL.update.await('UPDATE renzu_clothes_outfits SET outfits = ? WHERE identifier = ?',{json.encode(outfits), xPlayer.identifier})
23 | else
24 | outfits = {[name] = appearance}
25 | return MySQL.insert.await('INSERT INTO renzu_clothes_outfits (identifier, outfits) VALUES(?, ?)',{xPlayer.identifier,json.encode(outfits)})
26 | end
27 | return false
28 | end
29 |
30 | lib.callback.register('renzu_clothes:SaveOutfit', function(src,data)
31 | local xPlayer = GetPlayerFromId(src)
32 | local appearance = data.appearance
33 | local name = data.name
34 | return SaveOutfit(xPlayer,name,appearance)
35 | end)
36 |
37 | lib.callback.register('renzu_clothes:RemoveOutfit', function(src,name)
38 | local xPlayer = GetPlayerFromId(src)
39 | return SaveOutfit(xPlayer,name,nil)
40 | end)
41 |
42 | local charset = {} do -- [0-9a-zA-Z]
43 | for c = 48, 57 do table.insert(charset, string.char(c)) end
44 | for c = 65, 90 do table.insert(charset, string.char(c)) end
45 | for c = 97, 122 do table.insert(charset, string.char(c)) end
46 | end
47 |
48 | local function randomString(length)
49 | if not length or length <= 0 then return '' end
50 | return randomString(length - 1) .. charset[math.random(1, #charset)]
51 | end
52 |
53 | local sharedcode_cache = {}
54 | lib.callback.register('renzu_clothes:GenerateCode', function(src,appearance)
55 | local generatedcode = randomString(8):upper()
56 | sharedcode_cache[generatedcode] = appearance
57 | return generatedcode
58 | end)
59 |
60 | lib.callback.register('renzu_clothes:AddCode', function(src, data)
61 | if not data then return end
62 | if not sharedcode_cache[data[1]] then return end
63 | local xPlayer = GetPlayerFromId(src)
64 | return SaveOutfit(xPlayer,data[2],sharedcode_cache[data[1]])
65 | end)
66 |
67 |
68 | lib.callback.register('renzu_clothes:getOutfits', function(src,data)
69 | local xPlayer = GetPlayerFromId(src)
70 | local outfits = {}
71 | local str = 'SELECT %s FROM %s WHERE %s = ?'
72 | local query = MySQL.query.await(str:format('outfits','renzu_clothes_outfits','identifier'),{xPlayer.identifier})
73 | local outfits = query[1] and json.decode(query[1].outfits)
74 | return outfits or {}
75 | end)
76 |
77 | SaveAppearance = function(xPlayer,skin)
78 | if ESX then
79 | MySQL.query.await('UPDATE users SET skin = ? WHERE identifier = ?', {json.encode(skin), xPlayer.identifier})
80 | else
81 | if skin.model ~= nil and skin ~= nil then
82 | -- TODO: Update primary key to be citizenid so this can be an insert on duplicate update query
83 | MySQL.query('DELETE FROM playerskins WHERE citizenid = ?', { xPlayer.PlayerData.citizenid }, function()
84 | MySQL.insert('INSERT INTO playerskins (citizenid, model, skin, active) VALUES (?, ?, ?, ?)', {
85 | xPlayer.PlayerData.citizenid,
86 | skin.model,
87 | json.encode(skin),
88 | 1
89 | })
90 | end)
91 | end
92 | end
93 | return true
94 | end
95 |
96 | Citizen.CreateThreadNow(function()
97 | local success, result = pcall(MySQL.scalar.await, 'SELECT 1 FROM renzu_clothes_outfits')
98 | if not success then
99 | MySQL.query.await([[CREATE TABLE `renzu_clothes_outfits` (
100 | `id` int NOT NULL AUTO_INCREMENT KEY,
101 | `identifier` varchar(64) DEFAULT NULL,
102 | `outfits` longtext DEFAULT NULL
103 | )]])
104 | print("^2SQL INSTALL SUCCESSFULLY ^0")
105 | end
106 | end)
--------------------------------------------------------------------------------
/server/old/server.lua:
--------------------------------------------------------------------------------
1 | if not Config.old then return end
2 | ESX = exports['es_extended']:getSharedObject()
3 |
4 | function AddClothestoInventory(current,data)
5 | for k,v in pairs(data) do
6 |
7 | --if current['inventory'] == nil then current['inventory'] = {}
8 | if current[v.name] == nil then
9 | --current[v.NameHash] = {}
10 | current[v.name] = {compo = k, draw = v.draw, texture = v.texture, count = 1}
11 |
12 | end
13 | end
14 | return current
15 | end
16 |
17 | function SaveClothes(clothename,clothe,xPlayer,data)
18 | local result = SqlFunc(Config.Mysql,'fetchAll','SELECT * FROM renzu_clothes WHERE identifier = @identifier', {['@identifier'] = xPlayer.identifier})
19 | if result[1] == nil then -- save new wardrobe to db
20 | local wardrobe = {}
21 | wardrobe[clothename] = clothe
22 | SqlFunc(Config.Mysql,'execute','INSERT INTO renzu_clothes (identifier, wardrobe, inventory) VALUES (@identifier, @wardrobe, @inventory)', {
23 | ['@identifier'] = xPlayer.identifier,
24 | ['@wardrobe'] = json.encode(wardrobe),
25 | ['@inventory'] = json.encode(AddClothestoInventory({},data))
26 | })
27 | elseif result[1] then -- replace existing or save new
28 |
29 | local wardrobe = json.decode(result[1].wardrobe) or {}
30 | local inventory = json.decode(result[1].inventory) or {}
31 | local clothes = {}
32 | if data then
33 | clothes = AddClothestoInventory(inventory,data)
34 |
35 | end
36 |
37 | wardrobe[clothename] = clothe
38 | SqlFunc(Config.Mysql,'execute','UPDATE renzu_clothes SET wardrobe = @wardrobe, inventory = @inventory WHERE identifier = @identifier', {
39 | ['@identifier'] = xPlayer.identifier,
40 | ['@wardrobe'] = json.encode(wardrobe),
41 | ['@inventory'] = json.encode(clothes)
42 | })
43 | end
44 | -- save skin
45 | SqlFunc(Config.Mysql,'execute','UPDATE users SET skin = @skin WHERE identifier = @identifier', {
46 | ['@skin'] = json.encode(clothe),
47 | ['@identifier'] = xPlayer.identifier
48 | })
49 | end
50 |
51 | ESX.RegisterServerCallback('renzu_clothes:save',function(source, cb, clothe)
52 | local source = tonumber(source)
53 | local xPlayer = ESX.GetPlayerFromId(source)
54 | SqlFunc(Config.Mysql,'execute','UPDATE users SET skin = @skin WHERE identifier = @identifier', {
55 | ['@skin'] = json.encode(clothe),
56 | ['@identifier'] = xPlayer.identifier
57 | })
58 |
59 | end)
60 |
61 | ESX.RegisterServerCallback('renzu_clothes:delclothe',function(source, cb, name)
62 | local source = tonumber(source)
63 | local xPlayer = ESX.GetPlayerFromId(source)
64 | local result = SqlFunc(Config.Mysql,'fetchAll','SELECT * FROM renzu_clothes WHERE identifier = @identifier', {['@identifier'] = xPlayer.identifier})
65 | if result[1] ~= nil then
66 | local data = result[1]
67 | local wardrobe = json.decode(data['wardrobe'])
68 | wardrobe[name] = nil
69 | SqlFunc(Config.Mysql,'execute','UPDATE renzu_clothes SET wardrobe = @wardrobe WHERE identifier = @identifier', {
70 | ['@identifier'] = xPlayer.identifier,
71 | ['@wardrobe'] = json.encode(wardrobe)
72 | })
73 | cb(true)
74 | end
75 | cb(false)
76 | end)
77 |
78 | ESX.RegisterServerCallback('renzu_clothes:buyclothe',function(source, cb, compo, draw, texture, dlc, bill)
79 | local source = tonumber(source)
80 | local xPlayer = ESX.GetPlayerFromId(source)
81 |
82 | if xPlayer.getMoney() >= bill then
83 | xPlayer.removeMoney(bill)
84 | local result = SqlFunc(Config.Mysql,'fetchAll','SELECT * FROM renzu_clothes WHERE identifier = @identifier', {['@identifier'] = xPlayer.identifier})
85 | if result[1] == nil then -- save new wardrobe to db
86 | local data = {}
87 | data['inventory'] = {}
88 | data['inventory'][dlc] = {compo = compo, draw = draw, texture = texture, count = 1}
89 | SqlFunc(Config.Mysql,'execute','INSERT INTO renzu_clothes (identifier, wardrobe) VALUES (@identifier, @wardrobe)', {
90 | ['@identifier'] = xPlayer.identifier,
91 | ['@wardrobe'] = '[]',
92 | ['@inventory'] = json.encode(data['inventory']),
93 | })
94 | elseif result[1] then -- replace existing or save new
95 | local data = {}
96 | if result[1]['inventory'] == nil then
97 | result[1]['inventory'] = {}
98 | end
99 | -- if result[1]['wardrobe'] == nil then
100 | -- result[1]['wardrobe'] = {}
101 | -- end
102 |
103 | data['inventory'] = json.decode(result[1]['inventory'])
104 |
105 | if data['inventory'][dlc] ~= nil then
106 |
107 | data['inventory'][dlc].count = tonumber(data['inventory'][dlc].count) + 1
108 | else
109 |
110 |
111 | data['inventory'][dlc] = {compo = compo, draw = draw, texture = texture, count = 1}
112 | end
113 | SqlFunc(Config.Mysql,'execute','UPDATE renzu_clothes SET inventory = @inventory WHERE identifier = @identifier', {
114 | ['@identifier'] = xPlayer.identifier,
115 | ['@inventory'] = json.encode(data['inventory'])
116 | })
117 | end
118 | Config.Notify('success','Job', dlc..' has been added to your clothing inventory',xPlayer.source)
119 | else
120 | Config.Notify('success','Job', dlc..' cannot not afford',xPlayer.source)
121 | cb(false)
122 | end
123 | end)
124 |
125 | ESX.RegisterServerCallback('renzu_clothes:selectclothe',function(source, cb, skin)
126 | local source = tonumber(source)
127 | local xPlayer = ESX.GetPlayerFromId(source)
128 | SqlFunc(Config.Mysql,'execute','UPDATE users SET skin = @skin WHERE identifier = @identifier', {
129 | ['@skin'] = json.encode(skin),
130 | ['@identifier'] = xPlayer.identifier
131 | })
132 | end)
133 |
134 | ESX.RegisterServerCallback('renzu_clothes:saveclothes', function(source, cb, name, data, inwardrobe, bill, clothedata, payment, currentshop)
135 | local xPlayer = ESX.GetPlayerFromId(source)
136 | if payment then -- Payment exists when opening cashier.
137 | if bill == 0 then
138 | Config.Notify('error', 'Clothing', 'You do not have a bill to settle with the cashier.', source)
139 | cb("ignore")
140 | elseif name == '' then
141 | Config.Notify('error', 'Clothing', 'You will need to give a name for your outfit.', source)
142 | cb("nosave")
143 | elseif payment == 'cash' then
144 | if xPlayer.getMoney() >= bill then
145 | xPlayer.removeMoney(bill)
146 | if Config.renzujobs then
147 | exports.renzu_jobs:addMoney(tonumber(bill),Config.Shop[currentshop].job,source,'money',true)
148 | end
149 | Config.Notify('success', 'Clothing', 'Purchased clothes successfully.', source)
150 | SaveClothes(name,data,xPlayer,clothedata)
151 | cb("save")
152 | else
153 | Config.Notify('error', 'Clothing', 'Not enough money on hand to make purchase.', source)
154 | cb("nosave")
155 | end
156 | elseif payment == 'bank' then
157 | if xPlayer.getAccount('bank').money >= bill then
158 | xPlayer.removeAccountMoney('bank', bill)
159 | if Config.renzujobs then
160 | exports.renzu_jobs:addMoney(tonumber(bill),Config.Shop[currentshop].job,source,'money',true)
161 | end
162 | Config.Notify('success', 'Clothing', 'Purchased clothes successfully.', source)
163 | SaveClothes(name,data,xPlayer,clothedata)
164 | cb("save")
165 | else
166 | Config.Notify('error', 'Clothing', 'Not enough money in bank to make purchase.', source)
167 | cb("nosave")
168 | end
169 | end
170 | else -- Payment is nil when opening the wardrobe.
171 | if name == '' then
172 | Config.Notify('error', 'Clothing', 'You will need to give a name for your outfit.', source)
173 | cb("nosave")
174 | else
175 | Config.Notify('success','Clothing', 'Outfit successfully saved.', source)
176 | SaveClothes(name,data,xPlayer,clothedata)
177 | cb("save")
178 | end
179 | end
180 | end)
181 |
182 | ESX.RegisterServerCallback('renzu_clothes:getPlayerWardrobe', function(source, cb, inventory, data)
183 |
184 | local xPlayer = ESX.GetPlayerFromId(source)
185 | local result = SqlFunc(Config.Mysql,'fetchAll','SELECT * FROM renzu_clothes WHERE identifier = @identifier', {['@identifier'] = xPlayer.identifier})
186 | local wardrobe = {}
187 | local inventory = {}
188 |
189 | if result[1] then
190 | wardrobe = json.decode(result[1].wardrobe) or {}
191 | inventory = json.decode(result[1].inventory) or {}
192 | else
193 | SqlFunc(Config.Mysql,'execute','INSERT INTO renzu_clothes (identifier, wardrobe, inventory) VALUES (@identifier, @wardrobe, @inventory)', {
194 | ['@identifier'] = xPlayer.identifier,
195 | ['@wardrobe'] = '[]',
196 | ['@inventory'] = json.encode(AddClothestoInventory({},data))
197 | })
198 | wardrobe = {}
199 | inventory = AddClothestoInventory({},data) or {}
200 | end
201 | cb({inventory = inventory, wardrobe = wardrobe})
202 | end)
203 |
204 | function SqlFunc(plugin,type,query,var)
205 | local wait = promise.new()
206 | if type == 'fetchAll' and plugin == 'mysql-async' then
207 | MySQL.Async.fetchAll(query, var, function(result)
208 | wait:resolve(result)
209 | end)
210 | end
211 | if type == 'execute' and plugin == 'mysql-async' then
212 | MySQL.Async.execute(query, var, function(result)
213 | wait:resolve(result)
214 | end)
215 | end
216 | if type == 'execute' and plugin == 'ghmattisql' then
217 | exports['ghmattimysql']:execute(query, var, function(result)
218 | wait:resolve(result)
219 | end)
220 | end
221 | if type == 'fetchAll' and plugin == 'ghmattisql' then
222 | exports.ghmattimysql:execute(query, var, function(result)
223 | wait:resolve(result)
224 | end)
225 | end
226 | if type == 'execute' and plugin == 'oxmysql' then
227 | exports.oxmysql:execute(query, var, function(result)
228 | wait:resolve(result)
229 | end)
230 | end
231 | if type == 'fetchAll' and plugin == 'oxmysql' then
232 | exports['oxmysql']:fetch(query, var, function(result)
233 | wait:resolve(result)
234 | end)
235 | end
236 | return Citizen.Await(wait)
237 | end
238 |
239 | AddEventHandler('onResourceStop', function(resourceName)
240 | if (GetCurrentResourceName() ~= resourceName) then
241 | return
242 | end
243 |
244 | end)
245 |
--------------------------------------------------------------------------------
/client/main.lua:
--------------------------------------------------------------------------------
1 | if Config.old then return end
2 |
3 | if not lib then warn('ox_lib is required in this version') return end
4 |
5 | local oldskin = nil
6 | local oldcomponent = {}
7 | local carts = {}
8 |
9 | SetPedComponent = function(type, component, drawable, index)
10 | if type ~= 'Props' then
11 | return SetPedComponentVariation(cache.ped, component, drawable, index, 2)
12 | else
13 | return SetPedPropIndex(cache.ped, component, drawable, index, 2)
14 | end
15 | end
16 |
17 | ClothingMenu = function(data)
18 | local lists = {}
19 | local clothesdata = deepcopy(Config.Data)
20 | if not oldskin then
21 | oldskin = Config.GetSkin()
22 | end
23 | local nums = {}
24 | local texture = data.type ~= 'Props' and GetPedTextureVariation(cache.ped,data.id) or GetPedPropTextureIndex(cache.ped,data.id)
25 | local drawable = data.type ~= 'Props' and GetPedDrawableVariation(cache.ped,data.id) or GetPedPropIndex(cache.ped,data.id)
26 | oldcomponent = {
27 | type = data.type,
28 | texture = texture,
29 | drawable = drawable,
30 | component = data.id
31 | }
32 | for drawable = 1, data.num do
33 | local texturenum = data.type ~= 'Props' and GetNumberOfPedTextureVariations(cache.ped, data.id, drawable) or GetNumberOfPedPropTextureVariations(cache.ped, data.id, drawable, - 1)
34 | local clothes_meta = {}
35 | local textureid = 1
36 | local drawable = drawable
37 | for texture = 1, texturenum do
38 | clothes_meta = GetClotheData(data.id,drawable,texture,data.type == 'Props',data.name) or GetClotheData(data.id,drawable,1,data.type == 'Props',data.name) or clothes_meta
39 | textureid = texture
40 | table.insert(nums,clothes_meta.label and clothes_meta.label ~= clothes_meta.NameHash and clothes_meta.label or data.name:gsub('_1',''):upper() ..' - '..texture)
41 | end
42 | local label = clothes_meta.label or ''
43 | local hash = clothes_meta.NameHash or ''
44 | local icon = clothes_meta.label and clothes_meta.label ~= clothes_meta.NameHash and 'https://raw.githubusercontent.com/renzuzu/carmap/main/carmap/clothes/'..hash..'.png' or data.icon
45 | local price = clothes_meta.Price or 100
46 | table.insert(lists,{close = false, description = 'Price: '..price, icon = icon, label = 'T Shirt '..label, values = nums , args = {price = price, drawable = drawable, texture = textureid, component = data.id}})
47 | nums = {}
48 | end
49 |
50 | if #lists == 0 then
51 | return Notify('No Clothing Available')
52 | end
53 |
54 | lib.registerMenu({
55 | id = 'clothe_lists',
56 | title = data.name:gsub('_1',''):upper(),
57 | position = 'top-right',
58 | onSideScroll = function(selected, scrollIndex, args)
59 | SetPedComponent(data.type,args.component, args.drawable, scrollIndex)
60 | end,
61 | onSelected = function(selected, secondary, args)
62 | SetPedComponent(data.type,args.component, args.drawable, secondary)
63 | end,
64 | onClose = function(keyPressed)
65 | SetPedComponent(oldcomponent.type,oldcomponent.component, oldcomponent.drawable, oldcomponent.texture)
66 | end,
67 | options = lists
68 | }, function(selected, scrollIndex, args)
69 |
70 | if not carts[args.component] then
71 | carts[args.component] = {}
72 | end
73 |
74 | carts[args.component] = {
75 | texture = scrollIndex,
76 | drawable = args.drawable,
77 | component = args.component,
78 | price = args.price
79 | }
80 |
81 | oldcomponent = {
82 | type = data.type,
83 | texture = scrollIndex,
84 | drawable = args.drawable,
85 | component = args.component
86 | }
87 |
88 | lib.notify({
89 | description = 'Added to Cart',
90 | type = 'success'
91 | })
92 | end)
93 |
94 | lib.showMenu('clothe_lists')
95 | end
96 |
97 | GetNumOfPedVariations = function(type,id)
98 | if type == 'ComponentVariations' then
99 | return GetNumberOfPedDrawableVariations(cache.ped, id)
100 | elseif type == 'Props' then
101 | return GetNumberOfPedPropDrawableVariations(cache.ped, id)
102 | end
103 | end
104 |
105 | ClothingIndex = function(data)
106 | local lists = {}
107 | local clothesdata = deepcopy(Config.Data)
108 |
109 | local hasarms = false
110 | local indexes = data.indexes
111 | for k,v in pairs(indexes) do
112 | if string.find(v,'arms') then
113 | hasarms = true
114 | end
115 | if clothesdata[v] and clothesdata[v].type and not string.find(v,'_2') then
116 | local num = GetNumOfPedVariations(clothesdata[v].type, clothesdata[v].componentid)
117 | table.insert(lists,{icon = clothesdata[v].icon,label = clothesdata[v].label, description = clothesdata[v].label, args = {icon = clothesdata[v].icon, type = clothesdata[v].type, num = num, id = clothesdata[v].componentid, name = v}})
118 | end
119 | end
120 |
121 | if #lists == 0 then
122 | Notify('No Clothing Available')
123 | return
124 | end
125 | if not hasarms then
126 | local num = GetNumOfPedVariations(clothesdata[indexes[1]].type, clothesdata[indexes[1]].componentid)
127 | return ClothingMenu({icon = clothesdata[indexes[1]].icon, type = clothesdata[indexes[1]].type, num = num, id = clothesdata[indexes[1]].componentid, name = indexes[1]})
128 | end
129 |
130 | lib.registerMenu({
131 | id = 'menu__index',
132 | title = data.label,
133 | position = 'top-right',
134 | options = lists
135 | }, function(selected, scrollIndex, args)
136 | ClothingMenu(args)
137 | end)
138 |
139 | lib.showMenu('menu__index')
140 | end
141 |
142 | Notify = function(msg,icon)
143 | local label = type(msg) ~= 'string' and '[E] - '..msg.label or msg
144 | lib.showTextUI(label, {
145 | position = "top-right",
146 | icon = icon or 'hand',
147 | style = {
148 | --borderRadius = '10px',
149 | backgroundColor = 'rgb(66 67 68 / 20%)',
150 | color = '#ccd1d5',
151 | textShadow = '1px 1px #8d959d',
152 | boxShadow = 'rgb(239 239 239 / 80%) 2px 2px 3px',
153 | borderBottomLeftRadius = '0 ',
154 | borderTopLeftRadius = '30px',
155 | marginBottom = '20vh'
156 | }
157 | })
158 | end
159 |
160 | Cashier = function(data)
161 | local total = 0
162 | local incart = 0
163 | for k,v in pairs(carts) do
164 | total += v.price
165 | incart += 1
166 | end
167 | lib.registerContext({
168 | id = 'clothe_cashier',
169 | title = 'Shop Cashier',
170 | options = {
171 | {
172 | title = 'Pay Bills',
173 | description = '***Total:*** $ '..total..' \n ***inCart:*** '..incart,
174 | icon = 'check',
175 | onSelect = function()
176 | Config.GetSkin()
177 | local success = lib.callback.await('renzu_clothes:Pay', false, total,Config.GetSkin())
178 | if success then
179 | Notify('Clothes Successfully paid', 'check')
180 | carts = {}
181 | oldskin = nil
182 | oldcomponent = {}
183 | else
184 | Notify('You dont have enough money', 'cross')
185 | end
186 | end,
187 | arrow = true,
188 | args = {
189 | someValue = 500
190 | }
191 | }
192 | }
193 | })
194 | lib.showContext('clothe_cashier')
195 | end
196 |
197 | Outfits = function()
198 | local options = {}
199 | local outfits = lib.callback.await('renzu_clothes:getOutfits',false)
200 | for name,appearance in pairs(outfits) do
201 | table.insert(options,{
202 | title = name,
203 | description = 'use outfit '..name,
204 | icon = 'tshirt',
205 | onSelect = function()
206 | lib.registerContext({
207 | id = 'outfit_option',
208 | title = 'Outfit',
209 | menu = 'outfits',
210 | options = {
211 | {
212 | title = 'Use',
213 | description = 'Set as New Outfit',
214 | icon = 'user-check',
215 | iconColor = 'green',
216 | onSelect = function()
217 | lib.showContext('outfits')
218 | Config.SetSkin(appearance)
219 | Notify('Outfit '..name..' is used', 'check')
220 | end
221 | },
222 | {
223 | title = 'Delete',
224 | description = 'Remove outfit from wardrobe',
225 | icon = 'user-times',
226 | iconColor = 'red',
227 | onSelect = function()
228 | local success = lib.callback.await('renzu_clothes:RemoveOutfit',false,name)
229 | Notify('Outfit '..name..' has been removed')
230 | end
231 | }
232 | }
233 | })
234 | lib.showContext('outfit_option')
235 | end,
236 | arrow = true,
237 | })
238 | end
239 | if #options == 0 then
240 | return Notify('Outfits is empty', 'check')
241 | end
242 | lib.registerContext({
243 | id = 'outfits',
244 | title = 'Outfit Lists',
245 | menu = 'wardrobe',
246 | options = options
247 | })
248 | lib.showContext('outfits')
249 | end
250 |
251 | Wardrobe = function(data)
252 | lib.registerContext({
253 | id = 'wardrobe',
254 | title = 'Wardrobe',
255 | options = {
256 | {
257 | title = 'Save Current',
258 | description = 'Save current outfit',
259 | icon = 'save',
260 | onSelect = function()
261 | local input = lib.inputDialog('New Outfit', {
262 | {type = 'input', label = 'Outfit Name', description = 'Name of the new outfit'},
263 | })
264 |
265 | if not input then return end
266 | local appearance = Config.GetSkin()
267 | local success = lib.callback.await('renzu_clothes:SaveOutfit',false, {name = input[1], appearance = appearance})
268 |
269 | if success then
270 | Notify('Outfit '..input[1]..' Saved', 'check')
271 | else
272 | Notify('Outfit '..input[1]..' is not saved', 'check')
273 | end
274 |
275 | end,
276 | arrow = true,
277 | },
278 | {
279 | title = 'View Outfits',
280 | description = 'See all saved outfits',
281 | icon = 'list',
282 | onSelect = Outfits,
283 | arrow = true,
284 | },
285 | {
286 | title = 'Add Outfit Code',
287 | description = 'Save outfit from generated code',
288 | icon = 'code',
289 | onSelect = function()
290 | local input = lib.inputDialog('Add Outfit Code', {
291 | {type = 'input', label = 'Outfit code', description = 'Shared outfit code'},
292 | {type = 'input', label = 'New Outfit Name', description = 'name your outfit'},
293 | })
294 |
295 | if not input then return end
296 |
297 | local add = lib.callback.await('renzu_clothes:AddCode',false,input)
298 |
299 | if add then
300 | Notify('Outfit has beed saved to wardrobe')
301 | else
302 | Notify('Outfit code does not exist')
303 | end
304 | end,
305 | arrow = true,
306 | },
307 | {
308 | title = 'Generate Code',
309 | description = 'Generate sharable code for current outfit',
310 | icon = 'qrcode',
311 | onSelect = function()
312 | local code = lib.callback.await('renzu_clothes:GenerateCode',false, Config.GetSkin())
313 |
314 | if code then
315 | local input = lib.inputDialog('Generated Outfit Code', {
316 | {type = 'input', label = 'Outfit code', description = 'Shareable outfit code', disabled = true, default = code},
317 | })
318 |
319 | if not input then return end
320 | lib.setClipboard(code)
321 | Notify("Code has been Copy to Clipboard")
322 | end
323 | end,
324 | arrow = true,
325 | }
326 | }
327 | })
328 | lib.showContext('wardrobe')
329 | end
330 |
331 | ClothingPoints = function(data)
332 | local point = lib.points.new(data.coord, 1.5, {
333 | data = data,
334 | })
335 |
336 | function point:onEnter()
337 | Notify(self.data,data.icon or Config.Data[self.data.indexes[1]].icon)
338 | end
339 |
340 | function point:onExit()
341 | lib.hideTextUI()
342 | end
343 |
344 | function point:nearby()
345 | DrawMarker(2, self.coords.x, self.coords.y, self.coords.z, 0.0, 0.0, 0.0, 0.0, 180.0, 0.0, 0.4, 0.4, 0.4, 200, 255, 241, 50, false, true, 2, nil, nil, false)
346 |
347 | if self.currentDistance < 1 and IsControlJustReleased(0, 38) then
348 | if data.type == 'cashier' then
349 | Cashier(data)
350 | elseif data.type == 'wardrobe' then
351 | Wardrobe(data)
352 | else
353 | ClothingIndex(self.data)
354 | end
355 | end
356 | end
357 | return point
358 | end
359 |
360 | local points = {}
361 | local ped = nil
362 | ClothingZones = function(data) -- check if player entered the zones and trigger all points for shop
363 | function onEnter(self)
364 | for k,point in pairs(data.clothesdisplay) do
365 | table.insert(points,ClothingPoints(point))
366 | end
367 | table.insert(points,ClothingPoints({label = 'Cashier', coord = data.cashier, type = 'cashier', icon = 'cash-register'}))
368 | table.insert(points,ClothingPoints({label = 'Wardrobe', coord = data.wardrobe, type = 'wardrobe', icon = 'tshirt'}))
369 |
370 | local model = `s_f_y_shop_mid`
371 | lib.requestModel(model)
372 | ped = CreatePed(4, model, data.cashier_ped.x,data.cashier_ped.y,data.cashier_ped.z, false, false)
373 | TaskTurnPedToFaceEntity(ped,cache.ped,-1)
374 | SetEntityAsMissionEntity(ped, true, true)
375 | SetBlockingOfNonTemporaryEvents(ped, true)
376 | SetEntityInvincible(ped, true)
377 |
378 | Notify('Welcome to Clothing Shop','fas fa-tshirt')
379 | Wait(3000)
380 | lib.hideTextUI()
381 | end
382 |
383 | function onExit(self)
384 | for i = 1 , #points do
385 | points[i]:remove()
386 | end
387 | if DoesEntityExist(ped) then
388 | DeleteEntity(ped)
389 | end
390 |
391 | if oldskin then
392 | Config.SetSkin(oldskin)
393 | oldskin = nil
394 | carts = {}
395 | oldcomponent = {}
396 | lib.hideMenu(true)
397 | end
398 | end
399 |
400 |
401 | local box = lib.zones.box({
402 | coords = data.coord,
403 | size = vec3(30, 30, 20),
404 | rotation = 45,
405 | debug = false,
406 | inside = inside,
407 | onEnter = onEnter,
408 | onExit = onExit
409 | })
410 | end
411 |
412 | for k,v in pairs(Config.Shop) do
413 |
414 | ClothingZones(v)
415 |
416 | local vec = v.coord
417 | local name = v.name
418 | local blip = AddBlipForCoord(v.coord.x, v.coord.y, v.coord.z)
419 | SetBlipSprite (blip, v.blips.sprite)
420 | SetBlipDisplay(blip, 4)
421 | SetBlipScale (blip, 0.8)
422 | SetBlipColour (blip, v.blips.color)
423 | SetBlipAsShortRange(blip, true)
424 | BeginTextCommandSetBlipName('STRING')
425 | AddTextComponentSubstringPlayerName(""..v.name.."")
426 | EndTextCommandSetBlipName(blip)
427 | end
428 |
429 | function GetClotheData(componentid,drawableid,textureid,prop,name)
430 | local data = {}
431 | if prop then
432 |
433 | data = Components.Props[GetEntityModel(PlayerPedId())][tostring(componentid)] ~= nil and Components.Props[GetEntityModel(PlayerPedId())][tostring(componentid)][tostring(drawableid)] ~= nil and Components.Props[GetEntityModel(PlayerPedId())][tostring(componentid)][tostring(drawableid)][tostring(textureid)] ~= nil and Components.Props[GetEntityModel(PlayerPedId())][tostring(componentid)][tostring(drawableid)][tostring(textureid)]
434 | if name and data then
435 | data.Price = data.Price * Config.Data[name].multiplier
436 | end
437 | return data
438 |
439 | elseif not prop then
440 |
441 | data = Components.ComponentVariations[GetEntityModel(PlayerPedId())][tostring(componentid)] ~= nil and Components.ComponentVariations[GetEntityModel(PlayerPedId())][tostring(componentid)][tostring(drawableid)] ~= nil and Components.ComponentVariations[GetEntityModel(PlayerPedId())][tostring(componentid)][tostring(drawableid)][tostring(textureid)] ~= nil and Components.ComponentVariations[GetEntityModel(PlayerPedId())][tostring(componentid)][tostring(drawableid)][tostring(textureid)]
442 | if name and data then
443 | data.Price = data.Price * Config.Data[name].multiplier
444 | end
445 |
446 | end
447 | return data
448 | end
449 |
450 | function deepcopy(orig)
451 | local orig_type = type(orig)
452 | local copy
453 | if orig_type == 'table' then
454 | copy = {}
455 | for orig_key, orig_value in next, orig, nil do
456 | copy[deepcopy(orig_key)] = deepcopy(orig_value)
457 | end
458 | setmetatable(copy, deepcopy(getmetatable(orig)))
459 | else -- number, string, boolean, etc
460 | copy = orig
461 | end
462 | return copy
463 | end
--------------------------------------------------------------------------------
/html/styleblue.css:
--------------------------------------------------------------------------------
1 | .leaderboard {
2 | max-width: 40vw;
3 | width: 40vw;
4 | border-radius: 12px;
5 | max-height: 70vh;
6 | overflow-x: hidden;
7 | }
8 | header {
9 | height: 11vh !important;
10 | position: absolute !important;
11 | width: 93% !important;
12 | }
13 | article {
14 | width: 99% !important;
15 | }
16 | .leaderboard header {
17 | /* --start: 20%;
18 | height: 130px; */
19 | --start: 25%;
20 | height: 100px;
21 | background-image: repeating-radial-gradient(circle at var(--start), #613a3a0a 0%, #00000091 10%, rgb(0 0 0 / 53%) 10%, rgb(43 30 30 / 33%) 17%), linear-gradient(to right, #090b15b8, #1d1d1fbd);
22 | background: #050d23;
23 | color: #fff;
24 | position: fixed;
25 | border-radius: 12px 12px 0 0;
26 | overflow: hidden;
27 | background: rgb(93 98 103);
28 | /* background: linear-gradient(90deg, rgb(143 146 148) 0%, rgb(136 138 140) 35%, rgb(156 159 162) 100%); */
29 | width: 40vw;
30 | z-index: 999;
31 | border-bottom-left-radius: 10px;
32 | border-bottom-right-radius: 10px;
33 | left: 2%;
34 | }
35 | .leaderboard header .leaderboard__title {
36 | position: absolute;
37 | z-index: 2;
38 | top: 50%;
39 |
40 | transform: translateY(-50%);
41 | text-transform: uppercase;
42 | margin: 0;
43 | }
44 | .leaderboard header .leaderboard__title span {
45 | display: block;
46 | margin-top: 2px;
47 | margin-right: 21px;
48 | /* position: absolute; */
49 | }
50 | .leaderboard header .leaderboard__title--top {
51 | font-size: 24px;
52 | font-weight: 700;
53 | letter-spacing: 6.5px;
54 | }
55 | .leaderboard header .leaderboard__title--bottom {
56 | font-size: 10px;
57 | font-weight: 500;
58 | letter-spacing: 3.55px;
59 | opacity: 0.65;
60 | transform: translateY(-2px);
61 | }
62 | .leaderboard header .leaderboard__icon {
63 | fill: #fff;
64 | opacity: 0.85;
65 | width: 70px;
66 | position: absolute;
67 | top: 10%;
68 | left: 5%;
69 | /* transform: translate(-140%, -50%); */
70 | }
71 | .leaderboard__profiles {
72 | /* background-color: #00000085; */
73 | /* border-radius: 0 0 12px 12px; */
74 | padding: 4px 11px 20px;
75 | display: flow-root;
76 | row-gap: 8px;
77 | /* width: 48%; */
78 | /* float: right; */
79 | height: 50%;
80 | margin-top: 16vh;
81 |
82 | }
83 | .leaderboard__profile {
84 | display: grid;
85 | grid-template-columns: 0.1fr 3fr 0.2fr;
86 | align-items: center;
87 | padding: 5px 9px 15px 9px;
88 | overflow: hidden;
89 | border-radius: 5px;
90 | box-shadow: 0 1px 1px 1px rgb(134 134 134 / 48%);
91 | cursor: pointer;
92 | transition: transform 0.25s cubic-bezier(0.7, 0.98, 0.86, 0.98), box-shadow 0.25s cubic-bezier(0.7, 0.98, 0.86, 0.98);
93 | background-color: #2e3033;
94 | width: 92% !important;
95 | float: left;
96 | position: relative;
97 | margin: 4px;
98 | height: 65px;
99 | direction: ltr;
100 | }
101 | .leaderboard__profile:hover {
102 | transform: scale(1.05);
103 | box-shadow: 0 9px 47px 11px rgba(51, 51, 51, 0.18);
104 | }
105 | .leaderboard__picture {
106 | /* max-width: 150%; */
107 | width: 40px;
108 | border-radius: 50%;
109 | box-shadow: 0 0 0 8px #79797938, 0 0 0 4px #ecececa8;
110 | }
111 | .leaderboard__name {
112 | color: #d0d0d0;
113 | font-weight: 500;
114 | font-size: 1.5vh;
115 | letter-spacing: 0.64px;
116 | margin-left: 32px;
117 | }
118 | .leaderboard__value {
119 | color: #35d8ac;
120 | font-weight: 700;
121 | font-size: 15px;
122 | text-align: right;
123 | }
124 | .leaderboard__value > span {
125 | opacity: 0.8;
126 | font-weight: 600;
127 | font-size: 13px;
128 | margin-left: 3px;
129 | }
130 |
131 | body {
132 | margin: 0;
133 | background-color: #ffffff00;
134 | /* display: grid; */
135 | /* height: 100vh; */
136 | place-items: center;
137 | font-family: "Source Sans Pro", sans-serif;
138 | position: absolute;
139 | left: 5%;
140 | right: 0;
141 | width: 30vw;
142 | top: 15%;
143 | /* height: 100%; */
144 | overflow: hidden;
145 | }
146 |
147 | /* The Modal (background) */
148 | .modal {
149 | overflow: revert;
150 | display: none;
151 | position: fixed;
152 | z-index: 1;
153 | padding-top: 5vh;
154 | left: 32%;
155 | /* left: 0; */
156 | top: 0;
157 | width: 70%;
158 | height: 100%;
159 | border-radius: 10px;
160 | }
161 |
162 | /* Modal Content */
163 | .modal-content {
164 | position: relative;
165 | background-color: rgb(81 82 84);
166 | margin: auto;
167 | padding: 0;
168 | border: 1px solid #888;
169 | width: 55%;
170 | box-shadow: 0 4px 8px 0 rgb(0 0 0 / 20%), 0 6px 20px 0 rgb(0 0 0 / 19%);
171 | -webkit-animation-name: animatetop;
172 | -webkit-animation-duration: 0.4s;
173 | animation-name: animatetop;
174 | animation-duration: 0.4s;
175 | color: #2097ff;
176 | border-radius: 20px;
177 | }
178 |
179 | /* Add Animation */
180 | @-webkit-keyframes animatetop {
181 | from {top:-300px; opacity:0}
182 | to {top:0; opacity:1}
183 | }
184 |
185 | @keyframes animatetop {
186 | from {top:-300px; opacity:0}
187 | to {top:0; opacity:1}
188 | }
189 |
190 | /* The Close Button */
191 | .close {
192 | color: white;
193 | float: right;
194 | font-size: 28px;
195 | font-weight: bold;
196 | }
197 |
198 | .close:hover,
199 | .close:focus {
200 | color: #000;
201 | text-decoration: none;
202 | cursor: pointer;
203 | }
204 |
205 | h2 {
206 | margin: 5px;
207 | font-size: 15px !important;
208 | }
209 | .modal-header {
210 | padding: 5px 5px;
211 | color: white;
212 | background: linear-gradient(
213 | 90deg
214 | , rgb(28 28 29) 0%, rgb(28 32 37 / 92%) 35%, rgb(66 69 72) 100%);
215 | border-radius: 20px;
216 | border-bottom-right-radius: 0;
217 | border-bottom-left-radius: 0;
218 | }
219 |
220 | .modal-body {padding: 2px 16px;}
221 |
222 | form {max-width: 99%;padding: 10px 10px;background: #27262673;border-radius: 8px;}
223 |
224 | h1 {
225 | width: 100%;
226 | font-size:20px;
227 | margin: 0 0 30px 0;
228 | text-align: center;
229 | }
230 |
231 | input[type="text"], input[type="password"], input[type="date"], input[type="datetime"], input[type="email"], input[type="number"], input[type="search"], input[type="tel"], input[type="time"], input[type="url"], textarea, select {background: rgba(255,255,255,0.1);
232 | border: none;
233 | font-size: 16px;
234 | height: 30px;
235 | margin: 0;
236 | outline: 0;
237 | padding: 8px;
238 | width: 45%;
239 | background-color: #0000003d;
240 | color: #8a97a0;
241 | box-shadow: 0 1px 0 rgb(0 0 0 / 3%) inset;
242 | margin-bottom: 30px;
243 | }
244 | button {padding: 0.6vh;color: #FFF;background-color: #505050;font-size: 11px;text-align: center;font-style: normal;border-radius: 5px;width: 100px;border: 1px solid #333333;border-width: 1px 1px 3px;box-shadow: 0 -1px 0 rgba(255,255,255,0.1) inset;margin-bottom: 1px;position: absolute;top: 122%;left: 15%;/* height: 50px; */margin-left: 2%;}
245 |
246 |
247 | body::-webkit-scrollbar {
248 | width: 2em;
249 | }
250 |
251 | body::-webkit-scrollbar-track {
252 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
253 | }
254 |
255 | body::-webkit-scrollbar-thumb {
256 | background-color: darkgrey;
257 | outline: 1px solid slategrey;
258 | }
259 | ::-webkit-scrollbar {
260 | width: 4px;
261 | }
262 | ::-webkit-scrollbar-thumb {
263 | border-radius: 30px;
264 | background: -webkit-gradient(
265 | linear,
266 | left top,
267 | left bottom,
268 | from(#686d71),
269 | to(#040c02)
270 | );
271 | }
272 |
273 | .leaderboard {
274 | /* box-shadow: 0 0 40px -10px rgba(0, 0, 0, 0.4); */
275 | }
276 | .jobname {
277 | float: left !important;
278 | position: absolute !important;
279 | left: 2.9vw !important;
280 | font-weight: 700 !important;
281 | font-size: 12px !important;
282 | top: 0.3vh !important;
283 | }
284 | .admin {
285 | float: left !important;
286 | position: absolute !important;
287 | left: 0.3vw !important;
288 | font-weight: 700 !important;
289 | font-size: 15px !important;
290 | top: 15% !important;
291 | color: rgb(10, 206, 75) !important;
292 | }
293 |
294 | .discordname {
295 | float: left;
296 | position: absolute;
297 | left: 3vw;
298 | font-weight: 700;
299 | font-size: 1vh;
300 | bottom: 0.5vh;
301 | }
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 | .card-container {
318 | display: grid;
319 | grid-auto-rows: 2.7fr;
320 | grid-template-columns: repeat(auto-fill, minmax(312px, 1fr));
321 | max-width: 1248px;
322 | margin: auto;
323 | }
324 |
325 | @media screen and (max-width: 1264px) {
326 | .card-container {
327 | max-width: 936px;
328 | }
329 | }
330 |
331 | @media screen and (max-width: 952px) {
332 | .card-container {
333 | max-width: 624px;
334 | }
335 | }
336 |
337 | .card {
338 | position: relative;
339 | color: white;
340 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
341 | Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
342 | border-radius: 14px;
343 | text-align: center;
344 | background: rgb(11 11 16 / 68%);
345 | display: grid;
346 | grid-template-columns: 280px;
347 | grid-template-rows: 2fr 0.7fr;
348 | width: 95%;
349 | box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.9);
350 | transition: 0.5s ease;
351 | margin: 16px;
352 | min-width: 250px;
353 | height: 500px;
354 | }
355 |
356 | @media screen and (max-width: 640px) {
357 | .card {
358 | width: 100%;
359 | grid-template-columns: repeat(auto-fill, minmax(100%, 1fr));
360 | }
361 |
362 | .card-container {
363 | grid-template-columns: calc(100% - 32px);
364 | width: calc(100% - 32px);
365 | }
366 | }
367 |
368 | .card.light:nth-last-of-type(odd),
369 | .card.dark:nth-last-of-type(even) {
370 | --fore: white;
371 | --back: rgba(18, 18, 49, 0.987);
372 | }
373 |
374 | .card.light:nth-last-of-type(even),
375 | .card.dark:nth-last-of-type(odd) {
376 | --fore: black;
377 | --back: white;
378 | }
379 |
380 | .card .card-header {
381 | position: absolute;
382 | border-radius: 14px;
383 | top: 0;
384 | left: 0;
385 | right: 0;
386 | display: flex;
387 | justify-content: space-between;
388 | padding: 20px 16px;
389 | }
390 |
391 | .card-header i {
392 | color: var(--fore);
393 | }
394 |
395 | .card-header .options > i {
396 | margin-left: 10px;
397 | }
398 |
399 | .card .card-text {
400 | color: var(--fore);
401 | height: fit-content;
402 | width: 25vw;
403 | margin: auto;
404 | margin-top: 32px;
405 | }
406 |
407 | .card-text .card-img {
408 | position: relative;
409 | background: url("https://cultivatedculture.com/wp-content/uploads/2019/12/LinkedIn-Profile-Picture-Example-Madeline-Mann.jpeg");
410 | height: 150px;
411 | width: 150px;
412 | background-size: cover;
413 | border-radius: 50%;
414 | margin: auto;
415 | box-shadow: 2px 5px 15px rgb(0 0 0 / 90%);
416 | }
417 |
418 | .card-img i {
419 | position: absolute;
420 | bottom: 6px;
421 | right: 4px;
422 | background: linear-gradient(90deg, #d400ff 0%, #d108a5 36%, #ff006a 100%);
423 | border-radius: 15px;
424 | }
425 |
426 | .card-text h2 {
427 | margin: 8px;
428 | margin-bottom: 2px;
429 | font-size: 18px;
430 | }
431 |
432 | .card-text h5 {
433 | margin: 0;
434 | color: grey;
435 | font-size: 8px;
436 | text-transform: uppercase;
437 | letter-spacing: 2px;
438 | }
439 |
440 | .card-text p {
441 | font-weight: 400;
442 | font-size: 11px;
443 | color: var(--fore);
444 | margin: 12px auto;
445 | width: 100%;
446 | }
447 |
448 | .card-text button {
449 | border-radius: 20px;
450 | text-transform: uppercase;
451 | border: none;
452 | padding: 10px;
453 | width: 180px;
454 | font-weight: 700;
455 | color: white;
456 | margin-top: 20px;
457 | background-image: linear-gradient(
458 | 90deg,
459 | #36a4f3 0%,
460 | #0d559e 36%,
461 | #1a5fb5 100%
462 | );
463 | position: unset;
464 | }
465 |
466 | .card-stats {
467 | display: flex;
468 | justify-content: space-around;
469 | border-bottom-left-radius: 15px;
470 | border-bottom-right-radius: 15px;
471 | position: absolute;
472 | left: 0;
473 | right: 0;
474 | bottom: 30px;
475 | padding: 4px 16px;
476 | }
477 |
478 | .card-stats .stats {
479 | display: flex;
480 | align-items: center;
481 | justify-content: center;
482 | flex-direction: column;
483 | padding: 10px 0;
484 | color: var(--fore);
485 | }
486 |
487 | .card-stats .type {
488 | font-size: 9px;
489 | font-weight: 400;
490 | color: grey;
491 | letter-spacing: 2px;
492 | text-transform: uppercase;
493 | }
494 |
495 | .card-stats .value {
496 | font-size: 16px;
497 | font-weight: 500;
498 | }
499 |
500 | .socials i {
501 | margin-left: 10px;
502 | font-size: 24px;
503 | background-clip: text;
504 | background: -webkit-linear-gradient(0deg, #d400ff 0%, #ff006a 100%);
505 | -webkit-background-clip: text;
506 | -webkit-text-fill-color: transparent;
507 | }
508 |
509 | .card:hover {
510 | transform: scale(1.1);
511 | }
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 | .container {
520 | display: flex;
521 | flex-direction: column;
522 | align-items: center;
523 | justify-content: center;
524 | width: 100%;
525 | height: 100%;
526 | }
527 |
528 | [type="radio"] {
529 | z-index: -1;
530 | position: absolute;
531 | opacity: 0;
532 | }
533 | [type="radio"]:checked ~ label {
534 | border-color: #0e80b7;
535 | background-color: rgba(97, 154, 234, 0.16);
536 | color: #FFF;
537 | border-style: unset;
538 | }
539 | [type="radio"]:checked ~ label:before {
540 | will-change: transform, border-width, border-color;
541 | -webkit-animation: bubble 1s ease-in;
542 | animation: bubble 1s ease-in;
543 | }
544 | [type="radio"]:checked ~ label:after {
545 | will-change: opacity, box-shadow;
546 | -webkit-animation: sparkles 700ms ease-in-out;
547 | animation: sparkles 700ms ease-in-out;
548 | }
549 | [type="radio"]:checked ~ label > span {
550 | will-change: transform;
551 | border: 0;
552 | background-image: linear-gradient(to top right, #6E89FF, #4363EE);
553 | -webkit-animation: radio 400ms cubic-bezier(0.17, 0.89, 0.32, 1.49);
554 | animation: radio 400ms cubic-bezier(0.17, 0.89, 0.32, 1.49);
555 | }
556 | [type="radio"]:checked ~ label > span:after {
557 | content: "";
558 | position: absolute;
559 | top: 50%;
560 | left: 50%;
561 | transform: translate(-50%, -50%);
562 | width: 0;
563 | height: 0;
564 | border-radius: 10px;
565 | background-color: #fff;
566 | }
567 | [type="radio"]:checked ~ label .job {
568 | will-change: box-shadow;
569 | -webkit-animation: job 500ms ease-in-out forwards;
570 | animation: job 500ms ease-in-out forwards;
571 | }
572 | [type="radio"]:checked ~ label .job:after {
573 | will-change: transform;
574 | -webkit-animation: shine 500ms ease-in forwards;
575 | animation: shine 500ms ease-in forwards;
576 | -webkit-animation-delay: 100ms;
577 | animation-delay: 100ms;
578 | }
579 |
580 | label {
581 | /* background: #222; */
582 | position: relative;
583 | display: grid;
584 | align-items: center;
585 | grid-template-columns: 20px auto 100px;
586 | grid-gap: 20px;
587 | width: 320px;
588 | height: 62px;
589 | padding: 0 20px;
590 | border-radius: 6px;
591 | border: 2px solid transparent;
592 | background-color: transparent;
593 | transition: all 300ms ease-in;
594 | font-size: 20px;
595 | text-transform: capitalize;
596 | color: #fff;
597 | }
598 | label:hover {
599 | border-color: #4062F6;
600 | background-color: rgba(97, 154, 234, 0.16);
601 | }
602 | label:before, label:after {
603 | position: absolute;
604 | left: 29px;
605 | border-radius: 50%;
606 | content: '';
607 | }
608 | label:before {
609 | margin: -2rem;
610 | border: solid 2rem #545461;
611 | width: 4rem;
612 | height: 4rem;
613 | transform: scale(0);
614 | }
615 | label:after {
616 | margin: -0.1875rem;
617 | width: 0.375rem;
618 | height: 0.375rem;
619 | box-shadow: 0.32476rem -2.6875rem 0 -0.1875rem #ff8080, -0.32476rem -2.3125rem 0 -0.1875rem #ffed80, 2.30366rem -1.42172rem 0 -0.1875rem #ffed80, 1.6055rem -1.69573rem 0 -0.1875rem #a4ff80, 2.54785rem 0.91464rem 0 -0.1875rem #a4ff80, 2.32679rem 0.19796rem 0 -0.1875rem #80ffc8, 0.87346rem 2.56226rem 0 -0.1875rem #80ffc8, 1.29595rem 1.94258rem 0 -0.1875rem #80c8ff, -1.45866rem 2.28045rem 0 -0.1875rem #80c8ff, -0.71076rem 2.2244rem 0 -0.1875rem #a480ff, -2.69238rem 0.28141rem 0 -0.1875rem #a480ff, -2.18226rem 0.8312rem 0 -0.1875rem #ff80ed, -1.89869rem -1.92954rem 0 -0.1875rem #ff80ed, -2.01047rem -1.18791rem 0 -0.1875rem #ff8080;
620 | }
621 | label > span {
622 | position: relative;
623 | display: inline-flex;
624 | width: 20px;
625 | height: 20px;
626 | border-radius: 20px;
627 | border: 2px solid #1045a5;
628 | background: #121517;
629 | border-color: #1045a5;
630 | }
631 |
632 | .job {
633 | position: relative;
634 | width: 243px;
635 | height: 152px;
636 | padding: 22px 24px;
637 | border-radius: 16px;
638 | box-shadow: 0 1px 0 0 rgba(255, 255, 255, 0.25);
639 | background-image: linear-gradient(45deg, #FFF, #CDCDCD);
640 | overflow: hidden;
641 | }
642 | .job:before {
643 | content: "";
644 | position: absolute;
645 | top: 0;
646 | bottom: 0;
647 | left: 0;
648 | right: 0;
649 | background: url("") no-repeat;
650 | }
651 | .job:after {
652 | content: "";
653 | position: absolute;
654 | top: 0;
655 | bottom: 0;
656 | width: 40px;
657 | transform: translateX(-70px);
658 | background-image: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0));
659 | }
660 | .job--blue {
661 | background-image: linear-gradient(45deg, #748DFB, #3859E8);
662 | }
663 | .job--dark {
664 | background-image: linear-gradient(45deg, #616161, #484848);
665 | }
666 | .job--sm {
667 | position: absolute;
668 | right: -76px;
669 | transform: scale(0.24);
670 | }
671 |
672 | .text__row {
673 | display: grid;
674 | grid-template-columns: 54px 64px;
675 | grid-gap: 6px;
676 | }
677 | .text__row:last-of-type {
678 | grid-template-columns: 45px 54px;
679 | margin-top: 7px;
680 | }
681 | .text__loader {
682 | height: 13px;
683 | border-radius: 2px;
684 | background-color: rgba(0, 0, 0, 0.4);
685 | }
686 |
687 | .option:not(:last-child) {
688 | margin-bottom: 4px;
689 | }
690 |
691 | @-webkit-keyframes radio {
692 | 0%, 17.5% {
693 | transform: scale(0);
694 | }
695 | }
696 |
697 | @keyframes radio {
698 | 0%, 17.5% {
699 | transform: scale(0);
700 | }
701 | }
702 | @-webkit-keyframes job {
703 | 0% {
704 | box-shadow: 0 1px 0 0 rgba(255, 255, 255, 0.25);
705 | transform: scale(0.24);
706 | }
707 | 45% {
708 | box-shadow: 0 12px 32px 0 rgba(0, 0, 0, 0.5);
709 | transform: scale(0.25);
710 | }
711 | 100% {
712 | box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.4);
713 | transform: scale(0.24);
714 | }
715 | }
716 | @keyframes job {
717 | 0% {
718 | box-shadow: 0 1px 0 0 rgba(255, 255, 255, 0.25);
719 | transform: scale(0.24);
720 | }
721 | 45% {
722 | box-shadow: 0 12px 32px 0 rgba(0, 0, 0, 0.5);
723 | transform: scale(0.25);
724 | }
725 | 100% {
726 | box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.4);
727 | transform: scale(0.24);
728 | }
729 | }
730 | @-webkit-keyframes shine {
731 | from {
732 | transform: translateX(-70px) rotate(10deg);
733 | }
734 | to {
735 | transform: translateX(300px) rotate(10deg);
736 | }
737 | }
738 | @keyframes shine {
739 | from {
740 | transform: translateX(-70px) rotate(10deg);
741 | }
742 | to {
743 | transform: translateX(300px) rotate(10deg);
744 | }
745 | }
746 | @-webkit-keyframes bubble {
747 | 15% {
748 | transform: scale(1);
749 | border-color: #545461;
750 | border-width: 2rem;
751 | }
752 | 30%, 100% {
753 | transform: scale(1);
754 | border-color: #545461;
755 | border-width: 0;
756 | }
757 | }
758 | @keyframes bubble {
759 | 15% {
760 | transform: scale(1);
761 | border-color: #545461;
762 | border-width: 2rem;
763 | }
764 | 30%, 100% {
765 | transform: scale(1);
766 | border-color: #545461;
767 | border-width: 0;
768 | }
769 | }
770 | @-webkit-keyframes sparkles {
771 | 0%, 10% {
772 | opacity: 0;
773 | transform: scale(0);
774 | }
775 | 15% {
776 | opacity: 1;
777 | transform: scale(1.2) rotate(-20deg);
778 | box-shadow: 0.32476rem -2.1875rem 0 0rem #ff8080, -0.32476rem -1.8125rem 0 0rem #ffed80, 1.91274rem -1.10998rem 0 0rem #ffed80, 1.21459rem -1.38398rem 0 0rem #a4ff80, 2.06039rem 0.80338rem 0 0rem #a4ff80, 1.83932rem 0.0867rem 0 0rem #80ffc8, 0.65652rem 2.11178rem 0 0rem #80ffc8, 1.07901rem 1.4921rem 0 0rem #80c8ff, -1.24172rem 1.82996rem 0 0rem #80c8ff, -0.49382rem 1.77391rem 0 0rem #a480ff, -2.20492rem 0.17015rem 0 0rem #a480ff, -1.69479rem 0.71994rem 0 0rem #ff80ed, -1.50777rem -1.61779rem 0 0rem #ff80ed, -1.61955rem -0.87617rem 0 0rem #ff8080;
779 | }
780 | }
781 | @keyframes sparkles {
782 | 0%, 10% {
783 | opacity: 0;
784 | transform: scale(0);
785 | }
786 | 15% {
787 | opacity: 1;
788 | transform: scale(1.2) rotate(-20deg);
789 | box-shadow: 0.32476rem -2.1875rem 0 0rem #ff8080, -0.32476rem -1.8125rem 0 0rem #ffed80, 1.91274rem -1.10998rem 0 0rem #ffed80, 1.21459rem -1.38398rem 0 0rem #a4ff80, 2.06039rem 0.80338rem 0 0rem #a4ff80, 1.83932rem 0.0867rem 0 0rem #80ffc8, 0.65652rem 2.11178rem 0 0rem #80ffc8, 1.07901rem 1.4921rem 0 0rem #80c8ff, -1.24172rem 1.82996rem 0 0rem #80c8ff, -0.49382rem 1.77391rem 0 0rem #a480ff, -2.20492rem 0.17015rem 0 0rem #a480ff, -1.69479rem 0.71994rem 0 0rem #ff80ed, -1.50777rem -1.61779rem 0 0rem #ff80ed, -1.61955rem -0.87617rem 0 0rem #ff8080;
790 | }
791 | }
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 | .season_tabs {
800 | position: relative;
801 | min-height: 360px;
802 | clear: both;
803 | margin: 5px 0;
804 | height: 600px;
805 | }
806 | .season_tab {
807 | float: left;
808 | clear: both;
809 | width: 8vw;
810 | /* background: #222; */
811 | /* height: 50%; */
812 | padding-bottom: 10px;
813 | }
814 | .season_tab label {
815 | background: #0e0e0e73;
816 | padding: 10px;
817 | border: 1px solid #ccc;
818 | margin-left: -1px;
819 | font-size: 15px;
820 | vertical-align: middle;
821 | position: relative;
822 | left: 1px;
823 | color: #fff;
824 | width: 264px;
825 | height: 22vh;
826 | display: table-cell;
827 | border-style: unset;
828 | }
829 | .season_tab [type=radio] {
830 | display: none;
831 | }
832 | .season_content {
833 | position: absolute;
834 | top: 0;
835 | left: 29%;
836 | background: #08080814;
837 | right: 0;
838 | bottom: 0;
839 | display: none;
840 | padding: 10px;
841 | /* border: 1px solid #ccc; */
842 | height: 550px;
843 | overflow: scroll;
844 | }
845 | .season_content span {
846 | animation: 0.5s ease-out 0s 1 slideInFromTop;
847 | }
848 | [type=radio]:checked ~ label {
849 | background: #141415db;
850 | border-bottom: 2px solid #8bc34a;
851 | z-index: 2;
852 | }
853 | [type=radio]:checked ~ label ~ .season_content {
854 | z-index: 1;
855 | display: block;
856 | }
857 |
858 | /*