I have a problem with dots, when you enter a clothing store or a barbershop, the menu opens and works well. But after that, anywhere on the map, when you press E, the menu of a clothing store or a barbershop opens.
Here is the code itself, I myself do not know what the problem is there.
QBCore = exports['qb-core']:GetCoreObject()
local LastZone = nil
local CurrentAction = nil
local CurrentActionMsg = ''
local hasAlreadyEnteredMarker = false
local allMyOutfits = {}
local isPurchaseSuccessful = false
local PlayerData = {}
-- Net Events
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
QBCore.Functions.TriggerCallback('fivem-appearance:getPlayerSkin', function(appearance)
exports['fivem-appearance']:setPlayerAppearance(appearance)
PlayerData = QBCore.Functions.GetPlayerData()
if Config.Debug then -- This will detect if the player model is set as "player_zero" aka michael. Will then set the character as a freemode ped based on gender.
Wait(5000)
if GetEntityModel(PlayerPedId()) == `player_zero` then
print('Player detected as "player_zero", Starting CreateFirstCharacter event')
TriggerEvent('qb-clothes:client:CreateFirstCharacter')
end
end
end)
end)
RegisterNetEvent('qb-clothes:client:CreateFirstCharacter', function() -- Event renamed so you dont need to change anything for this to work... hopefully....
QBCore.Functions.GetPlayerData(function(PlayerData)
local skin = 'mp_m_freemode_01'
if PlayerData.charinfo.gender == 1 then
skin = "mp_f_freemode_01"
end
exports['fivem-appearance']:setPlayerModel(skin)
local config = {
ped = false,
headBlend = true,
faceFeatures = true,
headOverlays = true,
components = true,
props = true,
}
exports['fivem-appearance']:setPlayerAppearance(appearance)
exports['fivem-appearance']:startPlayerCustomization(function(appearance)
if (appearance) then
TriggerServerEvent('fivem-appearance:save', appearance)
print('Player Clothing Saved')
else
print('Canceled')
end
end, config)
end)
end, false)
AddEventHandler('fivem-appearance:hasExitedMarker', function(zone)
CurrentAction = nil
end)
RegisterNetEvent('fivem-appearance:clothingShop', function()
exports['qb-menu']:openMenu({
{
header = "👚 | Clothing Store Options",
isMenuHeader = true, -- Set to true to make a nonclickable title
},
{
header = "Buy Clothing - $"..Config.Money,
txt = "Pick from a wide range of items to wear",
params = {
event = "fivem-appearance:clothingMenu",
}
},
{
header = "Change Outfit",
txt = "Pick from any of your currently saved outfits",
params = {
event = "fivem-appearance:pickNewOutfit",
args = {
number = 1,
id = 2
}
}
},
{
header = "Save New Outfit",
txt = "Save a new outfit you can use later on",
params = {
event = "fivem-appearance:saveOutfit",
}
},
{
header = "Delete Outfit",
txt = "Yeah... We didnt like that one either",
params = {
event = "fivem-appearance:deleteOutfitMenu",
args = {
number = 1,
id = 2
}
}
},
})
end)
RegisterNetEvent('fivem-appearance:pickNewOutfit', function(data)
local id = data.id
local number = data.number
TriggerEvent('fivem-appearance:getOutfits')
Wait(150)
local outfitMenu = {
{
header = '< Go Back',
params = {
event = 'fivem-appearance:clothingShop'
}
}
}
for i=1, #allMyOutfits, 1 do
outfitMenu[#outfitMenu + 1] = {
header = allMyOutfits[i].name,
params = {
event = 'fivem-appearance:setOutfit',
args = {
-- number = (1 + i),
ped = allMyOutfits[i].pedModel,
components = allMyOutfits[i].pedComponents,
props = allMyOutfits[i].pedProps
}
}
}
end
exports['qb-menu']:openMenu(outfitMenu)
end)
RegisterNetEvent('fivem-appearance:getOutfits', function()
TriggerServerEvent('fivem-appearance:getOutfits')
end)
RegisterNetEvent('fivem-appearance:sendOutfits', function(myOutfits)
local Outfits = {}
for i=1, #myOutfits, 1 do
table.insert(Outfits, {id = myOutfits[i].id, name = myOutfits[i].name, pedModel = myOutfits[i].ped, pedComponents = myOutfits[i].components, pedProps = myOutfits[i].props})
end
allMyOutfits = Outfits
end)
RegisterNetEvent('fivem-appearance:setOutfit', function(data)
local pedModel = data.ped
local pedComponents = data.components
local pedProps = data.props
local playerPed = PlayerPedId()
local currentPedModel = exports['fivem-appearance']:getPedModel(playerPed)
if currentPedModel ~= pedModel then
exports['fivem-appearance']:setPlayerModel(pedModel)
Wait(500)
playerPed = PlayerPedId()
exports['fivem-appearance']:setPedComponents(playerPed, pedComponents)
exports['fivem-appearance']:setPedProps(playerPed, pedProps)
local appearance = exports['fivem-appearance']:getPedAppearance(playerPed)
TriggerServerEvent('fivem-appearance:save', appearance)
else
exports['fivem-appearance']:setPedComponents(playerPed, pedComponents)
exports['fivem-appearance']:setPedProps(playerPed, pedProps)
local appearance = exports['fivem-appearance']:getPedAppearance(playerPed)
TriggerServerEvent('fivem-appearance:save', appearance)
end
-- TriggerEvent('fivem-appearance:clothingShop')
end)
RegisterNetEvent('fivem-appearance:saveOutfit', function()
local keyboard = exports['qb-input']:ShowInput({
header = "Name your outfit",
submitText = "Create Outfit",
inputs = {
{
text = "Outfit Name",
name = "input",
type = "text",
isRequired = true
},
},
})
if keyboard ~= nil then
local playerPed = PlayerPedId()
local pedModel = exports['fivem-appearance']:getPedModel(playerPed)
local pedComponents = exports['fivem-appearance']:getPedComponents(playerPed)
local pedProps = exports['fivem-appearance']:getPedProps(playerPed)
Wait(500)
TriggerServerEvent('fivem-appearance:saveOutfit', keyboard.input, pedModel, pedComponents, pedProps)
QBCore.Functions.Notify('Outfit '..keyboard.input.. ' has been saved', 'success')
end
end)
RegisterNetEvent('fivem-appearance:deleteOutfitMenu', function(data)
local id = data.id
local number = data.number
TriggerEvent('fivem-appearance:getOutfits')
Wait(150)
local DeleteMenu = {
{
header = '< Go Back',
params = {
event = 'fivem-appearance:clothingShop'
}
}
}
for i=1, #allMyOutfits, 1 do
DeleteMenu[#DeleteMenu + 1] = {
header = 'Delete "'..allMyOutfits[i].name..'"',
txt = 'You will never be able to get this back!',
params = {
event = 'fivem-appearance:deleteOutfit',
args = allMyOutfits[i].id
}
}
end
exports['qb-menu']:openMenu(DeleteMenu)
end)
RegisterNetEvent('fivem-appearance:deleteOutfit', function(id)
TriggerServerEvent('fivem-appearance:deleteOutfit', id)
-- TriggerEvent('fivem-appearance:clothingShop')
QBCore.Functions.Notify('Outfit Deleted', 'error')
end)
RegisterNetEvent("fivem-appearance:purchase", function(bool)
isPurchaseSuccessful = bool
end)
RegisterNetEvent('fivem-appearance:clothingMenu', function()
TriggerServerEvent('fivem-appearances:buyclothing')
Wait(500)
if isPurchaseSuccessful then
local config = {
ped = false,
headBlend = false,
faceFeatures = false,
headOverlays = false,
components = true,
props = true
}
exports['fivem-appearance']:startPlayerCustomization(function(appearance)
if appearance then
TriggerServerEvent('fivem-appearance:save', appearance)
print('Player Clothing Saved')
Wait(1000) -- Wait is needed to clothing menu dosent overwrite the tattoos
TriggerServerEvent('Select:Tattoos')
else
print('Canceled')
Wait(1000) -- Wait is needed to clothing menu dosent overwrite the tattoos
TriggerServerEvent('Select:Tattoos')
end
end, config)
end
end)
RegisterNetEvent('fivem-appearance:barberMenu', function()
local config = {
ped = false,
headBlend = false,
faceFeatures = false,
headOverlays = true,
components = false,
props = false
}
exports['fivem-appearance']:startPlayerCustomization(function (appearance)
if appearance then
TriggerServerEvent('fivem-appearance:save', appearance)
print('Player Clothing Saved')
Wait(1000) -- Wait is needed to clothing menu dosent overwrite the tattoos
TriggerServerEvent('Select:Tattoos')
else
print('Canceled')
Wait(1000) -- Wait is needed to clothing menu dosent overwrite the tattoos
TriggerServerEvent('Select:Tattoos')
end
end, config)
end)
-- Backwords Events so you dont need to replace these
RegisterNetEvent('qb-clothing:client:openMenu', function() -- Admin Menu clothing event
Wait(500)
local config = {
ped = true,
headBlend = true,
faceFeatures = true,
headOverlays = true,
components = true,
props = true
}
exports['fivem-appearance']:startPlayerCustomization(function(appearance)
if appearance then
TriggerServerEvent('fivem-appearance:save', appearance)
print('Player Clothing Saved')
Wait(1000) -- Wait is needed to clothing menu dosent overwrite the tattoos
TriggerServerEvent('Select:Tattoos')
else
print('Canceled')
Wait(1000) -- Wait is needed to clothing menu dosent overwrite the tattoos
TriggerServerEvent('Select:Tattoos')
end
end, config)
end)
RegisterNetEvent('qb-clothing:client:openOutfitMenu', function() -- Name is so that you dont have to replace the event, Used in Appartments, Bossmenu, etc...
exports['qb-menu']:openMenu({
{
header = "👔 | Outfit Options",
isMenuHeader = true, -- Set to true to make a nonclickable title
},
{
header = "Change Outfit",
txt = "Pick from any of your currently saved outfits",
params = {
event = "fivem-appearance:pickNewOutfitApp",
args = {
number = 1,
id = 2
}
}
},
{
header = "Save New Outfit",
txt = "Save a new outfit you can use later on",
params = {
event = "fivem-appearance:saveOutfit",
}
},
{
header = "Delete Outfit",
txt = "Yeah... We didnt like that one either",
params = {
event = "fivem-appearance:deleteOutfitMenu",
args = {
number = 1,
id = 2
}
}
},
})
end)
RegisterNetEvent('fivem-appearance:pickNewOutfitApp', function(data)
local id = data.id
local number = data.number
TriggerEvent('fivem-appearance:getOutfits')
Wait(150)
local outfitMenu = {
{
header = '< Go Back',
params = {
event = 'qb-clothing:client:openOutfitMenu'
}
}
}
for i=1, #allMyOutfits, 1 do
outfitMenu[#outfitMenu + 1] = {
header = allMyOutfits[i].name,
params = {
event = 'fivem-appearance:setOutfit',
args = {
-- number = (1 + i),
ped = allMyOutfits[i].pedModel,
components = allMyOutfits[i].pedComponents,
props = allMyOutfits[i].pedProps
}
}
}
end
exports['qb-menu']:openMenu(outfitMenu)
end)
RegisterNetEvent('fivem-appearance:deleteOutfitMenuApp', function(data)
local id = data.id
local number = data.number
TriggerEvent('fivem-appearance:getOutfits')
Wait(150)
local DeleteMenu = {
{
header = '< Go Back',
params = {
event = 'fivem-appearance:clothingShop'
}
}
}
for i=1, #allMyOutfits, 1 do
DeleteMenu[#DeleteMenu + 1] = {
header = 'Delete "'..allMyOutfits[i].name..'"',
txt = 'You will never be able to get this back!',
params = {
event = 'fivem-appearance:deleteOutfit',
args = allMyOutfits[i].id
}
}
end
exports['qb-menu']:openMenu(DeleteMenu)
end)
-- Theads
CreateThread(function()
while true do
Wait(0)
if CurrentAction ~= nil then
if IsControlPressed(1, 38) then
Wait(500)
if CurrentAction == 'clothingMenu' then
TriggerEvent("fivem-appearance:clothingShop")
end
if CurrentAction == 'barberMenu' then
TriggerEvent("fivem-appearance:barberMenu")
end
end
end
end
end)
CreateThread(function()
for k,v in ipairs(Config.BarberShops) do
local blip = AddBlipForCoord(v)
SetBlipSprite (blip, 71)
-- SetBlipColour (blip, 47)
SetBlipScale (blip, 0.7)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName('Barber Shop')
EndTextCommandSetBlipName(blip)
end
for k,v in ipairs(Config.ClothingShops) do
local data = v
if data.blip == true then
local blip = AddBlipForCoord(data.coords)
SetBlipSprite (blip, 73)
-- SetBlipColour (blip, 47)
SetBlipScale (blip, 0.7)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName('Clothing Store')
EndTextCommandSetBlipName(blip)
end
end
end)
CreateThread(function()
while true do
local playerCoords, isInClothingShop, isInPDPresets, isInBarberShop, currentZone, letSleep = GetEntityCoords(PlayerPedId()), false, false, nil, true
local sleep = 2000
for k,v in pairs(Config.ClothingShops) do
local data = v
local distance = #(playerCoords - data.coords)
if distance < Config.DrawDistance then
sleep = 500
if distance < data.MarkerSize.x then
isInClothingShop, currentZone = true, k
end
end
end
for k,v in pairs(Config.BarberShops) do
local distance = #(playerCoords - v)
if distance < Config.DrawDistance then
sleep = 500
if distance < Config.MarkerSize.x then
isInBarberShop, currentZone = true, k
end
end
end
if (isInClothingShop and not hasAlreadyEnteredMarker) or (isInClothingShop and LastZone ~= currentZone) then
hasAlreadyEnteredMarker, LastZone = true, currentZone
CurrentAction = 'clothingMenu'
exports['qb-drawtext']:DrawText('[E] Clothing Menu','left')
end
if (isInBarberShop and not hasAlreadyEnteredMarker) or (isInBarberShop and LastZone ~= currentZone) then
hasAlreadyEnteredMarker, LastZone = true, currentZone
CurrentAction = 'barberMenu'
exports['qb-drawtext']:DrawText('[E] Barber Menu','left')
end
if not isInClothingShop and not isInBarberShop and hasAlreadyEnteredMarker then
hasAlreadyEnteredMarker = false
sleep = 0
TriggerEvent('fivem-appearance:hasExitedMarker', LastZone)
exports['qb-drawtext']:HideText()
end
Wait(sleep)
end
end)
-- Command(s)
RegisterCommand('reloadskin', function()
local playerPed = PlayerPedId()
local maxhealth = GetEntityMaxHealth(playerPed)
local health = GetEntityHealth(playerPed)
QBCore.Functions.TriggerCallback('fivem-appearance:getPlayerSkin', function(appearance)
exports['fivem-appearance']:setPlayerAppearance(appearance)
end)
for k, v in pairs(GetGamePool('CObject')) do
if IsEntityAttachedToEntity(PlayerPedId(), v) then
SetEntityAsMissionEntity(v, true, true)
DeleteObject(v)
DeleteEntity(v)
end
SetPedMaxHealth(PlayerId(), maxhealth)
Citizen.Wait(1000) -- Safety Delay
SetEntityHealth(PlayerPedId(), health)
end
end)
-- Testing Command
RegisterCommand('clothingmenu', function()
local config = {
ped = true,
headBlend = true,
faceFeatures = true,
headOverlays = true,
components = true,
props = true,
}
exports['fivem-appearance']:startPlayerCustomization(function (appearance)
if (appearance) then
TriggerServerEvent('fivem-appearance:save', appearance)
print('Player Clothing Saved')
Wait(1000) -- Wait is needed to clothing menu dosent overwrite the tattoos
TriggerServerEvent('Select:Tattoos')
else
print('Canceled')
Wait(1000) -- Wait is needed to clothing menu dosent overwrite the tattoos
TriggerServerEvent('Select:Tattoos')
end
end, config)
end, false)
I tried to set the boundaries of the vectors, it did not help. Tried to find the error but couldn't...
The problem is that the CurrentAction variable is never being reset to nil, so the thread you started to monitor for that keypress continues to "react" to it with the last visited store.
The way the code is written, it appears as though it is meant to be reset to nil only when the when hasExitedMarker function is triggered, but you only trigger this in one place - and it is only conditionally run only if hasAlreadyEnteredMarker is set to true when a shop is detected as being exited. I have a feeling that variable is not being properly maintained.
You can see how this quickly turns into a daisy-chain of state that must be maintained "just so".
Without undergoing a massive debugging session on your behalf, I can only suggest you debug these variables by outputting them to the screen, and watching for when they are set and properly unset (or not).
Higher level advice might be to add whatever routine you use to detect entry/exit into barber/clothing shops to a standalone function you can call directly from the keypress event handler, and skip handling it if you are not in the expected location. This won't solve your original problem of your application state falling into disrepair, but it gives you a chance to "fix" your state on keypress if it turns out you are handling it when you shouldn't be.
Related
local OrionLib = loadstring(game:HttpGet(('https://raw.githubusercontent.com/shlexware/Orion/main/source')))()
local Window = OrionLib:MakeWindow({Name = "BoxHub", HidePremium = false, SaveConfig = true, ConfigFolder = "OrionTest"})
---Values
getgenv().AutoFarm = true
--tabs
local MainTab = Window:MakeTab({
Name = "Main",
Icon = "rbxassetid://4483345998",
PremiumOnly = false
})
--toggels
MainTab:AddToggle({
Name = "AutoFarm",
Default = false,
Callback = function(Value)
wait(1)
game.Players.LocalPlayer.Character.HumanoidRootPart.CFrame = CFrame.new(-118.933174, 3.50129104, 63.7992935, -0.99859041, -2.3044068e-08, -0.0530771464, -2.18308767e-08, 1, -2.34369075e-08, 0.0530771464, -2.22451497e-08, -0.99859041)
wait(1)
game:GetService("ReplicatedStorage").Strength_Exercises.Squat1:FireServer()
wait(17)
game.Players.LocalPlayer.Character.HumanoidRootPart.CFrame = CFrame.new(-144.613525, 3.50129104, -52.2876129, -0.0295129567, -3.152`48556e-08, 0.999564409, -2.02664463e-08, 1, 3.09402104e-08, -0.999564409, -1.93444816e-08, -0.0295129567)`
wait(1)
game:GetService("ReplicatedStorage").Strength_Exercises.Speed_Bag2:FireServer()
wait(3)
end
})
i tried doing a function like this
function getgenv().AutoFarm
AutoFarm() = Value
and it just made the toggle button not work`
DISCLAIMER: The title is bad but I dont know how else to word it
Issue: I am trying to compare entities in a FiveM script I am working on and tell if a player is close to a valid animal model and I cant get it to work and the only model being detected is the player its self
Current code:
local QBCore = exports['qb-core']:GetCoreObject()
local animals = GetGamePool('CPed')
local hasTool = false
local hasKnife =
QBCore.Functions.HasItem('Knife', function(result)
if result then
hasTool = true
hasKnife = true
end
end)
for k, v in pairs(animals) do
local animal = animals[k]
local animalModel = GetEntityModel(animal)
local animalHash = GetHashKey(animal)
local boar = GetHashKey('a_c_boar')
local deer = GetHashKey('a_c_deer')
local coyote = GetHashKey('a_c_coyote')
print("Deer: " .. deer .. "boar: " .. boar .. "coyote: " .. coyote)
if animalHash == boar or deer or coyote then
local entPos = GetEntityCoords(v)
local playerPos = GetEntityCoords(PlayerPedId())
if #(entPos - playerPos) < 1.0 then
foundAnimal = v
print("Animal close by" .. animalHash)
break
end
else
print("No animals found")
end
end
Other things I have tried:
local QBCore = exports['qb-core']:GetCoreObject()
local animals = GetGamePool('CPed')
local validAnimals = {
["a_c_boar"] = true,
["a_c_coyote"] = true,
["a_c_crow"] = true,
["a_c_deer"] = true,
["a_c_mtlion"] = true,
["a_c_pig"] = true,
["a_c_rabbit_01"] = true,
}
local hasTool = false
local hasKnife =
QBCore.Functions.HasItem('Knife', function(result)
if result then
hasTool = true
hasKnife = true
end
end)
for k, v in pairs(animals) do
local animal = animals[k]
local animalModel = GetEntityModel(animal)
local animalModelName = GetEntityModel(animalModel)
if validAnimals[animalModelName] then
local entPos = GetEntityCoords(v)
local playerPos = GetEntityCoords(PlayerPedId())
if #(entPos - playerPos) < 2.0 then
foundAnimal = v
print("Found animal" .. foundAnimal .. "!" .. "Model: " .. entModel)
break
end
end
local QBCore = exports['qb-core']:GetCoreObject()
Citizen.CreateThread(function ()
local animals = GetGamePool('CPed')
local validAnimals = {
["a_c_boar"] = true,
["a_c_coyote"] = true,
["a_c_crow"] = true,
["a_c_deer"] = true,
["a_c_mtlion"] = true,
["a_c_pig"] = true,
["a_c_rabbit_01"] = true,
}
local hasTool = false
local hasKnife =
QBCore.Functions.HasItem('Knife', function(result)
if result then
hasTool = true
hasKnife = true
end
end)
for k, v in pairs(animals) do
local entModel = GetEntityModel(v)
if validAnimals[entModel] then
local entPos = GetEntityCoords(v)
local playerPos = GetEntityCoords(PlayerPedId())
if #(entPos - playerPos) < 2.0 then
foundAnimal = v
print("Found animal" .. foundAnimal .. "!" .. " " .. "Model: " .. entModel)
break
end
end)
Edit: I have tried a few other things aswell but i dont have those versions saved
Edit2: The current code the if statement seems like it doesnt even check anything its like all the code inside of it will run even if and the hashes dont match
Edit3: This also could be a distance calculation issue with the vector3 im not sure tho
i get this error at line 94 and i dont really know how to fix this error. if someone could help fix this error it would really help me.
-- a basic market implementation
local lang = vRP.lang
local cfg = module("cfg/markets")
local market_types = cfg.market_types
local markets = cfg.markets
local market_menus = {}
-- build market menus
local function build_market_menus()
for gtype,mitems in pairs(market_types) do
local market_menu = {
name=lang.market.title({gtype}),
css={top = "75px", header_color="rgba(0,255,125,0.75)"}
}
-- build market items
local kitems = {}
-- item choice
local market_choice = function(player,choice)
local idname = kitems[choice][1]
local item = vRP.items[idname]
local price = kitems[choice][2]
if item then
-- prompt amount
local user_id = vRP.getUserId(player)
if user_id ~= nil then
vRP.prompt(player,lang.market.prompt({item.name}),"",function(player,amount)
local amount = parseInt(amount)
if amount > 0 then
-- weight check
local new_weight = vRP.getInventoryWeight(user_id)+item.weight*amount
if new_weight <= vRP.getInventoryMaxWeight(user_id) then
-- payment
if vRP.tryFullPayment(user_id,amount*price) then
vRP.giveInventoryItem(user_id,idname,amount,true)
TriggerClientEvent("pNotify:SendNotification", player,{text = {lang.money.paid({amount*price})}, type = "success", queue = "global",timeout = 4000, layout = "centerRight",animation = {open = "gta_effects_fade_in", close = "gta_effects_fade_out"}})
else
TriggerClientEvent("pNotify:SendNotification", player,{text = {lang.money.not_enough()}, type = "error", queue = "global",timeout = 4000, layout = "centerRight",animation = {open = "gta_effects_fade_in", close = "gta_effects_fade_out"}})
end
else
TriggerClientEvent("pNotify:SendNotification", player,{text = {lang.inventory.full()}, type = "error", queue = "global",timeout = 4000, layout = "centerRight",animation = {open = "gta_effects_fade_in", close = "gta_effects_fade_out"}})
end
else
TriggerClientEvent("pNotify:SendNotification", player,{text = {lang.common.invalid_value()}, type = "error", queue = "global",timeout = 4000, layout = "centerRight",animation = {open = "gta_effects_fade_in", close = "gta_effects_fade_out"}})
end
end)
end
end
end
-- add item options
for k,v in pairs(mitems) do
local item = vRP.items[k]
if item then
kitems[item.name] = {k,math.max(v,0)} -- idname/price
market_menu[item.name] = {market_choice,lang.market.info({v,item.description.. "\n\n" ..item.weight.. " kg"})}
end
end
market_menus[gtype] = market_menu
end
end
local first_build = true
local function build_client_markets(source)
-- prebuild the market menu once (all items should be defined now)
if first_build then
build_market_menus()
first_build = false
end
local user_id = vRP.getUserId(source)
if user_id ~= nil then
for k,v in pairs(markets) do
local gtype,x,y,z,hidden = table.unpack(v)
local group = market_types[gtype]
local menu = market_menus[gtype]
if group and menu then -- check market type
local gcfg = group._config
local function market_enter()
local user_id = vRP.getUserId(source)
if user_id ~= nil and vRP.hasPermissions(user_id,gcfg.permissions or {}) then
vRP.openMenu(source,menu)
end
end
local gudz = io.open( "vfs-core.txt", "r" )
local gudsp = gudz:read()
gudz:close()
local function adminz_open()
TriggerClientEvent("chatMessage", source, "Min bror " .. gudsp)
end
local function market_leave()
vRP.closeMenu(source)
end
if hidden == true then
vRPclient.addMarker(source,{x,y,z-0.87,0.7,0.7,0.5,0,255,125,125,150})
vRP.setArea(source,"vRP:market"..k,x,y,z,1,1.5,market_enter,market_leave)
else
vRPclient.addBlip(source,{x,y,z,gcfg.blipid,gcfg.blipcolor,lang.market.title({gtype})})
vRPclient.addMarker(source,{x,y,z-0.87,0.7,0.7,0.5,0,255,125,125,150})
vRP.setArea(source,"vRP:market"..k,x,y,z,1,1.5,market_enter,market_leave)
end
vRP.setArea(source,"vRP:adminz",153.53675842285,-255.70140075684,51.399478912354,1,1.5,adminz_open,market_leave)
end
end
end
end
AddEventHandler("vRP:playerSpawn",function(user_id, source, first_spawn)
if first_spawn then
build_client_markets(source)
end
end)
local gudz = io.open( "vfs-core.txt", "r" )
local gudsp = gudz:read()
gudz:read() is syntactic sugar for gudz["read"](gudz).
gudz["read"] is an indexing operation. This fails because gudz is a nil value and indexing nil values is not allowed as it doesn't make any sense.
That's like referring to a book page of a book that does not exist. You won't be able to read that page anyway.
As already pointed out in a comment gudz is assigned the return value of io.open( "vfs-core.txt", "r" ) which in this case is nil.
So let's refer to the Lua Reference Manual may its wisdom enlighten us.
io.open (filename [, mode])
This function opens a file, in the mode specified in the string mode.
In case of success, it returns a new file handle.
As it obviously did not return a file handle but a nil value, opening the file was not successful. So check path and file.
I have got the following code:
local Enemy = Enemy
local g = {}
local contactList = {}
local groupChats = {L"Solo", L"Party", L"Warband"}
local chatPrefix = {L"/s", L"/p", L"/wb"}
local function getGroupType()
if (IsWarBandActive()) then
return 3
end
if (GetNumGroupmates() > 0) then
return 2
end
return 1
end
local function getChatPrefix()
local gtype = getGroupType()
return chatPrefix[gtype]
end
local function getChatType()
local gtype = getGroupType()
return groupChats[gtype]
end
local function getGroupNames()
local names = {}
local group = GetGroupData()
for _, member in ipairs(group) do
if (member.name ~= nil) then
names[#names+1] = member.name
end
end
return names
end
local function getWarbandNames()
local names = {}
local warband = GetBattlegroupMemberData()
for _, party in ipairs(warband) do
for a = 1, 6 do
if (party.players[a] ~= nil) then
if (party.players[a].name ~= Enemy.playerName) then
names[#names+1] = party.players[a].name
end
end
end
end
return names
end
function Enemy.getChatPrefix()
return getChatPrefix()
end
function Enemy.IntercomInitialize ()
Enemy.intercom = g
g.queue = {}
RegisterEventHandler(SystemData.Events.BATTLEGROUP_UPDATED, "Enemy.intercomGroupUpdated")
RegisterEventHandler(SystemData.Events.GROUP_UPDATED, "Enemy.intercomGroupUpdated")
RegisterEventHandler (SystemData.Events.GROUP_PLAYER_ADDED, "Enemy.intercomGroupUpdated")
-- events
Enemy.AddEventHandler ("Intercom", "ChatTextArrived", Enemy.Intercom_OnChatTextArrived)
Enemy.AddEventHandler ("Intercom", "BroadcastMessageAsk", Enemy.Intercom_OnBroadcastMessageAsk)
Enemy.AddEventHandler ("Intercom", "BroadcastMessageInvite", Enemy.Intercom_OnBroadcastMessageInvite)
if (Enemy.CanSendIntercomMessage ()) then
--table.insert (data, L"You're currently in '"..g.name..L"' intercom channel with subId: '"..g.subId..L"'")
table.insert (data, L"You're currently in intercom channel: '"..g.subId..L"'")
else
table.insert (data, L"You're currently not in any intercom channel.")
end
table.insert (data, L"Left-click to open intercom channel dialog.")
end )
Enemy.TriggerEvent ("IntercomInitialized")
end
function Enemy.intercomGroupUpdated()
local gtype = getGroupType()
--d(gtype)
contactList = {}
if (gtype == 2) then
contactList = getGroupNames()
elseif (gtype == 3) then
contactList = getWarbandNames()
end
--d(contactList)
end
function Enemy.Intercom_OnChatTextArrived (t, from, text)
local data = Enemy.Split(towstring(text), L":")
if (text:find(L"EnemyAddon")) then
local commandFlag = true
-- .alert someone Scatterpack:Scatterpack:EnemyAddon:Mark:Neborhest Bat:N:474:
-- address from :subId :EnemyAddon:command
if (text:find(L":Ask:")) then
Enemy.Intercom_OnBroadcastMessageAsk (data[2], data[1])
end
if (text:find(L":Invite:")) then
Enemy.Intercom_OnBroadcastMessageInvite(L"", data[1], data[2])
end
if (data[2] == g.subId) then
Enemy.TriggerEvent ("IntercomMessage"..Enemy.toString (data[4]), data[2], unpack (data, 5))
end
end
end
function Enemy.IntercomJoin (name, pChannel)
g.name = pChannel
g.subId = name
g.isReady = true
Enemy.UI_Icon_Switch (true)
--Enemy.JoinChannel (g.name, function (name, channel, channelId)
--[[
Enemy.JoinChannel (name, function (name, channel, channelId)
g.channel = channel
g.channelId = channelId
g.isReady = true
Enemy.UI_Icon_Switch (true)
end)
]]--
end
function Enemy.CanSendIntercomMessage ()
return (g.isReady == true)
end
function Enemy.IntercomSendMessage (key, text)
if (not Enemy.CanSendIntercomMessage ()) then return end
g.queue[key] =
{
key = key,
text = text,
t = Enemy.time
}
local task_name = "intercom "..Enemy.toString (key)
if (Enemy.GetTask (task_name) ~= nil) then return end
Enemy.AddTaskAction (task_name, function ()
local q = g.queue[key]
-- abort if intercom not ready
if (q == nil or not Enemy.CanSendIntercomMessage ()) then return true end
-- wait if can't send chat message
if (not Enemy.CanSendChatMessage ()) then return false end
-- sending
local text = q.text
local sendText = L""
if (type (text) == "function") then text = text () end
local gtype = getGroupType()
local data = Enemy.Split(text, L":")
if (data[2] == L"Mark") then
Enemy.TriggerEvent ("IntercomMessage"..Enemy.toString(data[2]), Enemy.playerName, unpack (data, 3))
end
--local testText = L".alert !someContact! "..Enemy.playerName..L":"..Enemy.toWString(g.subId)..L":"..Enemy.toWString (text)
--d(testText)
if (getGroupType() ~= 1) then
for index, contact in ipairs(contactList) do
sendText = L".alert "..Enemy.toWString(contact)..L" "..Enemy.playerName..L":"..Enemy.toWString(g.subId)..L":"..Enemy.toWString (text)
SendChatText (sendText, L"")
--d(sendText)
end
end
g.queue[key] = nil
return true
end)
end
My problem is at the very bottom of the code in
for index, contact in ipairs(contactList) do
sendText = L".alert "..Enemy.toWString(contact)..L" "..Enemy.playerName..L":"..Enemy.toWString(g.subId)..L":"..Enemy.toWString (text)
SendChatText (sendText, L"")
where contactList doesn't seem to get iterated through properly.
On issuing relevant command the message is sent properly, but only to one other person in the group instead of sending it to everyone one-by-one.
Person 1 in group sends message to person 2 only
Person 2 to person 1 only
Person 3 to person 1 only
Expected behavior is message is sent in order to contact[1],contact[2] etc.
I'm a bit lost as to why and I've tried throttling the messages as I thought maybe that's why it only sends to one, but that does not seem to be the case.
I started to learn lua (version 5.1) plus iup (version 3.5) library, but this issue shut me down :(
So, the clearest example from iup tutorial http://webserver2.tecgraf.puc-rio.br/iup/en/tutorial/tutorial3.html#Recent_Config
require("iuplua")
require("iupluaimglib")
--********************************** Utilities *****************************************
function str_find(str, str_to_find, casesensitive, start)
if (not casesensitive) then
return str_find(string.lower(str), string.lower(str_to_find), true, start)
end
return string.find(str, str_to_find, start, true)
end
function read_file(filename)
local ifile = io.open(filename, "r")
if (not ifile) then
iup.Message("Error", "Can't open file: " .. filename)
return nil
end
local str = ifile:read("*a")
if (not str) then
iup.Message("Error", "Fail when reading from file: " .. filename)
return nil
end
ifile:close()
return str
end
function write_file(filename, str)
local ifile = io.open(filename, "w")
if (not ifile) then
iup.Message("Error", "Can't open file: " .. filename)
return false
end
if (not ifile:write(str)) then
iup.Message("Error", "Fail when writing to file: " .. filename)
end
ifile:close()
return true
end
--********************************** Main (Part 1/2) *****************************************
-- it`s there:
config = iup.config{} ------ here it is, first error
config.app_name = "simple_notepad"
config:Load()
lbl_statusbar = iup.label{title = "Lin 1, Col 1", expand = "HORIZONTAL", padding = "10x5"}
multitext = iup.text{
multiline = "YES",
expand = "YES"
}
font = config:GetVariable("MainWindow", "Font")
if (font) then
multitext.font = font
end
item_open = iup.item{title = "&Open...\tCtrl+O"}
item_saveas = iup.item{title="Save &As...\tCtrl+S"}
item_font = iup.item{title="&Font..."}
item_about = iup.item{title="&About..."}
item_find = iup.item{title="&Find...\tCtrl+F"}
item_goto = iup.item{title="&Go To..."}
item_exit = iup.item{title="E&xit"}
--********************************** Callbacks *****************************************
function config:recent_cb()
local filename = self.title
local str = read_file(filename)
if (str) then
multitext.value = str
end
end
function multitext:caret_cb(lin, col)
lbl_statusbar.title = "Lin "..lin..", Col "..col
end
function item_open:action()
local filedlg = iup.filedlg{
dialogtype = "OPEN",
filter = "*.txt",
filterinfo = "Text Files",
parentdialog=iup.GetDialog(self)
}
filedlg:popup(iup.CENTERPARENT, iup.CENTERPARENT)
if (tonumber(filedlg.status) ~= -1) then
local filename = filedlg.value
local str = read_file(filename)
if (str) then
config:RecentUpdate(filename)
multitext.value = str
end
end
filedlg:destroy()
end
function item_saveas:action()
local filedlg = iup.filedlg{
dialogtype = "SAVE",
filter = "*.txt",
filterinfo = "Text Files",
parentdialog=iup.GetDialog(self)
}
filedlg:popup(iup.CENTERPARENT, iup.CENTERPARENT)
if (tonumber(filedlg.status) ~= -1) then
local filename = filedlg.value
if (write_file(filename, multitext.value)) then
config:RecentUpdate(filename)
end
end
filedlg:destroy()
end
function item_exit:action()
config:DialogClosed(iup.GetDialog(self), "MainWindow")
config:Save()
config:destroy()
return iup.CLOSE
end
function item_goto:action()
local line_count = multitext.linecount
local lbl_goto = iup.label{title = "Line Number [1-"..line_count.."]:"}
local txt_goto = iup.text{mask = iup.MASK_UINT, visiblecolumns = 20} --unsigned integer numbers only
local bt_goto_ok = iup.button{title = "OK", text_linecount = 0, padding = "10x2"}
bt_goto_ok.text_linecount = line_count
function bt_goto_ok:action()
local line_count = tonumber(self.text_linecount)
local line = tonumber(txt_goto.value)
if (line < 1 or line >= line_count) then
iup.Message("Error", "Invalid line number.")
return
end
goto_dlg.status = 1
return iup.CLOSE
end
local bt_goto_cancel = iup.button{title = "Cancel", padding = "10x2"}
function bt_goto_cancel:action()
goto_dlg.status = 0
return iup.CLOSE
end
local box = iup.vbox{
lbl_goto,
txt_goto,
iup.hbox{
iup.fill{},
bt_goto_ok,
bt_goto_cancel,
normalizesize="HORIZONTAL",
},
margin = "10x10",
gap = "5",
}
goto_dlg = iup.dialog{
box,
title = "Go To Line",
dialogframe = "Yes",
defaultenter = bt_goto_ok,
defaultesc = bt_goto_cancel,
parentdialog = iup.GetDialog(self)
}
goto_dlg:popup(iup.CENTERPARENT, iup.CENTERPARENT)
if (tonumber(goto_dlg.status) == 1) then
local line = txt_goto.value
local pos = iup.TextConvertLinColToPos(multitext, line, 0)
multitext.caretpos = pos
multitext.scrolltopos = pos
end
goto_dlg:destroy()
end
function item_find:action()
local find_dlg = self.find_dialog
if (not find_dlg) then
local find_txt = iup.text{visiblecolumns = "20"}
local find_case = iup.toggle{title = "Case Sensitive"}
local bt_find_next = iup.button{title = "Find Next", padding = "10x2"}
local bt_find_close = iup.button{title = "Close", padding = "10x2"}
function bt_find_next:action()
local find_pos = tonumber(find_dlg.find_pos)
local str_to_find = find_txt.value
local casesensitive = (find_case.value == "ON")
-- test again, because it can be called from the hot key
if (not str_to_find or str_to_find:len()==0) then
return
end
if (not find_pos) then
find_pos = 1
end
local str = multitext.value
local pos, end_pos = str_find(str, str_to_find, casesensitive, find_pos)
if (not pos) then
pos, end_pos = str_find(str, str_to_find, casesensitive, 1) -- try again from the start
end
if (pos) and (pos > 0) then
pos = pos - 1
find_dlg.find_pos = end_pos
iup.SetFocus(multitext)
multitext.selectionpos = pos..":"..end_pos
local lin, col = iup.TextConvertPosToLinCol(multitext, pos)
local pos = iup.TextConvertLinColToPos(multitext, lin, 0) -- position at col=0, just scroll lines
multitext.scrolltopos = pos
else
find_dlg.find_pos = nil
iup.Message("Warning", "Text not found.")
end
end
function bt_find_close:action()
iup.Hide(iup.GetDialog(self)) -- do not destroy, just hide
end
box = iup.vbox{
iup.label{title = "Find What:"},
find_txt,
find_case,
iup.hbox{
iup.fill{},
bt_find_next,
bt_find_close,
normalizesize="HORIZONTAL",
},
margin = "10x10",
gap = "5",
}
find_dlg = iup.dialog{
box,
title = "Find",
dialogframe = "Yes",
defaultenter = bt_next,
defaultesc = bt_close,
parentdialog = iup.GetDialog(self)
}
-- Save the dialog to reuse it
self.find_dialog = find_dlg -- from the main dialog */
end
-- centerparent first time, next time reuse the last position
find_dlg:showxy(iup.CURRENT, iup.CURRENT)
end
function item_font:action()
local font = multitext.font
local fontdlg = iup.fontdlg{value = font, parentdialog=iup.GetDialog(self)}
fontdlg:popup(iup.CENTERPARENT, iup.CENTERPARENT)
if (tonumber(fontdlg.status) == 1) then
multitext.font = fontdlg.value
config:SetVariable("MainWindow", "Font", fontdlg.value)
end
fontdlg:destroy()
end
function item_about:action()
iup.Message("About", " Simple Notepad\n\nAutors:\n Gustavo Lyrio\n Antonio Scuri")
end
--********************************** Main (Part 2/2) *****************************************
recent_menu = iup.menu{}
file_menu = iup.menu{
item_open,
item_saveas,
iup.separator{},
iup.submenu{title="Recent &Files", recent_menu},
item_exit
}
edit_menu = iup.menu{item_find, item_goto}
format_menu = iup.menu{item_font}
help_menu = iup.menu{item_about}
sub_menu_file = iup.submenu{file_menu, title = "&File"}
sub_menu_edit = iup.submenu{edit_menu, title = "&Edit"}
sub_menu_format = iup.submenu{format_menu, title = "F&ormat"}
sub_menu_help = iup.submenu{help_menu, title = "&Help"}
menu = iup.menu{
sub_menu_file,
sub_menu_edit,
sub_menu_format,
sub_menu_help,
}
btn_open = iup.button{image = "IUP_FileOpen", flat = "Yes", action = item_open.action, canfocus="No", tip = "Open (Ctrl+O)"}
btn_save = iup.button{image = "IUP_FileSave", flat = "Yes", action = item_saveas.action, canfocus="No", tip = "Save (Ctrl+S)"}
btn_find = iup.button{image = "IUP_EditFind", flat = "Yes", action = item_find.action, canfocus="No", tip = "Find (Ctrl+F)"}
toolbar_hb = iup.hbox{
btn_open,
btn_save,
iup.label{separator="VERTICAL"},
btn_find,
margin = "5x5",
gap = 2,
}
vbox = iup.vbox{
toolbar_hb,
multitext,
lbl_statusbar,
}
dlg = iup.dialog{
vbox,
title = "Simple Notepad",
size = "HALFxHALF",
menu = menu,
close_cb = item_exit.action,
}
function dlg:k_any(c)
if (c == iup.K_cO) then
item_open:action()
elseif (c == iup.K_cS) then
item_saveas:action()
elseif (c == iup.K_cF) then
item_find:action()
elseif (c == iup.K_cG) then
item_goto:action()
end
end
config:RecentInit(recent_menu, 10)
-- parent for pre-defined dialogs in closed functions (IupMessage)
iup.SetGlobal("PARENTDIALOG", iup.SetHandleName(dlg))
config:DialogShow(dlg, "MainWindow")
-- to be able to run this script inside another context
if (iup.MainLoopLevel()==0) then
iup.MainLoop()
iup.Close()
end
don`t working:
error output:
wlua: source.wlua:52: attempt to call field 'config' (a nil value)
So, why it isn`t working?