forked from Simnation/Main
ed
This commit is contained in:
parent
993501dc99
commit
5f0d428070
18 changed files with 1236 additions and 49 deletions
BIN
resources/[Developer]/[Nordi]/kyaktrailer/trailersmall.yft
Normal file
BIN
resources/[Developer]/[Nordi]/kyaktrailer/trailersmall.yft
Normal file
Binary file not shown.
BIN
resources/[Developer]/[Nordi]/kyaktrailer/trailersmall.ytd
Normal file
BIN
resources/[Developer]/[Nordi]/kyaktrailer/trailersmall.ytd
Normal file
Binary file not shown.
BIN
resources/[Developer]/[Nordi]/kyaktrailer/trailersmall_hi.yft
Normal file
BIN
resources/[Developer]/[Nordi]/kyaktrailer/trailersmall_hi.yft
Normal file
Binary file not shown.
BIN
resources/[Developer]/[Nordi]/snipe-sitting-master.zip
Normal file
BIN
resources/[Developer]/[Nordi]/snipe-sitting-master.zip
Normal file
Binary file not shown.
|
@ -51,42 +51,12 @@ CodeStudio.Products = {
|
|||
itemPrice = 2,
|
||||
itemInfo = "Refreshing water",
|
||||
},
|
||||
['ecola_zero_dose'] = {
|
||||
itemName = "E-Cola Zero Dose",
|
||||
['pack_ecola'] = {
|
||||
itemName = "Packet E-Cola Dosen",
|
||||
itemStock = 50,
|
||||
itemPrice = 2,
|
||||
itemInfo = "Fizzy cola with a twist",
|
||||
},
|
||||
['ecola_dose'] = {
|
||||
itemName = "E-Cola Dose",
|
||||
itemStock = 50,
|
||||
itemPrice = 2,
|
||||
itemInfo = "Fizzy cola with a twist",
|
||||
},
|
||||
['sprunk_zero_dose'] = {
|
||||
itemName = "Sprunk Zero Dose",
|
||||
itemStock = 50,
|
||||
itemPrice = 2,
|
||||
itemInfo = "Fizzy cola with a twist",
|
||||
},
|
||||
['sprunk_dose'] = {
|
||||
itemName = "Sprunk Dose",
|
||||
itemStock = 50,
|
||||
itemPrice = 2,
|
||||
itemInfo = "Fizzy cola with a twist",
|
||||
},
|
||||
['orange_o_tang_zero_dose'] = {
|
||||
itemName = "Orange O Tang Zero Dose",
|
||||
itemStock = 50,
|
||||
itemPrice = 2,
|
||||
itemInfo = "Fizzy cola with a twist",
|
||||
},
|
||||
['orange_o_tang_dose'] = {
|
||||
itemName = "Orange O Tang Dose",
|
||||
itemStock = 50,
|
||||
itemPrice = 2,
|
||||
itemInfo = "Fizzy cola with a twist",
|
||||
},
|
||||
itemPrice = 20,
|
||||
itemInfo = "",
|
||||
},
|
||||
['ecola_zero_flasche'] = {
|
||||
itemName = "E-Cola Zero Flasche",
|
||||
itemStock = 50,
|
||||
|
@ -123,12 +93,6 @@ CodeStudio.Products = {
|
|||
itemPrice = 4,
|
||||
itemInfo = "Fizzy cola with a twist",
|
||||
},
|
||||
['junk_energy'] = {
|
||||
itemName = "Junk Energy",
|
||||
itemStock = 50,
|
||||
itemPrice = 2,
|
||||
itemInfo = "Dose mit Engery",
|
||||
},
|
||||
['munky_juice'] = {
|
||||
itemName = "Munky Juice",
|
||||
itemStock = 50,
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 516 KiB |
2
resources/[inventory]/muhaddil-machines/.gitattributes
vendored
Normal file
2
resources/[inventory]/muhaddil-machines/.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
21
resources/[inventory]/muhaddil-machines/LICENSE
Normal file
21
resources/[inventory]/muhaddil-machines/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024 Muhaddil
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
53
resources/[inventory]/muhaddil-machines/NUI/NUI.html
Normal file
53
resources/[inventory]/muhaddil-machines/NUI/NUI.html
Normal file
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Vending Machine</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="vending-container">
|
||||
<h1>Elige un producto</h1>
|
||||
<div id="items-list"></div>
|
||||
<button id="close-btn">Cerrar</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.addEventListener('message', function (event) {
|
||||
var data = event.data;
|
||||
|
||||
if (data.action == 'open') {
|
||||
document.getElementById('vending-container').style.display = 'block';
|
||||
var itemsList = document.getElementById('items-list');
|
||||
itemsList.innerHTML = '';
|
||||
|
||||
data.items.forEach(function (item) {
|
||||
var itemDiv = document.createElement('div');
|
||||
itemDiv.textContent = item.label + ' - $' + item.price;
|
||||
itemDiv.onclick = function () {
|
||||
fetch('https://muhaddil-machines/selectItem', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
itemName: item.name,
|
||||
itemPrice: item.price,
|
||||
machineName: data.machineName
|
||||
})
|
||||
}).then(res => res.json());
|
||||
};
|
||||
itemsList.appendChild(itemDiv);
|
||||
});
|
||||
} else if (data.action == 'close') {
|
||||
document.getElementById('vending-container').style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('close-btn').onclick = function () {
|
||||
fetch('https://muhaddil-machines/close', {
|
||||
method: 'POST',
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
61
resources/[inventory]/muhaddil-machines/README.md
Normal file
61
resources/[inventory]/muhaddil-machines/README.md
Normal file
|
@ -0,0 +1,61 @@
|
|||
# muhaddil_machines (FiveM)
|
||||
|
||||
A FiveM script that adds several machines to improve user experience.
|
||||
|
||||
## Features
|
||||
|
||||
- Vending machines for drinks and snacks
|
||||
- Water coolers with a timeout feature
|
||||
- Food stands with various items
|
||||
- News sellers with newspapers
|
||||
- Custom animations for interactions
|
||||
- Configurable framework support (ESX and QBCore)
|
||||
- Debug mode for development
|
||||
- Auto version checker
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone or download the repository.
|
||||
2. Add the resource to your `resources` folder.
|
||||
3. Add `start muhaddil_machines` to your `server.cfg`.
|
||||
|
||||
## Configuration
|
||||
|
||||
You can configure the script by editing the [config.lua](config.lua) file. Here are some of the options available:
|
||||
|
||||
- `DebugMode`: Enable or disable debug mode.
|
||||
- `Framework`: Choose between 'esx' or 'qb'.
|
||||
- `UseOXNotifications`: Use OX notifications or frameworks.
|
||||
- `ThirstRemoval`: Amount of thirst removed by water coolers.
|
||||
- `WaterCoolerTimeout`: Timeout duration for water coolers.
|
||||
- `VisibleProp`: Show or hide props during animations.
|
||||
- `ShowWaitNotification`: Show notification when water cooler is on timeout.
|
||||
- `MaxDrinksBeforeKill`: Maximum drinks before player death.
|
||||
- `CountDrinksPlace`: Count drinks before or after drinking.
|
||||
|
||||
## Usage
|
||||
|
||||
### Vending Machines
|
||||
|
||||
Interact with vending machines to buy drinks and snacks. The available items and their prices are configured in the [config.lua](config.lua) file.
|
||||
|
||||
### Water Coolers
|
||||
|
||||
Interact with water coolers to drink water. The script includes a timeout feature to prevent excessive use.
|
||||
|
||||
### Food Stands
|
||||
|
||||
Interact with food stands to buy various food items. The available items and their prices are configured in the [config.lua](config.lua) file.
|
||||
|
||||
### News Sellers
|
||||
|
||||
Interact with news sellers to buy newspapers. The available items and their prices are configured in the [config.lua](config.lua) file.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
||||
|
||||
<p>
|
||||
<img src="https://i.ibb.co/zPZpZmR/imagen.png" width="400" style="display:inline-block; margin-right: 10px;" />
|
||||
<img src="https://i.ibb.co/BP9Cppn/imagen.png" width="400" style="display:inline-block;" />
|
||||
</p>
|
472
resources/[inventory]/muhaddil-machines/client.lua
Normal file
472
resources/[inventory]/muhaddil-machines/client.lua
Normal file
|
@ -0,0 +1,472 @@
|
|||
local buying = false -- Variable to prevent multiple purchases
|
||||
local LastWaterCoolerUse = 0 -- Variable to prevent multiple uses of the water cooler
|
||||
local TimeoutDuration = Config.WaterCoolerTimeout * 1000 -- Timeout duration for water coolers in milliseconds
|
||||
local DrinkCount = 0 -- Variable to count the number of drinks
|
||||
|
||||
if Config.Framework == "esx" then
|
||||
ESX = exports['es_extended']:getSharedObject()
|
||||
elseif Config.Framework == "qb" then
|
||||
QBCore = exports['qb-core']:GetCoreObject()
|
||||
elseif Config.Framework == "ox" then
|
||||
Ox = require '@ox_core.lib.init'
|
||||
else
|
||||
ESX = exports['es_extended']:getSharedObject()
|
||||
end
|
||||
|
||||
function DebugPrint(...) -- Debug print function
|
||||
if Config.DebugMode then
|
||||
print(...)
|
||||
end
|
||||
end
|
||||
|
||||
function Notify(msgtitle, msg, time, type2) -- Notification function
|
||||
if Config.UseOXNotifications then
|
||||
lib.notify({
|
||||
title = msgtitle,
|
||||
description = msg,
|
||||
showDuration = true,
|
||||
type = type2,
|
||||
style = {
|
||||
backgroundColor = 'rgba(0, 0, 0, 0.75)',
|
||||
color = 'rgba(255, 255, 255, 1)',
|
||||
['.description'] = {
|
||||
color = '#909296',
|
||||
backgroundColor = 'transparent'
|
||||
}
|
||||
}
|
||||
})
|
||||
else
|
||||
if Config.Framework == 'qb' then
|
||||
QBCore.Functions.Notify(msg, type2, time)
|
||||
elseif Config.Framework == 'esx' then
|
||||
TriggerEvent('esx:showNotification', msg, type2, time)
|
||||
elseif Config.Framework == 'ox' then
|
||||
lib.notify({
|
||||
title = msgtitle,
|
||||
description = msg,
|
||||
showDuration = true,
|
||||
type = type2,
|
||||
style = {
|
||||
backgroundColor = 'rgba(0, 0, 0, 0.75)',
|
||||
color = 'rgba(255, 255, 255, 1)',
|
||||
['.description'] = {
|
||||
color = '#909296',
|
||||
backgroundColor = 'transparent'
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RegisterNetEvent("muhaddil-machines:Notify")
|
||||
AddEventHandler("muhaddil-machines:Notify", function(msgtitle, msg, time, type)
|
||||
Notify(msgtitle, msg, time, type)
|
||||
end)
|
||||
|
||||
local function loadAnimDict(animDict)
|
||||
RequestAnimDict(animDict)
|
||||
while not HasAnimDictLoaded(animDict) do
|
||||
Citizen.Wait(0)
|
||||
end
|
||||
end
|
||||
|
||||
local function playAnimation(ped, animDict, animName)
|
||||
loadAnimDict(animDict)
|
||||
TaskPlayAnim(ped, animDict, animName, 8.0, 5.0, -1, 1, 1, false, false, false)
|
||||
Citizen.Wait(4500)
|
||||
ClearPedTasks(ped)
|
||||
RemoveAnimDict(animDict)
|
||||
end
|
||||
|
||||
local function vendingAnimation(entity)
|
||||
local ped = PlayerPedId()
|
||||
local position = GetOffsetFromEntityInWorldCoords(entity, 0.0, -0.97, 0.05)
|
||||
local heading = GetEntityHeading(entity)
|
||||
local prop_name = 'ng_proc_sodacan_01a'
|
||||
buying = true
|
||||
|
||||
TaskTurnPedToFaceEntity(ped, entity, -1)
|
||||
if not IsEntityAtCoord(ped, position.x, position.y, position.z, 0.1, 0.0, 0.1, false, true, 0) then
|
||||
TaskGoStraightToCoord(ped, position.x, position.y, position.z, 1.0, 20000, heading, 0.1)
|
||||
Citizen.Wait(1000)
|
||||
end
|
||||
TaskTurnPedToFaceEntity(ped, entity, -1)
|
||||
Citizen.Wait(1000)
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
local playerPed = PlayerPedId()
|
||||
local x, y, z = table.unpack(GetEntityCoords(playerPed))
|
||||
|
||||
if Config.VisibleProp then
|
||||
local prop = CreateObject(GetHashKey(prop_name), x, y, z + 0.2, true, true, true)
|
||||
local boneIndex = GetPedBoneIndex(playerPed, 18905)
|
||||
end
|
||||
|
||||
RequestAmbientAudioBank("VENDING_MACHINE", false)
|
||||
HintAmbientAudioBank("VENDING_MACHINE", 0)
|
||||
if Config.VisibleProp then
|
||||
AttachEntityToEntity(prop, playerPed, boneIndex, 0.12, 0.008, 0.03, 240.0, -60.0, 0.0, true, true, false,
|
||||
true, 1, true)
|
||||
end
|
||||
playAnimation(playerPed, Config.Animations.sodamachines[1], Config.Animations.sodamachines[2])
|
||||
Citizen.Wait(1000)
|
||||
|
||||
ClearPedSecondaryTask(playerPed)
|
||||
if DoesEntityExist(prop) then
|
||||
DeleteObject(prop)
|
||||
end
|
||||
ReleaseAmbientAudioBank()
|
||||
|
||||
buying = false
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
local function showQuantityDialog(item, vendingMachineName, entity)
|
||||
local input = lib.inputDialog("Selecciona la cantidad", {
|
||||
{ type = 'number', label = 'Cantidad', min = 1, max = Config.InputMaxValue, default = 1 }
|
||||
})
|
||||
|
||||
if not input then return end
|
||||
local cantidad = input[1]
|
||||
|
||||
if cantidad and cantidad > 0 then
|
||||
local ped = PlayerPedId()
|
||||
if buying then return end
|
||||
buying = true
|
||||
|
||||
vendingAnimation(entity)
|
||||
|
||||
Citizen.Wait(4500)
|
||||
|
||||
TriggerServerEvent('muhaddil-machines:buy', 'machine', vendingMachineName, item.name, cantidad)
|
||||
else
|
||||
Notify('Error', 'Cantidad no válida', 5000, "error")
|
||||
end
|
||||
|
||||
buying = false
|
||||
end
|
||||
|
||||
local function replacePrice(inputString, price)
|
||||
return inputString:gsub("%%price%%", tostring(price))
|
||||
end
|
||||
|
||||
local function showVendingMenu(vendingMachineName, entity, items)
|
||||
local options = {}
|
||||
|
||||
for _, item in pairs(items) do
|
||||
table.insert(options, {
|
||||
title = replacePrice(item.label, item.price),
|
||||
icon = item.icon or 'fa-solid fa-bottle-water',
|
||||
onSelect = function()
|
||||
if buying then return end
|
||||
showQuantityDialog(item, vendingMachineName, entity)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
lib.registerContext({
|
||||
id = 'vending_menu_' .. vendingMachineName,
|
||||
title = 'Máquina expendedora',
|
||||
canClose = true,
|
||||
options = options
|
||||
})
|
||||
|
||||
lib.showContext('vending_menu_' .. vendingMachineName)
|
||||
end
|
||||
|
||||
local function interactWithWaterCooler(entity)
|
||||
local currentTime = GetGameTimer()
|
||||
|
||||
if Config.ShowWaitNotification then
|
||||
if currentTime - LastWaterCoolerUse < TimeoutDuration then
|
||||
DebugPrint("Debes esperar antes de usar nuevamente la fuente de agua.")
|
||||
Notify('¡Echa el freno madaleno!', 'Relaja, espera un poco antes de volver a usar la máquina', 5000, "error")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if IsAnimated then return end
|
||||
IsAnimated = true
|
||||
LastWaterCoolerUse = currentTime
|
||||
|
||||
local prop_name = 'prop_cs_paper_cup'
|
||||
local ped = PlayerPedId()
|
||||
local position = GetOffsetFromEntityInWorldCoords(entity, 0.0, -0.97, 0.05)
|
||||
local heading = GetEntityHeading(entity)
|
||||
|
||||
if not IsEntityAtCoord(ped, position.x, position.y, position.z, 0.1, 0.1, 0.1, false, true, 0) then
|
||||
TaskGoStraightToCoord(ped, position.x, position.y, position.z, 1.0, 20000, heading, 0.1)
|
||||
Wait(1000)
|
||||
end
|
||||
TaskTurnPedToFaceEntity(ped, entity, -1)
|
||||
|
||||
lib.progressBar({
|
||||
duration = 2000,
|
||||
label = 'Llenado Vaso',
|
||||
})
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
local playerPed = PlayerPedId()
|
||||
local x, y, z = table.unpack(GetEntityCoords(playerPed))
|
||||
local prop = CreateObject(GetHashKey(prop_name), x, y, z + 0.2, true, true, true)
|
||||
local boneIndex = GetPedBoneIndex(playerPed, 18905)
|
||||
AttachEntityToEntity(prop, playerPed, boneIndex, 0.12, 0.008, 0.03, 240.0, -60.0, 0.0, true, true, false, true, 1,
|
||||
true)
|
||||
|
||||
local animDict = 'mp_player_intdrink'
|
||||
local animName = 'loop_bottle'
|
||||
|
||||
playAnimation(playerPed, animDict, animName)
|
||||
|
||||
if Config.CountDrinksPlace == 'before' then
|
||||
DrinkCount = DrinkCount + 1
|
||||
end
|
||||
|
||||
if Config.KillPlayerOnExcess then
|
||||
local warningThreshold = math.ceil(Config.MaxDrinksBeforeKill / 2)
|
||||
print(warningThreshold)
|
||||
|
||||
if DrinkCount >= Config.MaxDrinksBeforeKill then
|
||||
SetEntityHealth(playerPed, 0)
|
||||
Notify('Demasiada agua', 'Has bebido demasiada agua y has muerto.', 5000, "error")
|
||||
DrinkCount = 0
|
||||
elseif DrinkCount >= warningThreshold then
|
||||
Notify('Agua fresca', 'Sigues bebiendo... ten cuidado.', 3000, "info")
|
||||
else
|
||||
Notify('Agua fresca', 'Has tomado un vaso de agua.', 3000, "info")
|
||||
end
|
||||
else
|
||||
Notify('Agua fresca', 'Has tomado un vaso de agua.', 3000, "info")
|
||||
end
|
||||
|
||||
IsAnimated = false
|
||||
ClearPedSecondaryTask(playerPed)
|
||||
DeleteObject(prop)
|
||||
RemoveAnimDict(animDict)
|
||||
|
||||
TriggerServerEvent('muhaddil-machines:RemoveThirst')
|
||||
|
||||
if Config.CountDrinksPlace == 'after' then
|
||||
DrinkCount = DrinkCount + 1
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function WaterCoolerTarget()
|
||||
for waterCoolerName, data in pairs(Config.WaterCoolers) do
|
||||
local options = {
|
||||
{
|
||||
label = "Beber Agua",
|
||||
icon = 'fa-solid fa-glass-water',
|
||||
onSelect = function(d)
|
||||
local entity = d.entity
|
||||
interactWithWaterCooler(entity)
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
exports.ox_target:addModel(joaat(data.model), options)
|
||||
end
|
||||
end
|
||||
|
||||
local function standAnimation(entity)
|
||||
local ped = PlayerPedId()
|
||||
local position = GetOffsetFromEntityInWorldCoords(entity, 0.0, -0.97, 0.05)
|
||||
local heading = GetEntityHeading(entity)
|
||||
buying = true
|
||||
|
||||
TaskTurnPedToFaceEntity(ped, entity, -1)
|
||||
if not IsEntityAtCoord(ped, position.x, position.y, position.z, 0.1, 0.0, 0.1, false, true, 0) then
|
||||
TaskGoStraightToCoord(ped, position.x, position.y, position.z, 1.0, 20000, heading, 0.1)
|
||||
Citizen.Wait(1000)
|
||||
end
|
||||
TaskTurnPedToFaceEntity(ped, entity, -1)
|
||||
Citizen.Wait(1000)
|
||||
|
||||
playAnimation(ped, Config.Animations.stand[1], Config.Animations.stand[2])
|
||||
Citizen.Wait(1000)
|
||||
|
||||
ClearPedSecondaryTask(ped)
|
||||
|
||||
buying = false
|
||||
end
|
||||
|
||||
local function showQuantityDialogStands(item, standName, entity)
|
||||
local input = lib.inputDialog("Selecciona la cantidad", {
|
||||
{ type = 'number', label = 'Cantidad', min = 1, max = Config.InputMaxValue, default = 1 }
|
||||
})
|
||||
|
||||
if not input then return end
|
||||
local cantidad = input[1]
|
||||
|
||||
if cantidad and cantidad > 0 then
|
||||
local ped = PlayerPedId()
|
||||
if buying then return end
|
||||
buying = true
|
||||
|
||||
standAnimation(entity)
|
||||
|
||||
TriggerServerEvent('muhaddil-machines:buy', 'stand', standName, item.name, cantidad)
|
||||
else
|
||||
Notify('Error', 'Cantidad no válida', 5000, "error")
|
||||
end
|
||||
|
||||
buying = false
|
||||
end
|
||||
|
||||
local function standMenu(standName, entity, items)
|
||||
local options = {}
|
||||
|
||||
for _, item in pairs(items) do
|
||||
table.insert(options, {
|
||||
title = replacePrice(item.label, item.price),
|
||||
icon = item.icon or 'fa-solid fa-bottle-water',
|
||||
onSelect = function()
|
||||
if buying then return end
|
||||
showQuantityDialogStands(item, standName, entity)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
lib.registerContext({
|
||||
id = 'stand_menu_' .. standName,
|
||||
title = 'Puesto de Comida',
|
||||
canClose = true,
|
||||
options = options
|
||||
})
|
||||
|
||||
lib.showContext('stand_menu_' .. standName)
|
||||
end
|
||||
|
||||
local function newsAnimation(entity)
|
||||
local ped = PlayerPedId()
|
||||
local position = GetOffsetFromEntityInWorldCoords(entity, 0.0, -0.97, 0.05)
|
||||
local heading = GetEntityHeading(entity)
|
||||
buying = true
|
||||
|
||||
TaskTurnPedToFaceEntity(ped, entity, -1)
|
||||
if not IsEntityAtCoord(ped, position.x, position.y, position.z, 0.0, 0.0, 0.0, false, true, 0) then
|
||||
TaskGoStraightToCoord(ped, position.x, position.y, position.z, 1.0, 20000, heading, 0.1)
|
||||
Citizen.Wait(1000)
|
||||
end
|
||||
TaskTurnPedToFaceEntity(ped, entity, -1)
|
||||
Citizen.Wait(1000)
|
||||
|
||||
loadAnimDict(Config.Animations.newsSellers[1])
|
||||
TaskPlayAnim(ped, Config.Animations.newsSellers[1], Config.Animations.newsSellers[2], 8.0, 5.0, -1, 1, 1, false,
|
||||
false, false)
|
||||
Citizen.Wait(2500)
|
||||
ClearPedTasks(ped)
|
||||
RemoveAnimDict(Config.Animations.newsSellers[1])
|
||||
|
||||
ClearPedSecondaryTask(ped)
|
||||
|
||||
buying = false
|
||||
end
|
||||
|
||||
|
||||
local function showQuantityDialogNews(item, newsName, entity)
|
||||
local input = lib.inputDialog("Selecciona la cantidad", {
|
||||
{ type = 'number', label = 'Cantidad', min = 1, max = Config.InputMaxValue, default = 1 }
|
||||
})
|
||||
|
||||
if not input then return end
|
||||
local cantidad = input[1]
|
||||
|
||||
if cantidad and cantidad > 0 then
|
||||
local ped = PlayerPedId()
|
||||
if buying then return end
|
||||
buying = true
|
||||
|
||||
newsAnimation(entity)
|
||||
|
||||
TriggerServerEvent('muhaddil-machines:buy', 'news', newsName, item.name, cantidad)
|
||||
else
|
||||
Notify('Error', 'Cantidad no válida', 5000, "error")
|
||||
end
|
||||
|
||||
buying = false
|
||||
end
|
||||
|
||||
local function newsMenu(newsName, entity, items)
|
||||
local options = {}
|
||||
|
||||
for _, item in pairs(items) do
|
||||
table.insert(options, {
|
||||
title = replacePrice(item.label, item.price),
|
||||
icon = item.icon or 'fa-solid fa-bottle-water',
|
||||
onSelect = function()
|
||||
if buying then return end
|
||||
showQuantityDialogNews(item, newsName, entity)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
lib.registerContext({
|
||||
id = 'news_menu_' .. newsName,
|
||||
title = 'Venta de Noticias',
|
||||
canClose = true,
|
||||
options = options
|
||||
})
|
||||
|
||||
lib.showContext('news_menu_' .. newsName)
|
||||
end
|
||||
|
||||
local function setupTargeting()
|
||||
for vendingMachineName, data in pairs(Config.machines) do
|
||||
local options = {
|
||||
{
|
||||
label = "Abrir Máquina Expendedora",
|
||||
icon = 'fa-solid fa-basket-shopping',
|
||||
onSelect = function(d)
|
||||
if buying then return end
|
||||
local entity = d.entity
|
||||
showVendingMenu(vendingMachineName, entity, data.items)
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
exports.ox_target:addModel(joaat(data.model), options)
|
||||
end
|
||||
|
||||
for standName, data in pairs(Config.Stands) do
|
||||
local options = {
|
||||
{
|
||||
label = "Abrir Puesto de Comida",
|
||||
icon = 'fa-solid fa-utensils',
|
||||
onSelect = function(d)
|
||||
if buying then return end
|
||||
local entity = d.entity
|
||||
standMenu(standName, entity, data.items)
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
exports.ox_target:addModel(joaat(data.model), options)
|
||||
end
|
||||
|
||||
for newsName, data in pairs(Config.NewsSellers) do
|
||||
local options = {
|
||||
{
|
||||
label = "Abrir Venta de Noticias",
|
||||
icon = 'fa-solid fa-newspaper',
|
||||
onSelect = function(d)
|
||||
if buying then return end
|
||||
local entity = d.entity
|
||||
newsMenu(newsName, entity, data.items)
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
exports.ox_target:addModel(joaat(data.model), options)
|
||||
end
|
||||
end
|
||||
|
||||
CreateThread(function()
|
||||
Wait(100)
|
||||
setupTargeting()
|
||||
WaterCoolerTarget()
|
||||
-- standsTarget()
|
||||
end)
|
314
resources/[inventory]/muhaddil-machines/config.lua
Normal file
314
resources/[inventory]/muhaddil-machines/config.lua
Normal file
|
@ -0,0 +1,314 @@
|
|||
Config = Config or {}
|
||||
|
||||
Config.DebugMode = true -- Enable debug mode
|
||||
Config.Framework = 'qb' -- 'esx', 'qb' or 'ox'
|
||||
Config.UseOXNotifications = true -- Use OX Notifications or framework notifications
|
||||
Config.Inventory = ''-- 'qs', 'ox' or leave blank
|
||||
Config.NewQBInventory = false -- If you're using the new QB Inventory
|
||||
|
||||
Config.ThirstRemoval = 150000 -- Amount of thirst removed by water coolers
|
||||
Config.WaterCoolerTimeout = 30 -- Timeout duration for water coolers in seconds
|
||||
Config.VisibleProp = false -- Show the prop when buying a drink
|
||||
Config.InputMaxValue = 10 -- Maximum value for the input
|
||||
Config.KillPlayerOnExcess = true -- Enable one of the two (WaterCooler)
|
||||
Config.ShowWaitNotification = false -- Enable one of the two (WaterCooler)
|
||||
Config.MaxDrinksBeforeKill = 3 -- (WaterCooler)
|
||||
Config.CountDrinksPlace = 'before' -- 'before' or 'after', it varies in the result of the Config.MaxDrinksBeforeKill (WaterCooler)
|
||||
|
||||
Config.Animations = { -- Animations for the vending machines
|
||||
stand = { -- Stand animations
|
||||
"special_ped@baygor@monologue_2@monologue_2h",
|
||||
"you_can_ignore_me_7"
|
||||
},
|
||||
sodamachines = { -- Soda machine animations
|
||||
"mini@sprunk@first_person",
|
||||
"plyr_buy_drink_pt1"
|
||||
},
|
||||
newsSellers = { -- News seller animations
|
||||
"anim@amb@nightclub@mini@drinking@drinking_shots@ped_c@normal",
|
||||
"pickup"
|
||||
},
|
||||
}
|
||||
|
||||
Config.machines = { -- Vending machines
|
||||
{
|
||||
model = 'prop_vend_soda_02',
|
||||
items = {
|
||||
{
|
||||
name = "ecola_dose",
|
||||
label = 'E-Cola Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "sprunk_dose",
|
||||
label = 'Sprunk Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "orange_o_tang_dose",
|
||||
label = 'Orange O Tang Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "ecola_zero_dose",
|
||||
label = 'E-Cola Zero Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "orange_o_tang_zero_dose",
|
||||
label = 'Orange O Tang Zero Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "sprunk_zero_dose",
|
||||
label = 'Sprunk Zero Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',',
|
||||
price = 4
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'prop_vend_soda_01',
|
||||
items = {
|
||||
{
|
||||
name = "ecola_dose",
|
||||
label = 'E-Cola Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "sprunk_dose",
|
||||
label = 'Sprunk Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "orange_o_tang_dose",
|
||||
label = 'Orange O Tang Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "ecola_zero_dose",
|
||||
label = 'E-Cola Zero Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "orange_o_tang_zero_dose",
|
||||
label = 'Orange O Tang Zero Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "sprunk_zero_dose",
|
||||
label = 'Sprunk Zero Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',',
|
||||
price = 4
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'ch_chint10_vending_smallroom_01',
|
||||
items = {
|
||||
{
|
||||
name = "ecola_dose",
|
||||
label = 'E-Cola Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "sprunk_dose",
|
||||
label = 'Sprunk Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "orange_o_tang_dose",
|
||||
label = 'Orange O Tang Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "ecola_zero_dose",
|
||||
label = 'E-Cola Zero Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "orange_o_tang_zero_dose",
|
||||
label = 'Orange O Tang Zero Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "sprunk_zero_dose",
|
||||
label = 'Sprunk Zero Dose ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',',
|
||||
price = 4
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'm23_2_prop_m32_vend_drink_01a',
|
||||
items = {
|
||||
{
|
||||
name = "junk_energy",
|
||||
label = 'Junk Energy ($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'sf_prop_sf_vend_drink_01a',
|
||||
items = {
|
||||
{
|
||||
name = "junk_energy",
|
||||
label = 'Junk Energy($%price%)',
|
||||
icon = 'fa-solid fa-can-food',
|
||||
price = 4
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'prop_vend_water_01',
|
||||
items = {
|
||||
{
|
||||
name = "water",
|
||||
label = 'Flasche Wasser ($%price%)',
|
||||
price = 2
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'prop_vend_snak_01',
|
||||
items = {
|
||||
{
|
||||
name = "mimis_instant_nudeln",
|
||||
label = 'Mimis Instant Nudeln ($%price%)',
|
||||
icon = 'fa-solid fa-pot-food',
|
||||
price = 6
|
||||
},
|
||||
{
|
||||
name = "twerks_candy",
|
||||
label = 'Ego Chaser Schockriegel ($%price%)',
|
||||
icon = 'fa-solid fa-candy-bar',
|
||||
price = 2
|
||||
},
|
||||
{
|
||||
name = "snikkel_candy",
|
||||
label = 'EarthQuakes ($%price%)',
|
||||
icon = 'fa-solid fa-candy-bar',
|
||||
price = 2
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'prop_vend_snak_01_tu',
|
||||
items = {
|
||||
{
|
||||
name = "mimis_instant_nudeln",
|
||||
label = 'Mimis Instant Nudeln ($%price%)',
|
||||
icon = 'fa-solid fa-pot-food',
|
||||
price = 6
|
||||
},
|
||||
{
|
||||
name = "twerks_candy",
|
||||
label = 'Ego Chaser Schockriegel ($%price%)',
|
||||
icon = 'fa-solid fa-candy-bar',
|
||||
price = 2
|
||||
},
|
||||
{
|
||||
name = "snikkel_candy",
|
||||
label = 'EarthQuakes ($%price%)',
|
||||
icon = 'fa-solid fa-candy-bar',
|
||||
price = 2
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
model = 'prop_vend_coffe_01',
|
||||
items = {
|
||||
{
|
||||
name = "coffe",
|
||||
label = 'Kaffee Togo ($%price%)',
|
||||
icon = 'fa fa-mug-hot',
|
||||
price = 4
|
||||
},
|
||||
{
|
||||
name = "kakao",
|
||||
label = 'Kakao Togo ($%price%)',
|
||||
icon = 'fa fa-mug-hot',
|
||||
price = 4
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'prop_vend_fags_01',
|
||||
items = {
|
||||
{
|
||||
name = "redwoodpack",
|
||||
label = 'Packung Redwood Zigaretten ($%price%)',
|
||||
icon = 'fa-solid fa-smoking',
|
||||
price = 10
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Config.WaterCoolers = { -- Water coolers
|
||||
{model = 'prop_watercooler_dark',},
|
||||
{model = 'prop_watercooler',},
|
||||
}
|
||||
|
||||
|
||||
Config.NewsSellers = { -- News sellers
|
||||
{
|
||||
model = 'prop_news_disp_06a',
|
||||
items = {
|
||||
{
|
||||
name = "newspaper",
|
||||
label = 'Periódico ($%price%)',
|
||||
icon = 'fa fa-newspaper',
|
||||
price = 30
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'prop_news_disp_01a',
|
||||
items = {
|
||||
{
|
||||
name = "newspaper",
|
||||
label = 'Periódico ($%price%)',
|
||||
icon = 'fa fa-newspaper',
|
||||
price = 30
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
model = 'prop_news_disp_03a',
|
||||
items = {
|
||||
{
|
||||
name = "newspaper",
|
||||
label = 'Periódico ($%price%)',
|
||||
icon = 'fa fa-newspaper',
|
||||
price = 30
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
16
resources/[inventory]/muhaddil-machines/fxmanifest.lua
Normal file
16
resources/[inventory]/muhaddil-machines/fxmanifest.lua
Normal file
|
@ -0,0 +1,16 @@
|
|||
fx_version 'cerulean'
|
||||
game 'gta5'
|
||||
lua54 'yes'
|
||||
|
||||
author 'Muhaddil'
|
||||
description 'FiveM script that adds vending machines'
|
||||
version 'v1.0.1'
|
||||
|
||||
shared_scripts {
|
||||
'config.lua',
|
||||
'@ox_lib/init.lua',
|
||||
}
|
||||
|
||||
client_script 'client.lua'
|
||||
|
||||
server_script 'server/*'
|
120
resources/[inventory]/muhaddil-machines/server/autoChecker.lua
Normal file
120
resources/[inventory]/muhaddil-machines/server/autoChecker.lua
Normal file
|
@ -0,0 +1,120 @@
|
|||
local currentVersion = GetResourceMetadata(GetCurrentResourceName(), 'version')
|
||||
local resourceName = 'Muhaddil/muhaddil-machines'
|
||||
local githubApiUrl = 'https://api.github.com/repos/' .. resourceName .. '/releases/latest'
|
||||
|
||||
-- Función para calcular la diferencia en días
|
||||
local function daysAgo(dateStr)
|
||||
local year, month, day = dateStr:match("(%d+)-(%d+)-(%d+)")
|
||||
local releaseTime = os.time({ year = year, month = month, day = day })
|
||||
local currentTime = os.time()
|
||||
local difference = os.difftime(currentTime, releaseTime) / (60 * 60 * 24) -- Diferencia en días
|
||||
return math.floor(difference)
|
||||
end
|
||||
|
||||
-- Función para convertir la fecha a "hace X días"
|
||||
local function formatDate(releaseDate)
|
||||
local days = daysAgo(releaseDate)
|
||||
if days < 1 then
|
||||
return "Today"
|
||||
elseif days == 1 then
|
||||
return "Yesterday"
|
||||
else
|
||||
return days .. " days ago"
|
||||
end
|
||||
end
|
||||
|
||||
-- Función para acortar la URL
|
||||
local function shortenTexts(text)
|
||||
local maxLength = 35
|
||||
if #text > maxLength then
|
||||
local shortened = text:sub(1, maxLength - 3) .. '...'
|
||||
return shortened
|
||||
else
|
||||
return text
|
||||
end
|
||||
end
|
||||
|
||||
local function printWithColor(message, colorCode)
|
||||
if type(message) ~= "string" then
|
||||
message = tostring(message)
|
||||
end
|
||||
print('\27[' .. colorCode .. 'm' .. message .. '\27[0m')
|
||||
end
|
||||
|
||||
local function printCentered(text, length, colorCode)
|
||||
local padding = math.max(length - #text - 2, 0)
|
||||
local leftPadding = math.floor(padding / 2)
|
||||
local rightPadding = padding - leftPadding
|
||||
printWithColor('│' .. string.rep(' ', leftPadding) .. text .. string.rep(' ', rightPadding) .. '│', colorCode)
|
||||
end
|
||||
|
||||
local function printWrapped(text, length, colorCode)
|
||||
if type(text) ~= "string" then
|
||||
text = tostring(text)
|
||||
end
|
||||
|
||||
local maxLength = length - 2
|
||||
local pos = 1
|
||||
|
||||
while pos <= #text do
|
||||
local endPos = pos + maxLength - 1
|
||||
if endPos > #text then
|
||||
endPos = #text
|
||||
else
|
||||
local spaceIndex = text:sub(pos, endPos):match('.*%s') or maxLength
|
||||
endPos = pos + spaceIndex - 1
|
||||
end
|
||||
|
||||
local line = text:sub(pos, endPos)
|
||||
if endPos < #text then
|
||||
line = line .. '...'
|
||||
end
|
||||
|
||||
printWithColor('│' .. line .. string.rep(' ', length - #line) .. '│', colorCode)
|
||||
|
||||
pos = endPos + 1
|
||||
end
|
||||
end
|
||||
|
||||
if Config.AutoVersionChecker then
|
||||
PerformHttpRequest(githubApiUrl, function(statusCode, response, headers)
|
||||
if statusCode == 200 then
|
||||
local data = json.decode(response)
|
||||
|
||||
if data and data.tag_name then
|
||||
local latestVersion = data.tag_name
|
||||
local releaseDate = data.published_at or "Unknown"
|
||||
local formattedDate = formatDate(releaseDate)
|
||||
local notes = data.body or "No notes available"
|
||||
local downloadUrl = data.html_url or "No download link available"
|
||||
local shortenedUrl = shortenTexts(downloadUrl)
|
||||
local shortenedNotes = shortenTexts(notes)
|
||||
|
||||
|
||||
local boxWidth = 52
|
||||
|
||||
if latestVersion ~= currentVersion then
|
||||
print('╭────────────────────────────────────────────────────╮')
|
||||
printWrapped('[muhaddil-machines] - New Version Available', boxWidth, '34') -- Blue
|
||||
printWrapped('Current version: ' .. currentVersion, boxWidth, '32') -- Green
|
||||
printWrapped('Latest version: ' .. latestVersion, boxWidth, '33') -- Yellow
|
||||
printWrapped('Released: ' .. formattedDate, boxWidth, '33') -- Yellow
|
||||
printWrapped('Notes: ' .. shortenedNotes, boxWidth, '33') -- Yellow
|
||||
printWrapped('Download: ' .. shortenedUrl, boxWidth, '32') -- Green
|
||||
print('╰────────────────────────────────────────────────────╯')
|
||||
else
|
||||
print('╭────────────────────────────────────────────────────╮')
|
||||
printWrapped('[muhaddil-machines] - Up-to-date', boxWidth, '32') -- Green
|
||||
printWrapped('Current version: ' .. currentVersion, boxWidth, '32') -- Green
|
||||
print('╰────────────────────────────────────────────────────╯')
|
||||
end
|
||||
else
|
||||
printWithColor('[muhaddil-machines] - Error: The JSON structure is not as expected.', '31') -- Red
|
||||
printWithColor('GitHub API Response: ' .. response, '31') -- Red
|
||||
end
|
||||
else
|
||||
printWithColor(
|
||||
'[muhaddil-machines] - Failed to check for latest version. Status code: ' .. statusCode, '31') -- Red
|
||||
end
|
||||
end, 'GET')
|
||||
end
|
164
resources/[inventory]/muhaddil-machines/server/server.lua
Normal file
164
resources/[inventory]/muhaddil-machines/server/server.lua
Normal file
|
@ -0,0 +1,164 @@
|
|||
if Config.Framework == "esx" then
|
||||
ESX = exports['es_extended']:getSharedObject()
|
||||
elseif Config.Framework == "qb" then
|
||||
QBCore = exports['qb-core']:GetCoreObject()
|
||||
elseif Config.Framework == "ox" then
|
||||
Ox = require '@ox_core.lib.init'
|
||||
else
|
||||
ESX = exports['es_extended']:getSharedObject()
|
||||
end
|
||||
|
||||
local function getPlayerObject(src) -- Get the player object
|
||||
if Config.Framework == 'qb' then
|
||||
return QBCore.Functions.GetPlayer(src)
|
||||
elseif Config.Framework == 'esx' then
|
||||
return ESX.GetPlayerFromId(src)
|
||||
elseif Config.Framework == 'ox' then
|
||||
return Ox.GetPlayer(src)
|
||||
end
|
||||
end
|
||||
|
||||
function DebugPrint(...)
|
||||
if Config.DebugMode then
|
||||
print(...)
|
||||
end
|
||||
end
|
||||
|
||||
local function TakeMoney(playerObject, method, amount) -- Take money from the player
|
||||
amount = tonumber(amount)
|
||||
|
||||
if Config.Framework == 'qb' then
|
||||
return playerObject.Functions.RemoveMoney(method, amount)
|
||||
elseif Config.Framework == 'esx' then
|
||||
if method == 'cash' then
|
||||
if playerObject.getMoney() >= amount then
|
||||
playerObject.removeMoney(amount)
|
||||
return true
|
||||
end
|
||||
elseif method == 'bank' then
|
||||
if playerObject.getAccount('bank').money >= amount then
|
||||
playerObject.removeAccountMoney('bank', amount)
|
||||
return true
|
||||
end
|
||||
end
|
||||
elseif Config.Framework == 'ox' then
|
||||
if exports.ox_inventory:GetItemCount(source, 'money') >= amount then
|
||||
exports.ox_inventory:RemoveItem(source, 'money', amount)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function giveItem(src, playerObject, item, amount) -- Give the item to the player
|
||||
if Config.Framework == 'qb' then
|
||||
if Config.Inventory == 'qs' then
|
||||
exports['qs-inventory']:AddItem(src, item.name, amount)
|
||||
elseif Config.Inventory == 'ox' then
|
||||
exports.ox_inventory:AddItem(src, item.name, amount)
|
||||
else
|
||||
if Config.NewQBInventory then
|
||||
exports['qb-inventory']:AddItem(source, item.name, amount, false, false, 'Machines')
|
||||
else
|
||||
playerObject.Functions.AddItem(item.name, amount)
|
||||
end
|
||||
end
|
||||
elseif Config.Framework == 'esx' then
|
||||
if Config.Inventory == 'qs' then
|
||||
exports['qs-inventory']:AddItem(src, item.name, amount)
|
||||
elseif Config.Inventory == 'ox' then
|
||||
exports.ox_inventory:AddItem(src, item.name, amount)
|
||||
else
|
||||
playerObject.addInventoryItem(item.name, amount)
|
||||
end
|
||||
elseif Config.Framework == 'ox' then
|
||||
exports.ox_inventory:AddItem(source, item.name, amount)
|
||||
end
|
||||
end
|
||||
|
||||
local function handlePurchase(src, player, item, machineName, totalPrice, cantidad) -- Handle the purchase
|
||||
local success = false
|
||||
|
||||
if TakeMoney(player, 'cash', totalPrice) then
|
||||
success = true
|
||||
elseif TakeMoney(player, 'bank', totalPrice) then
|
||||
success = true
|
||||
end
|
||||
|
||||
if success then
|
||||
giveItem(src, player, item, cantidad)
|
||||
else
|
||||
TriggerClientEvent('muhaddil-machines:Notify', src, '', 'No tienes suficiente dinero.', 'error')
|
||||
end
|
||||
end
|
||||
|
||||
local function findItemInSource(sourceData, itemName) -- Find the item in the source data
|
||||
for _, item in ipairs(sourceData.items) do
|
||||
if item.name == itemName then
|
||||
return item
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
RegisterNetEvent('muhaddil-machines:buy',
|
||||
function(sourceType, sourceName, itemName, cantidad) -- Event for buying the item
|
||||
local src = source
|
||||
local player = getPlayerObject(src)
|
||||
|
||||
local sourceData
|
||||
if sourceType == 'machine' then
|
||||
sourceData = Config.machines[sourceName]
|
||||
elseif sourceType == 'stand' then
|
||||
sourceData = Config.Stands[sourceName]
|
||||
elseif sourceType == 'news' then
|
||||
sourceData = Config.NewsSellers[sourceName]
|
||||
else
|
||||
TriggerClientEvent('muhaddil-machines:Notify', src, '', 'El tipo de origen no es válido.', 'error')
|
||||
return
|
||||
end
|
||||
|
||||
local item = findItemInSource(sourceData, itemName)
|
||||
if item then
|
||||
local totalPrice = item.price * cantidad
|
||||
handlePurchase(src, player, item, sourceName, totalPrice, cantidad)
|
||||
else
|
||||
TriggerClientEvent('muhaddil-machines:Notify', src, '', 'El artículo no está disponible', 'error')
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterServerEvent('muhaddil-machines:RemoveThirst') -- Event for the watercoolers to remove thirst
|
||||
AddEventHandler('muhaddil-machines:RemoveThirst', function()
|
||||
local src = source
|
||||
|
||||
if Config.Framework == 'qb' then
|
||||
local player = QBCore.Functions.GetPlayer(src)
|
||||
if player then
|
||||
local currentThirst = player.PlayerData.metadata['thirst'] or 0
|
||||
if currentThirst < 100 then
|
||||
local newThirst = math.min(currentThirst + Config.ThirstRemoval, 100)
|
||||
player.Functions.SetMetaData('thirst', newThirst)
|
||||
|
||||
TriggerClientEvent('hud:client:UpdateNeeds', src, player.PlayerData.metadata.hunger or 50, newThirst)
|
||||
else
|
||||
print("[Info] El jugador " .. src .. " ya tiene la sed máxima (100).")
|
||||
end
|
||||
else
|
||||
print("[Error] No se pudo obtener el jugador para src: " .. tostring(src))
|
||||
end
|
||||
elseif Config.Framework == 'esx' then
|
||||
TriggerClientEvent('esx_status:add', src, 'thirst', Config.ThirstRemoval)
|
||||
elseif Config.Framework == 'ox' then
|
||||
local player = Ox.GetPlayer(src)
|
||||
local beforeStatus = player.getStatus('thirst')
|
||||
player.removeStatus('thirst', Config.ThirstRemoval)
|
||||
local afterStatus = player.getStatus('thirst')
|
||||
DebugPrint("[Info] El jugador " ..
|
||||
src .. " tenía " .. beforeStatus .. " de sed y ahora tiene " .. afterStatus .. ".")
|
||||
local statuses = player.getStatuses()
|
||||
DebugPrint("[Info] Los estados del jugador " .. src .. " son: " .. json.encode(statuses))
|
||||
else
|
||||
print("[Error] Configuración de framework no válida.")
|
||||
end
|
||||
end)
|
|
@ -197,7 +197,7 @@ Config.Items = {
|
|||
stamina = 0,
|
||||
}
|
||||
},
|
||||
["tims_instant_nudeln"] = {
|
||||
["mimis_instant_nudeln"] = {
|
||||
uses = 1,
|
||||
prop = { model = `v_res_fa_potnoodle`, boneId = 60309, offset = vec3(0.08, -0.04, 0.07), rotation = vec3(-30.0, 10.0, 0.0) },
|
||||
idle = { dict = "anim@scripted@island@special_peds@pavel@hs4_pavel_ig5_caviar_p1", anim = "base_idle", time = 2000, params = { nil, nil, nil, 49 } },
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
config.vendingMachine = {
|
||||
active = true,
|
||||
active = false,
|
||||
machines = {
|
||||
{
|
||||
objects = {
|
||||
|
|
|
@ -1590,7 +1590,7 @@ itemsData = {
|
|||
},
|
||||
redwoodpack = {
|
||||
useable = true,
|
||||
weight = 200,
|
||||
weight = 100,
|
||||
type = 'item',
|
||||
unique = false,
|
||||
description = '',
|
||||
|
@ -8252,16 +8252,16 @@ itemsData = {
|
|||
label = 'Funkgerät',
|
||||
name = 'radio',
|
||||
},
|
||||
tims_instant_nudeln = {
|
||||
mimis_instant_nudeln = {
|
||||
useable = true,
|
||||
weight = 100,
|
||||
type = 'item',
|
||||
unique = false,
|
||||
description = 'der Kulinarische Blitzbesuch in Fernost',
|
||||
image = 'tims_instant_nudeln.png',
|
||||
image = 'mimis_instant_nudeln.png',
|
||||
shouldClose = true,
|
||||
label = 'Tim\'s Instant Nudeln',
|
||||
name = 'tims_instant_nudeln',
|
||||
label = 'Mimis Instant Nudeln',
|
||||
name = 'mimis_instant_nudeln',
|
||||
},
|
||||
attachment_bench = {
|
||||
useable = true,
|
||||
|
@ -10197,7 +10197,7 @@ itemsData = {
|
|||
type = 'item',
|
||||
description = '',
|
||||
weight = 1000,
|
||||
label = 'Packung E-Cola',
|
||||
label = 'Packet E-Cola Dosen',
|
||||
unique = true,
|
||||
useable = true,
|
||||
image = 'pack_ecola.png',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue