elnelson
Lunaria World Dev
Good afternoon otlanders, everything was running but but when i zipped the files to upload to website for updater and tested i got this error, any idea what could be? i've tried changing names of variables but had no luck...
error.log:
ERROR: failed to load UI from 'Quests.otui': unable to open file '/modules/game_quests/Quests.otui': not found
FATAL ERROR: Unable to load module 'game_quests': /modules/game_quests/quests.lua:171: attempt to index global 'questWindow' (a nil value)
stack traceback:
[C]: in function '__index'
/modules/game_quests/quests.lua:171: in function 'init'
/modules/game_quests/quests.otmod:7:[@onLoad]:1: in main chunk
[C]: in function 'ensureModuleLoaded'
/init.lua:71: in function 'tmpLoadFunc'
/modules/updater/updater.lua:60: in function 'loadModules'
/modules/updater/updater.lua:219: in function 'abort'
/modules/updater/updater.lua:262: in function </modules/updater/updater.lua:261>
[C]: in function 'pcall'
/modules/corelib/util.lua:311: in function 'signalcall'
/modules/corelib/ui/uimessagebox.lua:87: in function 'ok'
/modules/corelib/ui/uimessagebox.lua:62: in function </modules/corelib/ui/uimessagebox.lua:62>
this is the quest.lua (its a total mess because im still learning otclient modules ):
and this is my quest.otui
error.log:
ERROR: failed to load UI from 'Quests.otui': unable to open file '/modules/game_quests/Quests.otui': not found
FATAL ERROR: Unable to load module 'game_quests': /modules/game_quests/quests.lua:171: attempt to index global 'questWindow' (a nil value)
stack traceback:
[C]: in function '__index'
/modules/game_quests/quests.lua:171: in function 'init'
/modules/game_quests/quests.otmod:7:[@onLoad]:1: in main chunk
[C]: in function 'ensureModuleLoaded'
/init.lua:71: in function 'tmpLoadFunc'
/modules/updater/updater.lua:60: in function 'loadModules'
/modules/updater/updater.lua:219: in function 'abort'
/modules/updater/updater.lua:262: in function </modules/updater/updater.lua:261>
[C]: in function 'pcall'
/modules/corelib/util.lua:311: in function 'signalcall'
/modules/corelib/ui/uimessagebox.lua:87: in function 'ok'
/modules/corelib/ui/uimessagebox.lua:62: in function </modules/corelib/ui/uimessagebox.lua:62>
this is the quest.lua (its a total mess because im still learning otclient modules ):
Lua:
questWindow = nil
selectedQuestName = nil
defaultQuests = {
[1] = {
item = "Scout the Lost Dog to Wolve\'s Den.",
itemID = 32,
aid = 8001,
amount = 1,
reagent = "The Lost Dog is looking for his friend \'Ruffles\', the dog looks wounded by wolves, lets look for the Wolve\'s Den at the North-East Coasts.\n\nBe careful, dont let the Lost Dog die!!",
price = 100,
type = 250,
reagentName = "wooden hammer",
reqItems = {
[1] = { ingredientId = 3105, reqItemTier = 0.9, reqItemCount = 5 }, -- dirty fur
[2] = { ingredientId = 3107, reqItemTier = 0.9, reqItemCount = 2 }, -- raw wood
[3] = { ingredientId = 3106, reqItemTier = 0.9, reqItemCount = 3 }, -- dirty fur
[4] = { ingredientId = 3577, reqItemTier = 0.9, reqItemCount = 3 }, -- raw wood
[5] = { ingredientId = 8194, reqItemTier = 0.9, reqItemCount = 4 }, -- dirty fur
[6] = { ingredientId = 3585, reqItemTier = 0.9, reqItemCount = 20 }, -- raw wood
},
},
...
}
local QUEST_OPCODE = 155
function onProtocolGame(opcode, buffer)
if opcode == QUEST_OPCODE then
handleQuestsMenuOpen(nil, opcode, buffer)
end
end
function init()
-- print("Initializing...")
connect(g_game, {
onGameStart = onGameStart,
onGameEnd = destroy
})
questWindow = g_ui.displayUI('Quests')
questWindow:setVisible(false)
-- g_keyboard.bindKeyDown('Ctrl+A', toggleWindow)
g_keyboard.bindKeyDown('Escape', hideQuestWindow)
-- questButton = modules.client_topmenu.addLeftGameButton('questButton', tr('Quest'), '/modules/game_quests/images/questIcon', toggleWindow)
ProtocolGame.registerExtendedOpcode(QUEST_OPCODE, handleQuestsMenuOpen)
end
function handleQuestsMenuOpen(protocol, opcode, buffer)
local craftData = {}
local craftsData = string.split(buffer, '@')
for _, data in ipairs(craftsData) do
local craft = deserializeCraft(data)
table.insert(craftData, craft)
end
updateQuests(craftData)
openQuestsWindow()
end
function tableToString(tbl)
local str = "{"
for k, v in pairs(tbl) do
str = str .. "[" .. tostring(k) .. "]="
if type(v) == "table" then
str = str .. tableToString(v)
else
str = str .. tostring(v)
end
str = str .. ","
end
str = str .. "}"
return str
end
function deserializeCraft(data)
-- print("Deserializing craft data:", data)
local craft = {}
craft.reqItems = {} -- Cambio "ingredients" a "reqItems"
local parts = string.split(data, ',')
for _, part in ipairs(parts) do
if part ~= '' then
local pair = string.split(part, '=')
if #pair == 2 then
local key = pair[1]
local value = pair[2]
if key == 'reqItems' then -- Cambio "ingredients" a "reqItems"
-- print("Deserializing reqItems:")
local reqItemsData = string.sub(value, 2, -2) -- Cambio de caracteres de delimitación
local reqItems = string.split(reqItemsData, '},') -- Cambio del separador
for _, reqItemData in ipairs(reqItems) do
local item = {}
local itemParts = string.split(reqItemData, ', ')
-- print("ReqItem parts:", table.concat(itemParts, ", "))
for _, itemPart in ipairs(itemParts) do
local itemPair = string.split(itemPart, '=')
local itemKey = itemPair[1]
local itemValue = itemPair[2]
if itemKey == 'ingredientId' then -- Cambio "itemid" a "ingredientId"
itemKey = 'ingredientId'
elseif itemKey == 'count' then -- Agregar soporte para "count"
itemKey = 'count'
elseif itemKey == 'tier' then -- Agregar soporte para "tier"
itemKey = 'tier'
end
-- print("Deserializing " .. itemKey .. ": " .. tostring(itemValue))
item[itemKey] = tonumber(itemValue) or itemValue
end
table.insert(craft.reqItems, item) -- Cambio "ingredients" a "reqItems"
end
-- print("ReqItems after deserialization:", tableToString(craft.reqItems))
else
-- Eliminar las impresiones innecesarias
-- print("Deserializing " .. key .. ": " .. tostring(value))
craft[key] = value
end
else
-- Eliminar las impresiones innecesarias
-- print("Error: Invalid part format:", part)
end
end
end
-- print("Craft after deserialization:", (craft))
return craft
end
function deserializeIngredients(data)
local items = {}
local parts = string.split(data, '|')
for _, part in ipairs(parts) do
local item = {}
local subParts = string.split(part, ',')
for _, subPart in ipairs(subParts) do
local subPair = string.split(subPart, '=')
local subKey = subPair[1]
local subValue = subPair[2]
if subKey == 'itemid' then
subKey = 'ingredientID'
end
item[subKey] = tonumber(subValue) or subValue
end
table.insert(items, item)
end
return items
end
function openQuestsWindow()
toggleQuestWindow()
end
function terminate()
-- print("Terminating...")
disconnect(g_game, {
onGameEnd = destroy
})
-- questButton:destroy()
destroy()
end
function onGameStart()
-- print("Game started.")
if (questWindow) then
questWindow:destroy()
questWindow = nil
end
if not questWindow then
questWindow = g_ui.displayUI('Challenges')
questWindow:setVisible(false)
end
end
function destroy()
-- print("Destroying window...")
if (questWindow) then
questWindow:destroy()
questWindow = nil
end
end
function toggleQuestWindow()
if (not g_game.isOnline()) then
return
end
if (questWindow:isVisible()) then
questWindow:setVisible(false)
else
questWindow:setVisible(true)
end
end
function hideQuestWindow()
if (not g_game.isOnline()) then
return
end
if (questWindow:isVisible()) then
questWindow:setVisible(false)
end
end
function getSelectedQuestName()
-- print("Getting selected craft name...")
return selectedQuestName
end
local aidSelected = nil
function onItemSelect(list, focusedChild, unfocusedChild, reason)
-- print("Selecting item...")
if focusedChild then
selectedQuestName = focusedChild.name:getText()
-- print('Selected Craft: ' .. selectedQuestName)
-- Encuentra la receta seleccionada en la tabla defaultQuests
for _, craft in pairs(defaultQuests) do
if string.lower(craft.item) == string.lower(selectedQuestName) then
aidSelected = craft.aid -- Obtiene el aid de la receta
break
end
end
if aid then
-- print('AID: ' .. aidSelected) -- Muestra el AID de la receta seleccionada
else
-- print('Recipe not found in defaultQuests')
end
else
-- print('Focused child is nil')
end
end
-- function details(list, focusedChild, unfocusedChild, reason)
-- g_game.talk('!recipe '..selectedQuestName..'')
-- end
function buyRecipe()
-- print('Selected details: ' .. selectedQuestName)
if selectedQuestName ~= nil then
g_game.talk('!challenge ' .. aidSelected)
g_game.talk('Accept')
questWindow:setVisible(false)
else
return displayErrorBox('Error', 'Select a valid quest.')
end
end
function onIngredientSelect(list, focusedChild, unfocusedChild, reason, selectedIngredientName)
-- print("Selecting Ingredient...")
if focusedChild then
-- print('Selected Ingredient: ' .. selectedIngredientName)
g_game.talk('!ingredient ' .. selectedIngredientName) -- Enviar un mensaje al juego con el nombre del ingrediente
else
-- print('Focused child is nil')
end
end
function onFilterSearch()
-- print("Filtering search...")
addEvent(function()
local searchText = questWindow.listSearch.search:getText():lower():trim()
local children = questWindow.selectionList:getChildren()
if (searchText:len() >= 1) then
for _, child in ipairs(children) do
local text = child.name:getText():lower()
if (text:find(searchText)) then
child:show()
else
child:hide()
end
end
else
for _, child in ipairs(children) do
child:show()
end
end
end)
end
local function formatNumber(num)
return tostring(math.floor(num)):reverse():gsub("(%d%d%d)", "%1,"):reverse():gsub("^,", "")
end
-- Función para convertir una tabla a una cadena de caracteres
function tableToString(tbl)
local str = '{'
for k, v in pairs(tbl) do
str = str .. tostring(k) .. '=' .. tostring(v) .. ', '
end
str = str:sub(1, -3) .. '}' -- Eliminar la coma y el espacio adicionales al final y agregar el corchete de cierre
return str
end
-- Ahora puedes llamar a la función tableToString para mostrar la representación de la tabla en cualquier parte del script donde lo desees.
function updateQuests(crafts)
questWindow.selectionList:destroyChildren()
-- Ordenar la tabla crafts en función de la experiencia total
for _, craft in ipairs(crafts) do
local button = g_ui.createWidget("SelectionButtonQuest", questWindow.selectionList)
button:setId(craft.itemID)
button.item:setOutfit({ type = craft.itemID, head = 19, body = 19, legs = 19, feet = 19})
-- button.item:setItemCount(craft.amount)
button.name:setText(craft.item)
for i = 1, 6 do
local ingredientWidget = button['ingredientsReq' .. i]
if ingredientWidget then
ingredientWidget:setItemId(nil)
ingredientWidget:setItemCount(nil)
ingredientWidget:setVisible(false)
end
end
local foundCraft = nil
for _, defaultCraft in pairs(defaultQuests) do
if string.lower(defaultCraft.item) == string.lower(craft.item) then
foundCraft = defaultCraft
break
end
end
local totalExp = foundCraft.type
local getPrice = 0
if foundCraft then
getPrice = foundCraft.price
-- print(totalExp)
local numIngredients = math.min(#foundCraft.reqItems, 6)
for i = 1, numIngredients do
local ingredient = foundCraft.reqItems[i]
local ingredientWidget = button['ingredientsReq' .. i]
if ingredient and ingredientWidget then
ingredientWidget:setItemId(ingredient.ingredientId)
ingredientWidget:setItemCount(ingredient.reqItemCount or 1)
ingredientWidget:setVisible(true)
-- Calculamos la experiencia total para este ingrediente
-- local expForIngredient = (ingredient.type)
-- totalExp = totalExp + expForIngredient
end
end
else
-- print("Error: Recipe not found in defaultCrafts")
-- print("Item: " .. craft.item)
end
if foundCraft and foundCraft.reagent then
button.reqReagent:setText(foundCraft.reagent)
else
button.reqReagent:setVisible(false)
end
-- Configurar la experiencia como recompensa
if foundCraft then
button.rewardCraftPoints:setText('' .. formatNumber(totalExp) .. ' Exp')
button.priceCraft:setText('' .. formatNumber(getPrice) .. '$')
else
button.rewardCraftPoints:setText('Exp: 0')
end
button.progress:setWidth(0)
button.onClick = function(widget) onItemSelect(nil, widget, nil, nil) end
end
end
function toggleQuestWindow()
if (not g_game.isOnline()) then
return
end
if (questWindow:isVisible()) then
questWindow:setVisible(false)
else
questWindow:setVisible(true)
end
end
function hideQuestWindow()
if (not g_game.isOnline()) then
return
end
-- if (window:isVisible()) then
-- window:setVisible(false)
-- end
end
function setCraftConsoleText(text, color)
if (not color) then
color = 'white'
end
questWindow.info:setText(text)
questWindow.info:setColor(color)
if consoleEvent then
removeEvent(consoleEvent)
consoleEvent = nil
end
consoleEvent = scheduleEvent(function()
questWindow.info:setText('')
end, 5000)
return true
end
and this is my quest.otui
CSS:
MiniPanel44 < Panel
text-offset: 0 3
text-align: top
image-source: /images/ui/minipanel
image-border: 2
image-border-top: 19
padding-left: 7
padding-bottom: 7
padding-top: 24
padding-right: 7
SelectionButtonQuest < Panel
image-source: /images/ui/button
image-color: #dfdfdf
image-clip: 0 0 22 23
image-border: 3
border: 1 alpha
focusable: true
phantom: false
$hover:
border: 1 white
$focus:
border: 1 white
image-color: #ffffff
Panel
id: progress
image-source: /images/ui/panel_flat
image-color: #00ff00
margin-left: 1
margin-top: 1
anchors.top: parent.top
anchors.left: parent.left
size: 159 158
UICreature
id: item
size: 90 90
margin-top: 26
margin-left: 8
anchors.top: parent.top
phantom: true
anchors.left: prev.left
background-color: #00000077
border: 1 black
Label
id: name
anchors.bottom: prev.top
anchors.left: parent.left
anchors.right: parent.right
margin-left: 3
margin-bottom: 8
text-align: left
text-wrap: true
background-color: #00000077
text-border: 50 black
Label
id: title
anchors.top: parent.top
anchors.left: item.right
text: Rewards:
margin-top: 30
margin-left: 65
text-align: left
text-wrap: true
Label
id: kills
anchors.top: item.bottom
anchors.left: parent.left
anchors.right: parent.right
text-align: center
margin-top: -5
text-wrap: true
UIItem
id: ingredientsReq1
anchors.top: title.bottom
anchors.left: item.right
text-align: right
margin-left: 15
margin-right: 5
margin-top: 5
text-wrap: true
height: 32
width: 32
focusable: true
phantom: false
onMousePress: modules.game_quests.onIngredientClick(1)
background-color: #00000077
border: 1 alpha
$hover:
border: 1 white
$focus:
border: 1 white
image-color: #ffffff
UIItem
id: ingredientsReq2
anchors.top: title.bottom
anchors.left: ingredientsReq1.right
text-align: right
margin-right: 5
margin-left: 5
margin-top: 5
text-wrap: true
height: 32
width: 32
focusable: true
onMousePress: modules.game_quests.onIngredientClick(2)
background-color: #00000077
border: 1 alpha
$hover:
border: 1 white
$focus:
border: 1 white
image-color: #ffffff
UIItem
id: ingredientsReq3
anchors.top: title.bottom
anchors.left: ingredientsReq2.right
text-align: right
margin-left: 5
margin-right: 5
margin-top: 5
text-wrap: true
height: 32
width: 32
focusable: true
onMousePress: modules.game_quests.onIngredientClick(3)
background-color: #00000077
border: 1 alpha
$hover:
border: 1 white
$focus:
border: 1 white
image-color: #ffffff
UIItem
id: ingredientsReq4
anchors.top: title.bottom
anchors.left: ingredientsReq3.right
text-align: right
margin-right: 5
margin-left: 5
margin-top: 5
text-wrap: true
height: 32
width: 32
focusable: true
onMousePress: modules.game_quests.onIngredientClick(4)
background-color: #00000077
border: 1 alpha
$hover:
border: 1 white
$focus:
border: 1 white
image-color: #ffffff
UIItem
id: ingredientsReq5
anchors.top: title.bottom
anchors.left: ingredientsReq4.right
text-align: right
margin-left: 5
margin-right: 5
margin-top: 5
text-wrap: true
height: 32
width: 32
focusable: true
onMousePress: modules.game_quests.onIngredientClick(5)
background-color: #00000077
border: 1 alpha
$hover:
border: 1 white
$focus:
border: 1 white
image-color: #ffffff
UIItem
id: ingredientsReq6
anchors.top: title.bottom
anchors.left: ingredientsReq5.right
text-align: right
margin-right: 5
margin-left: 5
margin-top: 5
text-wrap: true
height: 32
width: 32
focusable: true
onMousePress: modules.game_quests.onIngredientClick(6)
background-color: #00000077
border: 1 alpha
$hover:
border: 1 white
$focus:
border: 1 white
image-color: #ffffff
Label
id: reqReagent
anchors.top: item.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
text-align: left
margin-bottom: 10
margin-left: 3
text-wrap: true
Label
id: priceCraft
anchors.top: parent.top
anchors.right: parent.right
anchors.left: title.right
text-align: right
margin-top: 5
margin-right: 15
text-wrap: true
Label
id: rewardCraftPoints
anchors.top: parent.top
anchors.left: title.right
text-align: left
margin-top: 30
margin-left: 3
text-wrap: true
MainQuestWindow
size: 415 370
id: questWindow
!text: tr('Challenges')
@onEnter: modules.game_quests.toggleQuestWindow()
@onEscape: modules.game_quests.toggleQuestWindow()
MiniPanel4
id: listSearch
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
margin-left: 5
height: 50
text: Filter
TextEdit
id: search
anchors.fill: parent
placeholder: Search by name
ScrollablePanel
id: selectionList
anchors.top: listSearch.bottom
anchors.left: listSearch.left
anchors.right: parent.right
anchors.bottom: separator.top
margin-top: 5
margin-bottom: 5
image-source: /images/ui/panel_flat
image-border: 1
padding: 4
padding-right: 16
vertical-scrollbar: selectionScroll
layout:
type: grid
cell-size: 350 225
cell-spacing: 8
flow: true
VerticalScrollBar
id: selectionScroll
anchors.top: prev.top
anchors.right: prev.right
anchors.bottom: prev.bottom
step: 80
pixel-scroll: true
HorizontalSeparator
id: separator
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
margin-bottom: 30
Label
id: info
anchors.top: separator.top
anchors.left: parent.left
width: 140
height: 45
text-align: center
text-wrap: true
Button
id: toggleButton
anchors.bottom: parent.bottom
anchors.right: parent.right
text: Close
width: 65
@onClick: modules.game_quests.toggleQuestWindow()
Button
id: finishButton
anchors.bottom: parent.bottom
anchors.right: toggleButton.left
text: Finish
width: 55
margin-right: 5
@onClick: modules.game_quests.finish()
Button
id: startButton
anchors.bottom: parent.bottom
anchors.right: toggleButton.left
text: Start
width: 55
margin-right: 5
@onClick: modules.game_quests.start()
Button
id: buyRecipeButton
anchors.bottom: parent.bottom
anchors.right: toggleButton.left
text: Accept
width: 80
margin-right: 5
@onClick: modules.game_quests.buyRecipe()