• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

OTClient @OnClick function

Hookah

Member
Joined
Jan 20, 2023
Messages
57
Reaction score
8
I'm trying to make questlog button works from inventory and not from a sidepanel or topmenu like this:
set.png
Changed Stop to 'QuestLog' then changed @OnClick function but it gives a nil value I have so many days trying to understand how OTClient works and im getting some but regarding to this I just dont get it

Lua:
    [C]: in function '__index'
    /modules/game_inventory/inventory.otui:261: [@onClick]:2: in function </modules/game_inventory/inventory.otui:261: [@onClick]:1>
ERROR: protected lua call failed: /modules/game_inventory/inventory.otui:261: [@onClick]:2: attempt to index field 'game_questlog' (a nil value)
stack traceback:
    [C]: in function '__index'
    /modules/game_inventory/inventory.otui:261: [@onClick]:2: in function </modules/game_inventory/inventory.otui:261: [@onClick]:1>
I just want a buttom that when you click it starts a module in this case Questlog. Thank you for reading
 
I'm trying to make questlog button works from inventory and not from a sidepanel or topmenu like this:
View attachment 73073
Changed Stop to 'QuestLog' then changed @OnClick function but it gives a nil value I have so many days trying to understand how OTClient works and im getting some but regarding to this I just dont get it

Lua:
    [C]: in function '__index'
    /modules/game_inventory/inventory.otui:261: [@onClick]:2: in function </modules/game_inventory/inventory.otui:261: [@onClick]:1>
ERROR: protected lua call failed: /modules/game_inventory/inventory.otui:261: [@onClick]:2: attempt to index field 'game_questlog' (a nil value)
stack traceback:
    [C]: in function '__index'
    /modules/game_inventory/inventory.otui:261: [@onClick]:2: in function </modules/game_inventory/inventory.otui:261: [@onClick]:1>
I just want a buttom that when you click it starts a module in this case Questlog. Thank you for reading

You need go to your questlog.lua and add in your last line:

Lua:
function showQuestlog()
    questLogWindow:show()
end

In your inventory.otui onclick function:
CSS:
@onClick: modules.game_questlog.showQuestlog()
 
You need go to your questlog.lua and add in your last line:

Lua:
function showQuestlog()
    questLogWindow:show()
end

In your inventory.otui onclick function:
CSS:
@onClick: modules.game_questlog.showQuestlog()

Tried it but I still have nil value o_O

Lua:
ERROR: protected lua call failed: /modules/game_inventory/inventory.otui:261: [@onClick]:2: attempt to index field 'game_questlog' (a nil value)
stack traceback:
    [C]: in function '__index'
    /modules/game_inventory/inventory.otui:261: [@onClick]:2: in function </modules/game_inventory/inventory.otui:261: [@onClick]:1>
 
game_questlog.otui
Lua:
QuestTrackerLabel < Panel
  height: 20
  layout:
    type: verticalBox
    fit-children: true

  $!first:
    margin-top: 3

  Label
    id: description
    text-align: center
    text-wrap: true
    text-auto-resize: true

  HorizontalSeparator
    margin-top: 3

QuestLabel < Label
  font: verdana-11px-monochrome
  height: 18
  text-offset: 2 1
  focusable: true
  color: #aaaaaa
  background-color: #484848

  $checked:
    background-color: #414141

  $focus:
    background-color: #ffffff22

QuestLog < Panel
  TextList
    id: questList
    anchors.fill: parent
    margin-bottom: 20
    focusable: false
    background-color: #484848
    vertical-scrollbar: questListScrollBar

  VerticalScrollBar
    id: questListScrollBar
    anchors.top: questList.top
    anchors.bottom: questList.bottom
    anchors.right: questList.right
    step: 14
    pixels-scroll: true

MissionLog < Panel
  Label
    id: questName
    anchors.top: parent.top
    anchors.left: parent.left
    anchors.right: parent.right
    text-align: left
    text: questline name

  TextList
    id: missionList
    anchors.top: prev.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-top: 3
    height: 133
    padding: 1
    focusable: false
    vertical-scrollbar: missionListScrollBar
    background-color: #484848

  VerticalScrollBar
    id: missionListScrollBar
    anchors.top: missionList.top
    anchors.right: missionList.right
    anchors.bottom: missionList.bottom
    step: 14
    pixels-scroll: true

  CheckBox
    id: track
    anchors.bottom: parent.bottom
    anchors.left: parent.left
    anchors.right: parent.right
    margin-bottom: 25
    !text: tr('Show in quest tracker')
    @onClick: modules.game_questlog.onTrackOptionChange(self)
    enabled: false

  FlatLabel
    id: missionDescription
    anchors.top: missionList.bottom
    anchors.left: parent.left
    anchors.right: missionListScrollBar.right
    anchors.bottom: prev.top
    background-color: #363636
    margin-bottom: 10
    margin-top: 10
    text-wrap: true

QuestLogWindow < MainWindow
  id: questLogWindow
  !text: tr('Quest Log')
  size: 330 405
  @onEscape: modules.game_questlog.back()
  $mobile:
    size: 330 350

  QuestLog
    id: questlog
    anchors.top: parent.top
    anchors.bottom: bottomSep.top
    anchors.left: parent.left
    anchors.right: parent.right
    visible: false
 
  MissionLog
    id: missionlog
    anchors.fill: prev

  HorizontalSeparator
    id: bottomSep
    anchors.right: parent.right
    anchors.left: parent.left
    anchors.bottom: closeButton.top
    margin-bottom: 8   

  Button
    id: closeButton
    !text: tr('Close')
    font: cipsoftFont
    anchors.right: parent.right
    anchors.bottom: parent.bottom
    color: #ffffff
    size: 45 21
    @onClick: modules.game_questlog.back()

  Button
    id: showButton
    anchors.verticalCenter: prev.verticalCenter
    anchors.right: prev.left
    margin-right: 3
    color: #ffffff
    size: 45 21
    !text: tr('Show')
    font: cipsoftFont
    @onClick: modules.game_questlog.showQuestLine()

  Button
    id: trackerButton
    anchors.verticalCenter: prev.verticalCenter
    anchors.left: parent.left
    margin-right: 3
    color: #ffffff
    size: 80 21
    text-align: center
    !text: tr('Quest Tracker')
    font: cipsoftFont
    @onClick: modules.game_questlog.toggle()

QuestTracker < MiniWindow
  id: questTracker
  !text: tr('Quest Tracker')
  height: 60
  icon: /images/topbuttons/quest_tracker

  MiniWindowContents
    padding-left: 5
    padding-right: 5
    padding-top: 5
    layout: verticalBox

    Panel
      id: list
      layout:
        type: verticalBox
        fit-children: true

    Panel
      height: 20
      margin-top: 5
      Button
        !text: tr('Add Tracked Quest')
        anchors.fill: parent
        margin-left: 30
        margin-right: 30
        font: cipsoftFont
        color: #FFFFFF
        @onClick: g_game.requestQuestLog()

game_inventory.lua

Code:
Icons = {}
Icons[PlayerStates.Poison] = { tooltip = tr('You are poisoned'), path = '/images/game/states/poisoned', id = 'condition_poisoned' }
Icons[PlayerStates.Burn] = { tooltip = tr('You are burning'), path = '/images/game/states/burning', id = 'condition_burning' }
Icons[PlayerStates.Energy] = { tooltip = tr('You are electrified'), path = '/images/game/states/electrified', id = 'condition_electrified' }
Icons[PlayerStates.Drunk] = { tooltip = tr('You are drunk'), path = '/images/game/states/drunk', id = 'condition_drunk' }
Icons[PlayerStates.ManaShield] = { tooltip = tr('You are protected by a magic shield'), path = '/images/game/states/magic_shield', id = 'condition_magic_shield' }
Icons[PlayerStates.Paralyze] = { tooltip = tr('You are paralysed'), path = '/images/game/states/slowed', id = 'condition_slowed' }
Icons[PlayerStates.Haste] = { tooltip = tr('You are hasted'), path = '/images/game/states/haste', id = 'condition_haste' }
Icons[PlayerStates.Swords] = { tooltip = tr('You may not logout during a fight'), path = '/images/game/states/logout_block', id = 'condition_logout_block' }
Icons[PlayerStates.Drowning] = { tooltip = tr('You are drowning'), path = '/images/game/states/drowning', id = 'condition_drowning' }
Icons[PlayerStates.Freezing] = { tooltip = tr('You are freezing'), path = '/images/game/states/freezing', id = 'condition_freezing' }
Icons[PlayerStates.Dazzled] = { tooltip = tr('You are dazzled'), path = '/images/game/states/dazzled', id = 'condition_dazzled' }
Icons[PlayerStates.Cursed] = { tooltip = tr('You are cursed'), path = '/images/game/states/cursed', id = 'condition_cursed' }
Icons[PlayerStates.PartyBuff] = { tooltip = tr('You are strengthened'), path = '/images/game/states/strengthened', id = 'condition_strengthened' }
Icons[PlayerStates.PzBlock] = { tooltip = tr('You may not logout or enter a protection zone'), path = '/images/game/states/protection_zone_block', id = 'condition_protection_zone_block' }
Icons[PlayerStates.Pz] = { tooltip = tr('You are within a protection zone'), path = '/images/game/states/protection_zone', id = 'condition_protection_zone' }
Icons[PlayerStates.Bleeding] = { tooltip = tr('You are bleeding'), path = '/images/game/states/bleeding', id = 'condition_bleeding' }
Icons[PlayerStates.Hungry] = { tooltip = tr('You are hungry'), path = '/images/game/states/hungry', id = 'condition_hungry' }

SkullIcons = {}
SkullIcons[SkullGreen] = { tooltip = tr('You are a member of a party'), path = '/images/game/states/skullgreen', id = 'skullIcon' }
SkullIcons[SkullWhite] = { tooltip = tr('You have attacked an unmarked player'), path = '/images/game/states/skullwhite', id = 'skullIcon' }
SkullIcons[SkullRed] = { tooltip = tr('You have killed too many unmarked players'), path = '/images/game/states/skullred', id = 'skullIcon' }

InventorySlotStyles = {
  [InventorySlotHead] = "HeadSlot",
  [InventorySlotNeck] = "NeckSlot",
  [InventorySlotBack] = "BackSlot",
  [InventorySlotBody] = "BodySlot",
  [InventorySlotRight] = "RightSlot",
  [InventorySlotLeft] = "LeftSlot",
  [InventorySlotLeg] = "LegSlot",
  [InventorySlotFeet] = "FeetSlot",
  [InventorySlotFinger] = "FingerSlot",
  [InventorySlotAmmo] = "AmmoSlot"
}

inventoryWindow = nil
inventoryPanel = nil
inventoryButton = nil
purseButton = nil

combatControlsWindow = nil
fightOffensiveBox = nil
fightBalancedBox = nil
fightDefensiveBox = nil
chaseModeButton = nil
safeFightButton = nil
mountButton = nil
fightModeRadioGroup = nil
chaseModeRadioGroup = nil
chaseModeStandBox = nil
chaseModeChaseBox = nil
buttonPvp = nil
skillsButton = nil
battleButton = nil
vipButton = nil

soulLabel = nil
capLabel = nil
conditionPanel = nil

function init()
  connect(LocalPlayer, {
    onInventoryChange = onInventoryChange,
    onBlessingsChange = onBlessingsChange
  })
  connect(g_game, { onGameStart = refresh })


  inventoryWindow = g_ui.loadUI('inventory', modules.game_interface.getRightPanel())
  inventoryWindow:disableResize()
  inventoryPanel = inventoryWindow:getChildById('contentsPanel')
  if not inventoryWindow.forceOpen then
    inventoryButton = modules.client_topmenu.addRightGameToggleButton('inventoryButton', tr('Inventory') .. ' (Ctrl+I)', '/images/topbuttons/inventory', toggle)
    inventoryButton:setOn(true)
  end
 
  purseButton = inventoryWindow:recursiveGetChildById('purseButton')
  purseButton.onClick = function()
    local purse = g_game.getLocalPlayer():getInventoryItem(InventorySlotPurse)
    if purse then
      g_game.use(purse)
    end
  end
 
  skillsButton = inventoryWindow:recursiveGetChildById('skillsButton')
  battleButton = inventoryWindow:recursiveGetChildById('battleButton')
  vipButton = inventoryWindow:recursiveGetChildById('vipButton')

  -- controls
  fightOffensiveBox = inventoryWindow:recursiveGetChildById('fightOffensiveBox')
  fightBalancedBox = inventoryWindow:recursiveGetChildById('fightBalancedBox')
  fightDefensiveBox = inventoryWindow:recursiveGetChildById('fightDefensiveBox')
 
  chaseModeStandBox = inventoryWindow:recursiveGetChildById('chaseModeBoxStand')
  chaseModeChaseBox = inventoryWindow:recursiveGetChildById('chaseModeBoxChase')

  chaseModeButton = inventoryWindow:recursiveGetChildById('chaseModeBox')
  safeFightButton = inventoryWindow:recursiveGetChildById('safeFightBox')
  buttonPvp = inventoryWindow:recursiveGetChildById('buttonPvp')

  mountButton = inventoryWindow:recursiveGetChildById('mountButton')
  mountButton.onClick = onMountButtonClick

  whiteDoveBox = inventoryWindow:recursiveGetChildById('whiteDoveBox')
  whiteHandBox = inventoryWindow:recursiveGetChildById('whiteHandBox')
  yellowHandBox = inventoryWindow:recursiveGetChildById('yellowHandBox')
  redFistBox = inventoryWindow:recursiveGetChildById('redFistBox')

  fightModeRadioGroup = UIRadioGroup.create()
  fightModeRadioGroup:addWidget(fightOffensiveBox)
  fightModeRadioGroup:addWidget(fightBalancedBox)
  fightModeRadioGroup:addWidget(fightDefensiveBox)

  chaseModeRadioGroup = UIRadioGroup.create()
  chaseModeRadioGroup:addWidget(chaseModeStandBox)
  chaseModeRadioGroup:addWidget(chaseModeChaseBox)

  connect(fightModeRadioGroup, { onSelectionChange = onSetFightMode })
  connect(chaseModeRadioGroup, { onSelectionChange = onSetChaseMode })
  connect(safeFightButton, { onCheckChange = onSetSafeFight })
  if buttonPvp then
    connect(buttonPvp, { onClick = onSetSafeFight2 }) 
  end
  connect(g_game, {
    onGameStart = online,
    onGameEnd = offline,
    onFightModeChange = update,
    onChaseModeChange = update,
    onSafeFightChange = update,
    onPVPModeChange   = update,
    onWalk = check,
    onAutoWalk = check
  })

  connect(LocalPlayer, { onOutfitChange = onOutfitChange })

  if g_game.isOnline() then
    online()
  end
-- controls end

-- status
  soulLabel = inventoryWindow:recursiveGetChildById('soulLabel')
  capLabel = inventoryWindow:recursiveGetChildById('capLabel')
  conditionPanel = inventoryWindow:recursiveGetChildById('conditionPanel')


  connect(LocalPlayer, { onStatesChange = onStatesChange,
                         onSoulChange = onSoulChange,
                         onFreeCapacityChange = onFreeCapacityChange })
-- status end
 
  connect(LocalPlayer, { onSkullChange = onSkullChange } )

  refresh()
  inventoryWindow:setup()
  inventoryWindow:open()
end

function terminate()
  disconnect(LocalPlayer, {
    onInventoryChange = onInventoryChange,
    onBlessingsChange = onBlessingsChange
  })
  disconnect(g_game, { onGameStart = refresh })

  -- controls
  if g_game.isOnline() then
    offline()
  end

  fightModeRadioGroup:destroy()
 
  disconnect(g_game, {
    onGameStart = online,
    onGameEnd = offline,
    onFightModeChange = update,
    onChaseModeChange = update,
    onSafeFightChange = update,
    onPVPModeChange   = update,
    onWalk = check,
    onAutoWalk = check
  })

  disconnect(LocalPlayer, { onOutfitChange = onOutfitChange })
  -- controls end
  -- status
  disconnect(LocalPlayer, { onStatesChange = onStatesChange,
                         onSoulChange = onSoulChange,
                         onFreeCapacityChange = onFreeCapacityChange })
  -- status end

  disconnect(LocalPlayer, { onSkullChange = onSkullChange } )

  inventoryWindow:destroy()
  if inventoryButton then
    inventoryButton:destroy()
  end
end

function toggleAdventurerStyle(hasBlessing)
  for slot = InventorySlotFirst, InventorySlotLast do
    local itemWidget = inventoryPanel:getChildById('slot' .. slot)
    if itemWidget then
      itemWidget:setOn(hasBlessing)
    end
  end
end

function refresh()
  local player = g_game.getLocalPlayer()
  for i = InventorySlotFirst, InventorySlotPurse do
    if g_game.isOnline() then
      onInventoryChange(player, i, player:getInventoryItem(i))
    else
      onInventoryChange(player, i, nil)
    end
    toggleAdventurerStyle(player and Bit.hasBit(player:getBlessings(), Blessings.Adventurer) or false)
  end
  if player then
    onSoulChange(player, player:getSoul())
    onFreeCapacityChange(player, player:getFreeCapacity())
    onStatesChange(player, player:getStates(), 0)
  end

  purseButton:setVisible(g_game.getFeature(GamePurseSlot))
end

function toggle()
  if not inventoryButton then
    return
  end
  if inventoryButton:isOn() then
    inventoryWindow:close()
    inventoryButton:setOn(false)
  else
    inventoryWindow:open()
    inventoryButton:setOn(true)
  end
end

function onMiniWindowClose()
  if not inventoryButton then
    return
  end
  inventoryButton:setOn(false)
end

-- hooked events
function onInventoryChange(player, slot, item, oldItem)
  if slot > InventorySlotPurse then return end

  if slot == InventorySlotPurse then
    if g_game.getFeature(GamePurseSlot) then
      --purseButton:setEnabled(item and true or false)
    end
    return
  end

  local itemWidget = inventoryPanel:getChildById('slot' .. slot)
  if item then
    itemWidget:setStyle('InventoryItem')
    itemWidget:setItem(item)
  else
    itemWidget:setStyle(InventorySlotStyles[slot])
    itemWidget:setItem(nil)
  end
end

function onBlessingsChange(player, blessings, oldBlessings)
  local hasAdventurerBlessing = Bit.hasBit(blessings, Blessings.Adventurer)
  if hasAdventurerBlessing ~= Bit.hasBit(oldBlessings, Blessings.Adventurer) then
    toggleAdventurerStyle(hasAdventurerBlessing)
  end
end


-- controls
function update()
  local fightMode = g_game.getFightMode()
  if fightMode == FightOffensive then
    fightModeRadioGroup:selectWidget(fightOffensiveBox)
  elseif fightMode == FightBalanced then
    fightModeRadioGroup:selectWidget(fightBalancedBox)
  else
    fightModeRadioGroup:selectWidget(fightDefensiveBox)
  end

  local chaseMode = g_game.getChaseMode()
  if chaseMode == ChaseOpponent then
    chaseModeRadioGroup:selectWidget(chaseModeChaseBox)
  else
    chaseModeRadioGroup:selectWidget(chaseModeStandBox)
  end

  local safeFight = g_game.isSafeFight()
  safeFightButton:setChecked(not safeFight)
  if buttonPvp then
    if safeFight then
      buttonPvp:setOn(false)
    else
      buttonPvp:setOn(true)
    end
  end
 
  if g_game.getFeature(GamePVPMode) then
    local pvpMode = g_game.getPVPMode()
    local pvpWidget = getPVPBoxByMode(pvpMode)
  end
end

function check()
  if modules.client_options.getOption('autoChaseOverride') then
    if g_game.isAttacking() and g_game.getChaseMode() == ChaseOpponent then
      g_game.setChaseMode(DontChase)
    end
  end
end

function online()
  local player = g_game.getLocalPlayer()
  if player then
    local char = g_game.getCharacterName()

    local lastCombatControls = g_settings.getNode('LastCombatControls')

    if not table.empty(lastCombatControls) then
      if lastCombatControls[char] then
        g_game.setFightMode(lastCombatControls[char].fightMode)
        g_game.setChaseMode(lastCombatControls[char].chaseMode)
        g_game.setSafeFight(lastCombatControls[char].safeFight)
        if lastCombatControls[char].pvpMode then
          g_game.setPVPMode(lastCombatControls[char].pvpMode)
        end
      end
    end

    if g_game.getFeature(GamePlayerMounts) then
      mountButton:setVisible(true)
      mountButton:setChecked(player:isMounted())
    else
      mountButton:setVisible(false)
    end
  end

  update()
end

function offline()
  local lastCombatControls = g_settings.getNode('LastCombatControls')
  if not lastCombatControls then
    lastCombatControls = {}
  end

  conditionPanel:destroyChildren()

  local player = g_game.getLocalPlayer()
  if player then
    local char = g_game.getCharacterName()
    lastCombatControls[char] = {
      fightMode = g_game.getFightMode(),
      chaseMode = g_game.getChaseMode(),
      safeFight = g_game.isSafeFight()
    }

    if g_game.getFeature(GamePVPMode) then
      lastCombatControls[char].pvpMode = g_game.getPVPMode()
    end

    -- save last combat control settings
    g_settings.setNode('LastCombatControls', lastCombatControls)
  end
end

function onSetFightMode(self, selectedFightButton)
  if selectedFightButton == nil then return end
  local buttonId = selectedFightButton:getId()
  local fightMode
  if buttonId == 'fightOffensiveBox' then
    fightMode = FightOffensive
  elseif buttonId == 'fightBalancedBox' then
    fightMode = FightBalanced
  else
    fightMode = FightDefensive
  end
  g_game.setFightMode(fightMode)
end

function onSetChaseMode(self, selectedButton)
  if selectedButton == nil then return end
  local buttonId = selectedButton:getId()
  local chaseMode
  if buttonId == 'chaseModeBoxChase' then
    chaseMode = ChaseOpponent
  else
    chaseMode = DontChase
  end
  g_game.setChaseMode(chaseMode)
end

function onSetSafeFight(self, checked)
  g_game.setSafeFight(not checked)
  if buttonPvp then
    if not checked then
      buttonPvp:setOn(false)
    else
      buttonPvp:setOn(true) 
    end
  end
end

function onSetSafeFight2(self)
  onSetSafeFight(self, not safeFightButton:isChecked())
end

function onSetPVPMode(self, selectedPVPButton)
  if selectedPVPButton == nil then
    return
  end

  local buttonId = selectedPVPButton:getId()
  local pvpMode = PVPWhiteDove
  if buttonId == 'whiteDoveBox' then
    pvpMode = PVPWhiteDove
  elseif buttonId == 'whiteHandBox' then
    pvpMode = PVPWhiteHand
  elseif buttonId == 'yellowHandBox' then
    pvpMode = PVPYellowHand
  elseif buttonId == 'redFistBox' then
    pvpMode = PVPRedFist
  end

  g_game.setPVPMode(pvpMode)
end

function onMountButtonClick(self, mousePos)
  local player = g_game.getLocalPlayer()
  if player then
    player:toggleMount()
  end
end

function onOutfitChange(localPlayer, outfit, oldOutfit)
  if outfit.mount == oldOutfit.mount then
    return
  end

  mountButton:setChecked(outfit.mount ~= nil and outfit.mount > 0)
end

function getPVPBoxByMode(mode)
  local widget = nil
  if mode == PVPWhiteDove then
    widget = whiteDoveBox
  elseif mode == PVPWhiteHand then
    widget = whiteHandBox
  elseif mode == PVPYellowHand then
    widget = yellowHandBox
  elseif mode == PVPRedFist then
    widget = redFistBox
  end
  return widget
end

-- status
function toggleIcon(bitChanged)
  local icon = conditionPanel:getChildById(Icons[bitChanged].id)
  if icon then
    icon:destroy()
  else
    icon = loadIcon(bitChanged)
    icon:setParent(conditionPanel)
  end
end

function loadIcon(bitChanged)
  local icon = g_ui.createWidget('ConditionWidget', conditionPanel)
  icon:setId(Icons[bitChanged].id)
  icon:setImageSource(Icons[bitChanged].path)
  icon:setTooltip(Icons[bitChanged].tooltip)
  return icon
end

function onSoulChange(localPlayer, soul)
  if not soul then return end
  soulLabel:setText(tr('Soul') .. ':\n' .. soul)
end

function onFreeCapacityChange(player, freeCapacity)
  if not freeCapacity then return end
  if freeCapacity > 99 then
    freeCapacity = math.floor(freeCapacity * 10) / 10
  end
  if freeCapacity > 999 then
    freeCapacity = math.floor(freeCapacity)
  end
  if freeCapacity > 99999 then
    freeCapacity = math.min(9999, math.floor(freeCapacity/1000)) .. "k"
  end
  capLabel:setText(tr('Cap') .. ':\n' .. (freeCapacity*100))
end

function onStatesChange(localPlayer, now, old)
  if now == old then return end
  local bitsChanged = bit32.bxor(now, old)
  for i = 1, 32 do
    local pow = math.pow(2, i-1)
    if pow > bitsChanged then break end
    local bitChanged = bit32.band(bitsChanged, pow)
    if bitChanged ~= 0 then
      toggleIcon(bitChanged)
    end
  end
end
 
game_questlog.otui


game_inventory.lua

Code:
Icons = {}
Icons[PlayerStates.Poison] = { tooltip = tr('You are poisoned'), path = '/images/game/states/poisoned', id = 'condition_poisoned' }
Icons[PlayerStates.Burn] = { tooltip = tr('You are burning'), path = '/images/game/states/burning', id = 'condition_burning' }
Icons[PlayerStates.Energy] = { tooltip = tr('You are electrified'), path = '/images/game/states/electrified', id = 'condition_electrified' }
Icons[PlayerStates.Drunk] = { tooltip = tr('You are drunk'), path = '/images/game/states/drunk', id = 'condition_drunk' }
Icons[PlayerStates.ManaShield] = { tooltip = tr('You are protected by a magic shield'), path = '/images/game/states/magic_shield', id = 'condition_magic_shield' }
Icons[PlayerStates.Paralyze] = { tooltip = tr('You are paralysed'), path = '/images/game/states/slowed', id = 'condition_slowed' }
Icons[PlayerStates.Haste] = { tooltip = tr('You are hasted'), path = '/images/game/states/haste', id = 'condition_haste' }
Icons[PlayerStates.Swords] = { tooltip = tr('You may not logout during a fight'), path = '/images/game/states/logout_block', id = 'condition_logout_block' }
Icons[PlayerStates.Drowning] = { tooltip = tr('You are drowning'), path = '/images/game/states/drowning', id = 'condition_drowning' }
Icons[PlayerStates.Freezing] = { tooltip = tr('You are freezing'), path = '/images/game/states/freezing', id = 'condition_freezing' }
Icons[PlayerStates.Dazzled] = { tooltip = tr('You are dazzled'), path = '/images/game/states/dazzled', id = 'condition_dazzled' }
Icons[PlayerStates.Cursed] = { tooltip = tr('You are cursed'), path = '/images/game/states/cursed', id = 'condition_cursed' }
Icons[PlayerStates.PartyBuff] = { tooltip = tr('You are strengthened'), path = '/images/game/states/strengthened', id = 'condition_strengthened' }
Icons[PlayerStates.PzBlock] = { tooltip = tr('You may not logout or enter a protection zone'), path = '/images/game/states/protection_zone_block', id = 'condition_protection_zone_block' }
Icons[PlayerStates.Pz] = { tooltip = tr('You are within a protection zone'), path = '/images/game/states/protection_zone', id = 'condition_protection_zone' }
Icons[PlayerStates.Bleeding] = { tooltip = tr('You are bleeding'), path = '/images/game/states/bleeding', id = 'condition_bleeding' }
Icons[PlayerStates.Hungry] = { tooltip = tr('You are hungry'), path = '/images/game/states/hungry', id = 'condition_hungry' }

SkullIcons = {}
SkullIcons[SkullGreen] = { tooltip = tr('You are a member of a party'), path = '/images/game/states/skullgreen', id = 'skullIcon' }
SkullIcons[SkullWhite] = { tooltip = tr('You have attacked an unmarked player'), path = '/images/game/states/skullwhite', id = 'skullIcon' }
SkullIcons[SkullRed] = { tooltip = tr('You have killed too many unmarked players'), path = '/images/game/states/skullred', id = 'skullIcon' }

InventorySlotStyles = {
  [InventorySlotHead] = "HeadSlot",
  [InventorySlotNeck] = "NeckSlot",
  [InventorySlotBack] = "BackSlot",
  [InventorySlotBody] = "BodySlot",
  [InventorySlotRight] = "RightSlot",
  [InventorySlotLeft] = "LeftSlot",
  [InventorySlotLeg] = "LegSlot",
  [InventorySlotFeet] = "FeetSlot",
  [InventorySlotFinger] = "FingerSlot",
  [InventorySlotAmmo] = "AmmoSlot"
}

inventoryWindow = nil
inventoryPanel = nil
inventoryButton = nil
purseButton = nil

combatControlsWindow = nil
fightOffensiveBox = nil
fightBalancedBox = nil
fightDefensiveBox = nil
chaseModeButton = nil
safeFightButton = nil
mountButton = nil
fightModeRadioGroup = nil
chaseModeRadioGroup = nil
chaseModeStandBox = nil
chaseModeChaseBox = nil
buttonPvp = nil
skillsButton = nil
battleButton = nil
vipButton = nil

soulLabel = nil
capLabel = nil
conditionPanel = nil

function init()
  connect(LocalPlayer, {
    onInventoryChange = onInventoryChange,
    onBlessingsChange = onBlessingsChange
  })
  connect(g_game, { onGameStart = refresh })


  inventoryWindow = g_ui.loadUI('inventory', modules.game_interface.getRightPanel())
  inventoryWindow:disableResize()
  inventoryPanel = inventoryWindow:getChildById('contentsPanel')
  if not inventoryWindow.forceOpen then
    inventoryButton = modules.client_topmenu.addRightGameToggleButton('inventoryButton', tr('Inventory') .. ' (Ctrl+I)', '/images/topbuttons/inventory', toggle)
    inventoryButton:setOn(true)
  end
 
  purseButton = inventoryWindow:recursiveGetChildById('purseButton')
  purseButton.onClick = function()
    local purse = g_game.getLocalPlayer():getInventoryItem(InventorySlotPurse)
    if purse then
      g_game.use(purse)
    end
  end
 
  skillsButton = inventoryWindow:recursiveGetChildById('skillsButton')
  battleButton = inventoryWindow:recursiveGetChildById('battleButton')
  vipButton = inventoryWindow:recursiveGetChildById('vipButton')

  -- controls
  fightOffensiveBox = inventoryWindow:recursiveGetChildById('fightOffensiveBox')
  fightBalancedBox = inventoryWindow:recursiveGetChildById('fightBalancedBox')
  fightDefensiveBox = inventoryWindow:recursiveGetChildById('fightDefensiveBox')
 
  chaseModeStandBox = inventoryWindow:recursiveGetChildById('chaseModeBoxStand')
  chaseModeChaseBox = inventoryWindow:recursiveGetChildById('chaseModeBoxChase')

  chaseModeButton = inventoryWindow:recursiveGetChildById('chaseModeBox')
  safeFightButton = inventoryWindow:recursiveGetChildById('safeFightBox')
  buttonPvp = inventoryWindow:recursiveGetChildById('buttonPvp')

  mountButton = inventoryWindow:recursiveGetChildById('mountButton')
  mountButton.onClick = onMountButtonClick

  whiteDoveBox = inventoryWindow:recursiveGetChildById('whiteDoveBox')
  whiteHandBox = inventoryWindow:recursiveGetChildById('whiteHandBox')
  yellowHandBox = inventoryWindow:recursiveGetChildById('yellowHandBox')
  redFistBox = inventoryWindow:recursiveGetChildById('redFistBox')

  fightModeRadioGroup = UIRadioGroup.create()
  fightModeRadioGroup:addWidget(fightOffensiveBox)
  fightModeRadioGroup:addWidget(fightBalancedBox)
  fightModeRadioGroup:addWidget(fightDefensiveBox)

  chaseModeRadioGroup = UIRadioGroup.create()
  chaseModeRadioGroup:addWidget(chaseModeStandBox)
  chaseModeRadioGroup:addWidget(chaseModeChaseBox)

  connect(fightModeRadioGroup, { onSelectionChange = onSetFightMode })
  connect(chaseModeRadioGroup, { onSelectionChange = onSetChaseMode })
  connect(safeFightButton, { onCheckChange = onSetSafeFight })
  if buttonPvp then
    connect(buttonPvp, { onClick = onSetSafeFight2 })
  end
  connect(g_game, {
    onGameStart = online,
    onGameEnd = offline,
    onFightModeChange = update,
    onChaseModeChange = update,
    onSafeFightChange = update,
    onPVPModeChange   = update,
    onWalk = check,
    onAutoWalk = check
  })

  connect(LocalPlayer, { onOutfitChange = onOutfitChange })

  if g_game.isOnline() then
    online()
  end
-- controls end

-- status
  soulLabel = inventoryWindow:recursiveGetChildById('soulLabel')
  capLabel = inventoryWindow:recursiveGetChildById('capLabel')
  conditionPanel = inventoryWindow:recursiveGetChildById('conditionPanel')


  connect(LocalPlayer, { onStatesChange = onStatesChange,
                         onSoulChange = onSoulChange,
                         onFreeCapacityChange = onFreeCapacityChange })
-- status end
 
  connect(LocalPlayer, { onSkullChange = onSkullChange } )

  refresh()
  inventoryWindow:setup()
  inventoryWindow:open()
end

function terminate()
  disconnect(LocalPlayer, {
    onInventoryChange = onInventoryChange,
    onBlessingsChange = onBlessingsChange
  })
  disconnect(g_game, { onGameStart = refresh })

  -- controls
  if g_game.isOnline() then
    offline()
  end

  fightModeRadioGroup:destroy()
 
  disconnect(g_game, {
    onGameStart = online,
    onGameEnd = offline,
    onFightModeChange = update,
    onChaseModeChange = update,
    onSafeFightChange = update,
    onPVPModeChange   = update,
    onWalk = check,
    onAutoWalk = check
  })

  disconnect(LocalPlayer, { onOutfitChange = onOutfitChange })
  -- controls end
  -- status
  disconnect(LocalPlayer, { onStatesChange = onStatesChange,
                         onSoulChange = onSoulChange,
                         onFreeCapacityChange = onFreeCapacityChange })
  -- status end

  disconnect(LocalPlayer, { onSkullChange = onSkullChange } )

  inventoryWindow:destroy()
  if inventoryButton then
    inventoryButton:destroy()
  end
end

function toggleAdventurerStyle(hasBlessing)
  for slot = InventorySlotFirst, InventorySlotLast do
    local itemWidget = inventoryPanel:getChildById('slot' .. slot)
    if itemWidget then
      itemWidget:setOn(hasBlessing)
    end
  end
end

function refresh()
  local player = g_game.getLocalPlayer()
  for i = InventorySlotFirst, InventorySlotPurse do
    if g_game.isOnline() then
      onInventoryChange(player, i, player:getInventoryItem(i))
    else
      onInventoryChange(player, i, nil)
    end
    toggleAdventurerStyle(player and Bit.hasBit(player:getBlessings(), Blessings.Adventurer) or false)
  end
  if player then
    onSoulChange(player, player:getSoul())
    onFreeCapacityChange(player, player:getFreeCapacity())
    onStatesChange(player, player:getStates(), 0)
  end

  purseButton:setVisible(g_game.getFeature(GamePurseSlot))
end

function toggle()
  if not inventoryButton then
    return
  end
  if inventoryButton:isOn() then
    inventoryWindow:close()
    inventoryButton:setOn(false)
  else
    inventoryWindow:open()
    inventoryButton:setOn(true)
  end
end

function onMiniWindowClose()
  if not inventoryButton then
    return
  end
  inventoryButton:setOn(false)
end

-- hooked events
function onInventoryChange(player, slot, item, oldItem)
  if slot > InventorySlotPurse then return end

  if slot == InventorySlotPurse then
    if g_game.getFeature(GamePurseSlot) then
      --purseButton:setEnabled(item and true or false)
    end
    return
  end

  local itemWidget = inventoryPanel:getChildById('slot' .. slot)
  if item then
    itemWidget:setStyle('InventoryItem')
    itemWidget:setItem(item)
  else
    itemWidget:setStyle(InventorySlotStyles[slot])
    itemWidget:setItem(nil)
  end
end

function onBlessingsChange(player, blessings, oldBlessings)
  local hasAdventurerBlessing = Bit.hasBit(blessings, Blessings.Adventurer)
  if hasAdventurerBlessing ~= Bit.hasBit(oldBlessings, Blessings.Adventurer) then
    toggleAdventurerStyle(hasAdventurerBlessing)
  end
end


-- controls
function update()
  local fightMode = g_game.getFightMode()
  if fightMode == FightOffensive then
    fightModeRadioGroup:selectWidget(fightOffensiveBox)
  elseif fightMode == FightBalanced then
    fightModeRadioGroup:selectWidget(fightBalancedBox)
  else
    fightModeRadioGroup:selectWidget(fightDefensiveBox)
  end

  local chaseMode = g_game.getChaseMode()
  if chaseMode == ChaseOpponent then
    chaseModeRadioGroup:selectWidget(chaseModeChaseBox)
  else
    chaseModeRadioGroup:selectWidget(chaseModeStandBox)
  end

  local safeFight = g_game.isSafeFight()
  safeFightButton:setChecked(not safeFight)
  if buttonPvp then
    if safeFight then
      buttonPvp:setOn(false)
    else
      buttonPvp:setOn(true)
    end
  end
 
  if g_game.getFeature(GamePVPMode) then
    local pvpMode = g_game.getPVPMode()
    local pvpWidget = getPVPBoxByMode(pvpMode)
  end
end

function check()
  if modules.client_options.getOption('autoChaseOverride') then
    if g_game.isAttacking() and g_game.getChaseMode() == ChaseOpponent then
      g_game.setChaseMode(DontChase)
    end
  end
end

function online()
  local player = g_game.getLocalPlayer()
  if player then
    local char = g_game.getCharacterName()

    local lastCombatControls = g_settings.getNode('LastCombatControls')

    if not table.empty(lastCombatControls) then
      if lastCombatControls[char] then
        g_game.setFightMode(lastCombatControls[char].fightMode)
        g_game.setChaseMode(lastCombatControls[char].chaseMode)
        g_game.setSafeFight(lastCombatControls[char].safeFight)
        if lastCombatControls[char].pvpMode then
          g_game.setPVPMode(lastCombatControls[char].pvpMode)
        end
      end
    end

    if g_game.getFeature(GamePlayerMounts) then
      mountButton:setVisible(true)
      mountButton:setChecked(player:isMounted())
    else
      mountButton:setVisible(false)
    end
  end

  update()
end

function offline()
  local lastCombatControls = g_settings.getNode('LastCombatControls')
  if not lastCombatControls then
    lastCombatControls = {}
  end

  conditionPanel:destroyChildren()

  local player = g_game.getLocalPlayer()
  if player then
    local char = g_game.getCharacterName()
    lastCombatControls[char] = {
      fightMode = g_game.getFightMode(),
      chaseMode = g_game.getChaseMode(),
      safeFight = g_game.isSafeFight()
    }

    if g_game.getFeature(GamePVPMode) then
      lastCombatControls[char].pvpMode = g_game.getPVPMode()
    end

    -- save last combat control settings
    g_settings.setNode('LastCombatControls', lastCombatControls)
  end
end

function onSetFightMode(self, selectedFightButton)
  if selectedFightButton == nil then return end
  local buttonId = selectedFightButton:getId()
  local fightMode
  if buttonId == 'fightOffensiveBox' then
    fightMode = FightOffensive
  elseif buttonId == 'fightBalancedBox' then
    fightMode = FightBalanced
  else
    fightMode = FightDefensive
  end
  g_game.setFightMode(fightMode)
end

function onSetChaseMode(self, selectedButton)
  if selectedButton == nil then return end
  local buttonId = selectedButton:getId()
  local chaseMode
  if buttonId == 'chaseModeBoxChase' then
    chaseMode = ChaseOpponent
  else
    chaseMode = DontChase
  end
  g_game.setChaseMode(chaseMode)
end

function onSetSafeFight(self, checked)
  g_game.setSafeFight(not checked)
  if buttonPvp then
    if not checked then
      buttonPvp:setOn(false)
    else
      buttonPvp:setOn(true)
    end
  end
end

function onSetSafeFight2(self)
  onSetSafeFight(self, not safeFightButton:isChecked())
end

function onSetPVPMode(self, selectedPVPButton)
  if selectedPVPButton == nil then
    return
  end

  local buttonId = selectedPVPButton:getId()
  local pvpMode = PVPWhiteDove
  if buttonId == 'whiteDoveBox' then
    pvpMode = PVPWhiteDove
  elseif buttonId == 'whiteHandBox' then
    pvpMode = PVPWhiteHand
  elseif buttonId == 'yellowHandBox' then
    pvpMode = PVPYellowHand
  elseif buttonId == 'redFistBox' then
    pvpMode = PVPRedFist
  end

  g_game.setPVPMode(pvpMode)
end

function onMountButtonClick(self, mousePos)
  local player = g_game.getLocalPlayer()
  if player then
    player:toggleMount()
  end
end

function onOutfitChange(localPlayer, outfit, oldOutfit)
  if outfit.mount == oldOutfit.mount then
    return
  end

  mountButton:setChecked(outfit.mount ~= nil and outfit.mount > 0)
end

function getPVPBoxByMode(mode)
  local widget = nil
  if mode == PVPWhiteDove then
    widget = whiteDoveBox
  elseif mode == PVPWhiteHand then
    widget = whiteHandBox
  elseif mode == PVPYellowHand then
    widget = yellowHandBox
  elseif mode == PVPRedFist then
    widget = redFistBox
  end
  return widget
end

-- status
function toggleIcon(bitChanged)
  local icon = conditionPanel:getChildById(Icons[bitChanged].id)
  if icon then
    icon:destroy()
  else
    icon = loadIcon(bitChanged)
    icon:setParent(conditionPanel)
  end
end

function loadIcon(bitChanged)
  local icon = g_ui.createWidget('ConditionWidget', conditionPanel)
  icon:setId(Icons[bitChanged].id)
  icon:setImageSource(Icons[bitChanged].path)
  icon:setTooltip(Icons[bitChanged].tooltip)
  return icon
end

function onSoulChange(localPlayer, soul)
  if not soul then return end
  soulLabel:setText(tr('Soul') .. ':\n' .. soul)
end

function onFreeCapacityChange(player, freeCapacity)
  if not freeCapacity then return end
  if freeCapacity > 99 then
    freeCapacity = math.floor(freeCapacity * 10) / 10
  end
  if freeCapacity > 999 then
    freeCapacity = math.floor(freeCapacity)
  end
  if freeCapacity > 99999 then
    freeCapacity = math.min(9999, math.floor(freeCapacity/1000)) .. "k"
  end
  capLabel:setText(tr('Cap') .. ':\n' .. (freeCapacity*100))
end

function onStatesChange(localPlayer, now, old)
  if now == old then return end
  local bitsChanged = bit32.bxor(now, old)
  for i = 1, 32 do
    local pow = math.pow(2, i-1)
    if pow > bitsChanged then break end
    local bitChanged = bit32.band(bitsChanged, pow)
    if bitChanged ~= 0 then
      toggleIcon(bitChanged)
    end
  end
end
Sorry, I need your questlog.lua, not inventory.lua
 
Sure, here it is:

Lua:
questLogButton = nil
questTrackerButton = nil
window = nil
trackerWindow = nil
settings = {}

local callDelay = 1000 -- each call delay is also increased by random values (0-callDelay/2)
local dispatcher = {}

function init()
  g_ui.importStyle('questlogwindow')

  window = g_ui.createWidget('QuestLogWindow', rootWidget)
  window:hide()
  trackerWindow = g_ui.createWidget('QuestTracker', modules.game_interface.getRightPanel())
  trackerWindow:setup()
  trackerWindow:hide()
 
  if not g_app.isMobile() then
    questLogButton = modules.client_topmenu.addLeftGameButton('questLogButton', tr('Quest Log'), '/images/topbuttons/questlog', function() g_game.requestQuestLog() end, false, 8)
    questTrackerButton = modules.client_topmenu.addLeftGameButton('questTrackerButton', tr('Quest Tracker'), '/images/topbuttons/quest_tracker', toggle, false, 9)
  end
 
  connect(g_game, { onQuestLog = onGameQuestLog,
                    onQuestLine = onGameQuestLine,
                    onGameEnd = offline,
                    onGameStart = online})
  online()
end

function terminate()
  disconnect(g_game, { onQuestLog = onGameQuestLog,
                       onQuestLine = onGameQuestLine,
                       onGameEnd = offline,
                       onGameStart = online})

  offline()
  if questLogButton then
    questLogButton:destroy()
  end
  if questTrackerButton then
    questTrackerButton:destroy()
  end
end

function toggle()
  if trackerWindow:isVisible() then
    trackerWindow:hide()
  else
    trackerWindow:show()
  end
end

function offline()
  if window then
    window:hide()
  end
  if trackerWindow then
    trackerWindow:hide()
  end
  save()
  -- reset tracker
  trackerWindow.contentsPanel.list:destroyChildren()
  trackerWindow.contentsPanel.list:setHeight(0)
end

function online()
  local playerName = g_game.getCharacterName()
  if not playerName then return end -- just to be sure
  load()
  refreshQuests()
  refreshTrackerWidgets()

  local playerName = g_game.getCharacterName()
  settings[playerName] = settings[playerName] or {}
  local settings = settings[playerName]
  local missionList = window.missionlog.missionList
  local track = window.missionlog.track
  local missionDescription = window.missionlog.missionDescription

  connect(missionList, {
    onChildFocusChange = function(self, focusedChild)
      if focusedChild == nil then return end
        missionDescription:setText(focusedChild.description)
        if focusedChild:isVisible() then
          track:setEnabled(true)
        end
        track:setChecked(settings[focusedChild.trackData])
      end
    }
  )
end

function show(questlog)
  if questlog then
    window:raise()
    window:show()
    window:focus()
    window.missionlog.currentQuest = nil -- reset current quest
    window.questlog:setVisible(true)
    window.missionlog:setVisible(false)
    window.closeButton:setText('Close')
    window.showButton:setVisible(true)
    window.missionlog.track:setEnabled(false)
    window.missionlog.track:setChecked(false)
    window.missionlog.missionDescription:setText('')
  else
    window.questlog:setVisible(false)
    window.missionlog:setVisible(true)
    window.closeButton:setText('Back')
    window.showButton:setVisible(false)
  end
end

function back()
  if window:isVisible() then
    if window.questlog:isVisible() then
      window:hide()
    else
      show(true)
    end
  end
end

function showQuestLine()
  local questList = window.questlog.questList
  local child = questList:getFocusedChild()

  g_game.requestQuestLine(child.questId)
  window.missionlog.questName:setText(child.questName)
  window.missionlog.currentQuest = child.questId
end

function onGameQuestLog(quests)
  show(true)

  local questList = window.questlog.questList

  questList:destroyChildren()
  for i,questEntry in pairs(quests) do
    local id, name, completed = unpack(questEntry)

    local questLabel = g_ui.createWidget('QuestLabel', questList)
    questLabel:setChecked(i % 2 == 0)
    questLabel.questId = id -- for quest tracker
    questLabel.questName = name
    name = completed and name.." (completed)" or name
    questLabel:setText(name)
    questLabel.onDoubleClick = function()
      window.missionlog.currentQuest = id
      g_game.requestQuestLine(id)
      window.missionlog.questName:setText(questLabel.questName)
    end
  end
  questList:focusChild(questList:getFirstChild())
end

function onGameQuestLine(questId, questMissions)
  show(false)
  local missionList = window.missionlog.missionList

  if questId == window.missionlog.currentQuest then
    missionList:destroyChildren()
  end
  for i,questMission in pairs(questMissions) do
    local name, description = unpack(questMission)

    --questlog
    local missionLabel = g_ui.createWidget('QuestLabel', missionList)
    local widgetId = questId..'.'..i
    missionLabel:setChecked(i % 2 == 0)
    missionLabel:setId(widgetId)
    missionLabel.questId = questId
    missionLabel.trackData = widgetId
    missionLabel:setText(name)
    missionLabel.description = description
    missionLabel:setVisible(questId == window.missionlog.currentQuest)

    --tracker
    local trackerLabel = trackerWindow.contentsPanel.list[widgetId]
    trackerLabel = trackerLabel or g_ui.createWidget('QuestTrackerLabel', trackerWindow.contentsPanel.list)
    trackerLabel:setId(widgetId)
    trackerLabel.description:setText(description)
    local data = settings[g_game.getCharacterName()]
    trackerLabel:setVisible(description:len() > 0 and data[widgetId])
  end
  local focusTarget = missionList:getFirstChild()
  if focusTarget and focusTarget:isVisible() then
    missionList:focusChild(focusTarget)
  end
end

function onTrackOptionChange(checkbox)
  local newStatus = not checkbox:isChecked()
  checkbox:setChecked(newStatus)

  local missionList = window.missionlog.missionList
  local focused = missionList:getFocusedChild()
  if not focused then return end
  local settings = settings[g_game.getCharacterName()]
  local trackdata = focused.trackData

  -- settings
  settings[trackdata] = newStatus

  local trackerWidget = trackerWindow.contentsPanel.list[trackdata]
  if trackerWidget then
    trackerWidget:setVisible(newStatus)
  end

  refreshQuests()
  save()
end

function refreshQuests()
  if not g_game.isOnline() then return end
  local data = settings[g_game.getCharacterName()]
  data = data or {}

  -- do not execute when questlost is in use
  if not window:isVisible() then
    for questData, track in pairs(data) do
      local id = string.split(questData, ".")[1]

      if not track then
        dispatcher[questData] = nil -- remove from dispatcher if no longer tracked
      else
        dispatcher[questData] = dispatcher[questData] or g_clock.millis()
      end

      if dispatcher[questData] and g_clock.millis() > dispatcher[questData] + callDelay + math.random(callDelay/2) then
        dispatcher[questData] = g_clock.millis()
        scheduleEvent(function()
          g_game.requestQuestLine(id) -- request update
        end, math.random(callDelay/2) )
      end
    end
  end

  scheduleEvent(refreshQuests, callDelay)
end

function refreshTrackerWidgets()
  if not g_game.isOnline() then return end
  local data = settings[g_game.getCharacterName()]
  data = data or {}

  for questData, enabled in pairs(data) do
    local data = string.split(questData, ".")
    local id = tonumber(data[1])

    local widget = trackerWindow.contentsPanel.list[questData]
    if not widget then
      g_game.requestQuestLine(id)
    end
  end
end

-- json handlers
function load()
  local file = "/settings/questlog.json"
  if g_resources.fileExists(file) then
    local status, result = pcall(function()
        return json.decode(g_resources.readFileContents(file))
    end)
    if not status then
        return g_logger.error(
                   "Error while reading profiles file. To fix this problem you can delete storage.json. Details: " ..
                       result)
    end
    settings = result
  end
end

function save()
  local file = "/settings/questlog.json"
  local status, result = pcall(function() return json.encode(settings, 2) end)
  if not status then
      return g_logger.error(
                 "Error while saving profile settings. Data won't be saved. Details: " ..
                     result)
  end
  if result:len() > 100 * 1024 * 1024 then
      return g_logger.error(
                 "Something went wrong, file is above 100MB, won't be saved")
  end
  g_resources.writeFileContents(file, result)
end

function showQuestlog()
    questLogWindow:show()
    g_game.requestQuestLog()
end
 
Sure, here it is:

Lua:
questLogButton = nil
questTrackerButton = nil
window = nil
trackerWindow = nil
settings = {}

local callDelay = 1000 -- each call delay is also increased by random values (0-callDelay/2)
local dispatcher = {}

function init()
  g_ui.importStyle('questlogwindow')

  window = g_ui.createWidget('QuestLogWindow', rootWidget)
  window:hide()
  trackerWindow = g_ui.createWidget('QuestTracker', modules.game_interface.getRightPanel())
  trackerWindow:setup()
  trackerWindow:hide()
 
  if not g_app.isMobile() then
    questLogButton = modules.client_topmenu.addLeftGameButton('questLogButton', tr('Quest Log'), '/images/topbuttons/questlog', function() g_game.requestQuestLog() end, false, 8)
    questTrackerButton = modules.client_topmenu.addLeftGameButton('questTrackerButton', tr('Quest Tracker'), '/images/topbuttons/quest_tracker', toggle, false, 9)
  end
 
  connect(g_game, { onQuestLog = onGameQuestLog,
                    onQuestLine = onGameQuestLine,
                    onGameEnd = offline,
                    onGameStart = online})
  online()
end

function terminate()
  disconnect(g_game, { onQuestLog = onGameQuestLog,
                       onQuestLine = onGameQuestLine,
                       onGameEnd = offline,
                       onGameStart = online})

  offline()
  if questLogButton then
    questLogButton:destroy()
  end
  if questTrackerButton then
    questTrackerButton:destroy()
  end
end

function toggle()
  if trackerWindow:isVisible() then
    trackerWindow:hide()
  else
    trackerWindow:show()
  end
end

function offline()
  if window then
    window:hide()
  end
  if trackerWindow then
    trackerWindow:hide()
  end
  save()
  -- reset tracker
  trackerWindow.contentsPanel.list:destroyChildren()
  trackerWindow.contentsPanel.list:setHeight(0)
end

function online()
  local playerName = g_game.getCharacterName()
  if not playerName then return end -- just to be sure
  load()
  refreshQuests()
  refreshTrackerWidgets()

  local playerName = g_game.getCharacterName()
  settings[playerName] = settings[playerName] or {}
  local settings = settings[playerName]
  local missionList = window.missionlog.missionList
  local track = window.missionlog.track
  local missionDescription = window.missionlog.missionDescription

  connect(missionList, {
    onChildFocusChange = function(self, focusedChild)
      if focusedChild == nil then return end
        missionDescription:setText(focusedChild.description)
        if focusedChild:isVisible() then
          track:setEnabled(true)
        end
        track:setChecked(settings[focusedChild.trackData])
      end
    }
  )
end

function show(questlog)
  if questlog then
    window:raise()
    window:show()
    window:focus()
    window.missionlog.currentQuest = nil -- reset current quest
    window.questlog:setVisible(true)
    window.missionlog:setVisible(false)
    window.closeButton:setText('Close')
    window.showButton:setVisible(true)
    window.missionlog.track:setEnabled(false)
    window.missionlog.track:setChecked(false)
    window.missionlog.missionDescription:setText('')
  else
    window.questlog:setVisible(false)
    window.missionlog:setVisible(true)
    window.closeButton:setText('Back')
    window.showButton:setVisible(false)
  end
end

function back()
  if window:isVisible() then
    if window.questlog:isVisible() then
      window:hide()
    else
      show(true)
    end
  end
end

function showQuestLine()
  local questList = window.questlog.questList
  local child = questList:getFocusedChild()

  g_game.requestQuestLine(child.questId)
  window.missionlog.questName:setText(child.questName)
  window.missionlog.currentQuest = child.questId
end

function onGameQuestLog(quests)
  show(true)

  local questList = window.questlog.questList

  questList:destroyChildren()
  for i,questEntry in pairs(quests) do
    local id, name, completed = unpack(questEntry)

    local questLabel = g_ui.createWidget('QuestLabel', questList)
    questLabel:setChecked(i % 2 == 0)
    questLabel.questId = id -- for quest tracker
    questLabel.questName = name
    name = completed and name.." (completed)" or name
    questLabel:setText(name)
    questLabel.onDoubleClick = function()
      window.missionlog.currentQuest = id
      g_game.requestQuestLine(id)
      window.missionlog.questName:setText(questLabel.questName)
    end
  end
  questList:focusChild(questList:getFirstChild())
end

function onGameQuestLine(questId, questMissions)
  show(false)
  local missionList = window.missionlog.missionList

  if questId == window.missionlog.currentQuest then
    missionList:destroyChildren()
  end
  for i,questMission in pairs(questMissions) do
    local name, description = unpack(questMission)

    --questlog
    local missionLabel = g_ui.createWidget('QuestLabel', missionList)
    local widgetId = questId..'.'..i
    missionLabel:setChecked(i % 2 == 0)
    missionLabel:setId(widgetId)
    missionLabel.questId = questId
    missionLabel.trackData = widgetId
    missionLabel:setText(name)
    missionLabel.description = description
    missionLabel:setVisible(questId == window.missionlog.currentQuest)

    --tracker
    local trackerLabel = trackerWindow.contentsPanel.list[widgetId]
    trackerLabel = trackerLabel or g_ui.createWidget('QuestTrackerLabel', trackerWindow.contentsPanel.list)
    trackerLabel:setId(widgetId)
    trackerLabel.description:setText(description)
    local data = settings[g_game.getCharacterName()]
    trackerLabel:setVisible(description:len() > 0 and data[widgetId])
  end
  local focusTarget = missionList:getFirstChild()
  if focusTarget and focusTarget:isVisible() then
    missionList:focusChild(focusTarget)
  end
end

function onTrackOptionChange(checkbox)
  local newStatus = not checkbox:isChecked()
  checkbox:setChecked(newStatus)

  local missionList = window.missionlog.missionList
  local focused = missionList:getFocusedChild()
  if not focused then return end
  local settings = settings[g_game.getCharacterName()]
  local trackdata = focused.trackData

  -- settings
  settings[trackdata] = newStatus

  local trackerWidget = trackerWindow.contentsPanel.list[trackdata]
  if trackerWidget then
    trackerWidget:setVisible(newStatus)
  end

  refreshQuests()
  save()
end

function refreshQuests()
  if not g_game.isOnline() then return end
  local data = settings[g_game.getCharacterName()]
  data = data or {}

  -- do not execute when questlost is in use
  if not window:isVisible() then
    for questData, track in pairs(data) do
      local id = string.split(questData, ".")[1]

      if not track then
        dispatcher[questData] = nil -- remove from dispatcher if no longer tracked
      else
        dispatcher[questData] = dispatcher[questData] or g_clock.millis()
      end

      if dispatcher[questData] and g_clock.millis() > dispatcher[questData] + callDelay + math.random(callDelay/2) then
        dispatcher[questData] = g_clock.millis()
        scheduleEvent(function()
          g_game.requestQuestLine(id) -- request update
        end, math.random(callDelay/2) )
      end
    end
  end

  scheduleEvent(refreshQuests, callDelay)
end

function refreshTrackerWidgets()
  if not g_game.isOnline() then return end
  local data = settings[g_game.getCharacterName()]
  data = data or {}

  for questData, enabled in pairs(data) do
    local data = string.split(questData, ".")
    local id = tonumber(data[1])

    local widget = trackerWindow.contentsPanel.list[questData]
    if not widget then
      g_game.requestQuestLine(id)
    end
  end
end

-- json handlers
function load()
  local file = "/settings/questlog.json"
  if g_resources.fileExists(file) then
    local status, result = pcall(function()
        return json.decode(g_resources.readFileContents(file))
    end)
    if not status then
        return g_logger.error(
                   "Error while reading profiles file. To fix this problem you can delete storage.json. Details: " ..
                       result)
    end
    settings = result
  end
end

function save()
  local file = "/settings/questlog.json"
  local status, result = pcall(function() return json.encode(settings, 2) end)
  if not status then
      return g_logger.error(
                 "Error while saving profile settings. Data won't be saved. Details: " ..
                     result)
  end
  if result:len() > 100 * 1024 * 1024 then
      return g_logger.error(
                 "Something went wrong, file is above 100MB, won't be saved")
  end
  g_resources.writeFileContents(file, result)
end

function showQuestlog()
    questLogWindow:show()
    g_game.requestQuestLog()
end

Try it:

Lua:
function showQuestlog()
    window:show()
    g_game.requestQuestLog()
end

Its 'window' and not 'questLogwindow'
 
sandboxed: true, yes
this is my inventory.otui:

Lua:
InventoryItem < Item
  $on:
    image-source: /images/ui/item-blessed

HeadSlot < InventoryItem
  id: slot1
  image-source: /images/game/slots/head
  &position: {x=65535, y=1, z=0}
  $on:
    image-source: /images/game/slots/head-blessed

BodySlot < InventoryItem
  id: slot4
  image-source: /images/game/slots/body
  &position: {x=65535, y=4, z=0}
  $on:
    image-source: /images/game/slots/body-blessed

LegSlot < InventoryItem
  id: slot7
  image-source: /images/game/slots/legs
  &position: {x=65535, y=7, z=0}
  $on:
    image-source: /images/game/slots/legs-blessed

FeetSlot < InventoryItem
  id: slot8
  image-source: /images/game/slots/feet
  &position: {x=65535, y=8, z=0}
  $on:
    image-source: /images/game/slots/feet-blessed

NeckSlot < InventoryItem
  id: slot2
  image-source: /images/game/slots/neck
  &position: {x=65535, y=2, z=0}
  $on:
    image-source: /images/game/slots/neck-blessed

LeftSlot < InventoryItem
  id: slot6
  image-source: /images/game/slots/left-hand
  &position: {x=65535, y=6, z=0}
  $on:
    image-source: /images/game/slots/left-hand-blessed

FingerSlot < InventoryItem
  id: slot9
  image-source: /images/game/slots/finger
  &position: {x=65535, y=9, z=0}
  $on:
    image-source: /images/game/slots/finger-blessed

BackSlot < InventoryItem
  id: slot3
  image-source: /images/game/slots/back
  &position: {x=65535, y=3, z=0}
  $on:
    image-source: /images/game/slots/back-blessed

RightSlot < InventoryItem
  id: slot5
  image-source: /images/game/slots/right-hand
  &position: {x=65535, y=5, z=0}
  $on:
    image-source: /images/game/slots/right-hand-blessed

AmmoSlot < InventoryItem
  id: slot10
  image-source: /images/game/slots/ammo
  &position: {x=65535, y=10, z=0}
  $on:
    image-source: /images/game/slots/ammo-blessed

PurseButton < UIButton
  id: purseButton
  size: 34 12
  !tooltip: tr('Open purse')
  icon-source: /images/game/slots/purse
  icon-clip: 0 0 34 12
 
  $on:
    icon-clip: 0 12 34 12

  $pressed:
    icon-clip: 0 12 34 12

CombatBox < UICheckBox
  size: 20 20
  image-clip: 0 0 20 20

  $checked:
    image-clip: 0 20 20 20

InventoryButton < Button
  height: 20
  margin-top: 2
  text-align: center

SoulCapLabel < GameLabel
  text-align: center
  font: cipsoftFont
  margin-top: 4
  text-offset: 0 3
  width: 36
  height: 20
  icon-source: /images/game/slots/soulcap
   
FightOffensiveBox < CombatBox
  image-source: /images/game/combatmodes/fightoffensive
FightBalancedBox < CombatBox
  image-source: /images/game/combatmodes/fightbalanced
FightDefensiveBox < CombatBox
  image-source: /images/game/combatmodes/fightdefensive
SafeFightBox < CombatBox
  image-source: /images/game/combatmodes/safefight

MountButton < CombatBox
  image-source: /images/game/combatmodes/mount

NonClosableMiniWindow
  height: 170
  id: inventoryWindow
  @onClose: modules.game_inventory.onMiniWindowClose()
  &save: true
  &autoOpen: 3

  NonClosableMiniWindowContents
    NeckSlot
      anchors.top: parent.top
      anchors.left: parent.left
      margin-top: 18
      margin-right: 5
      margin-left: 5

    LeftSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      anchors.left: prev.left
      margin-top: 4

    FingerSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      anchors.left: prev.left
      margin-top: 4
 
    HeadSlot
      anchors.top: parent.top
      anchors.left: slot2.right
      margin-top: 4
      margin-left: 4

    BodySlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    LegSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    FeetSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4
 
    BackSlot
      anchors.top: slot2.top
      anchors.left: slot1.right
      margin-left: 4

    RightSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    AmmoSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    SoulCapLabel
      id: capLabel
      anchors.top: slot10.bottom
      anchors.horizontalCenter: slot10.horizontalCenter
   
    SoulCapLabel
      id: soulLabel
      anchors.top: slot9.bottom
      anchors.horizontalCenter: slot9.horizontalCenter

    PurseButton
      anchors.left: slot3.left
      anchors.bottom: slot3.top    
      margin-bottom: 3

    Panel
      id: conditionPanel
      image-source: /images/ui/conditionPanel
      layout:
        type: horizontalBox
      height: 13
      padding: 2
      anchors.top: slot8.bottom
      anchors.left: slot6.left
      anchors.right: slot5.right
      margin-top: 3

    FightOffensiveBox
      id: fightOffensiveBox
      anchors.left: slot3.right
      anchors.top: slot3.top
      margin-left: 8

    FightBalancedBox
      id: fightBalancedBox
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1

    FightDefensiveBox
      id: fightDefensiveBox
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1
 
    CombatBox
      id: chaseModeBoxStand
      image-source: /images/game/combatmodes/standmode
      anchors.left: fightOffensiveBox.right
      anchors.top: fightOffensiveBox.top
      margin-left: 4
 
    CombatBox
      id: chaseModeBoxChase
      image-source: /images/game/combatmodes/chasemode
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1
 
    SafeFightBox
      id: safeFightBox
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1
   
    MountButton
      id: mountButton
      margin-top: 44
      anchors.left: prev.right
      anchors.top: parent.top

    InventoryButton
      !text: tr('Quests')
      anchors.top: fightDefensiveBox.bottom
      anchors.left: fightDefensiveBox.left
      anchors.right: safeFightBox.right
      margin-top: 3
      @onClick: modules.game_questlog.showQuestlog()

    InventoryButton
      !text: tr('Options')
      anchors.top: prev.bottom
      anchors.left: prev.left
      anchors.right: prev.right
      margin-top: 5
      @onClick: modules.client_options.toggle()
 
    InventoryButton
      id: help
      !text: tr('Hotkeys')
      anchors.top: prev.bottom
      anchors.left: prev.left
      anchors.right: prev.right
      margin-top: 3
      @onClick: modules.game_hotkeys.toggle()
If you could add another button after hotkeys would be awesome (I always try but it doesn't let me open the client anymore) otui files seems to be really hard to edit
 
Try this:

Lua:
function showQuestlog()
    g_game.requestQuestLog()
end

To create another button:

HTML:
InventoryItem < Item
  $on:
    image-source: /images/ui/item-blessed

HeadSlot < InventoryItem
  id: slot1
  image-source: /images/game/slots/head
  &position: {x=65535, y=1, z=0}
  $on:
    image-source: /images/game/slots/head-blessed

BodySlot < InventoryItem
  id: slot4
  image-source: /images/game/slots/body
  &position: {x=65535, y=4, z=0}
  $on:
    image-source: /images/game/slots/body-blessed

LegSlot < InventoryItem
  id: slot7
  image-source: /images/game/slots/legs
  &position: {x=65535, y=7, z=0}
  $on:
    image-source: /images/game/slots/legs-blessed

FeetSlot < InventoryItem
  id: slot8
  image-source: /images/game/slots/feet
  &position: {x=65535, y=8, z=0}
  $on:
    image-source: /images/game/slots/feet-blessed

NeckSlot < InventoryItem
  id: slot2
  image-source: /images/game/slots/neck
  &position: {x=65535, y=2, z=0}
  $on:
    image-source: /images/game/slots/neck-blessed

LeftSlot < InventoryItem
  id: slot6
  image-source: /images/game/slots/left-hand
  &position: {x=65535, y=6, z=0}
  $on:
    image-source: /images/game/slots/left-hand-blessed

FingerSlot < InventoryItem
  id: slot9
  image-source: /images/game/slots/finger
  &position: {x=65535, y=9, z=0}
  $on:
    image-source: /images/game/slots/finger-blessed

BackSlot < InventoryItem
  id: slot3
  image-source: /images/game/slots/back
  &position: {x=65535, y=3, z=0}
  $on:
    image-source: /images/game/slots/back-blessed

RightSlot < InventoryItem
  id: slot5
  image-source: /images/game/slots/right-hand
  &position: {x=65535, y=5, z=0}
  $on:
    image-source: /images/game/slots/right-hand-blessed

AmmoSlot < InventoryItem
  id: slot10
  image-source: /images/game/slots/ammo
  &position: {x=65535, y=10, z=0}
  $on:
    image-source: /images/game/slots/ammo-blessed

PurseButton < UIButton
  id: purseButton
  size: 34 12
  !tooltip: tr('Open purse')
  icon-source: /images/game/slots/purse
  icon-clip: 0 0 34 12
 
  $on:
    icon-clip: 0 12 34 12

  $pressed:
    icon-clip: 0 12 34 12

CombatBox < UICheckBox
  size: 20 20
  image-clip: 0 0 20 20

  $checked:
    image-clip: 0 20 20 20

InventoryButton < Button
  height: 20
  margin-top: 2
  text-align: center

SoulCapLabel < GameLabel
  text-align: center
  font: cipsoftFont
  margin-top: 4
  text-offset: 0 3
  width: 36
  height: 20
  icon-source: /images/game/slots/soulcap
  
FightOffensiveBox < CombatBox
  image-source: /images/game/combatmodes/fightoffensive
FightBalancedBox < CombatBox
  image-source: /images/game/combatmodes/fightbalanced
FightDefensiveBox < CombatBox
  image-source: /images/game/combatmodes/fightdefensive
SafeFightBox < CombatBox
  image-source: /images/game/combatmodes/safefight

MountButton < CombatBox
  image-source: /images/game/combatmodes/mount

NonClosableMiniWindow
  height: 170
  id: inventoryWindow
  @onClose: modules.game_inventory.onMiniWindowClose()
  &save: true
  &autoOpen: 3

  NonClosableMiniWindowContents
    NeckSlot
      anchors.top: parent.top
      anchors.left: parent.left
      margin-top: 18
      margin-right: 5
      margin-left: 5

    LeftSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      anchors.left: prev.left
      margin-top: 4

    FingerSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      anchors.left: prev.left
      margin-top: 4
 
    HeadSlot
      anchors.top: parent.top
      anchors.left: slot2.right
      margin-top: 4
      margin-left: 4

    BodySlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    LegSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    FeetSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4
 
    BackSlot
      anchors.top: slot2.top
      anchors.left: slot1.right
      margin-left: 4

    RightSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    AmmoSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    SoulCapLabel
      id: capLabel
      anchors.top: slot10.bottom
      anchors.horizontalCenter: slot10.horizontalCenter
  
    SoulCapLabel
      id: soulLabel
      anchors.top: slot9.bottom
      anchors.horizontalCenter: slot9.horizontalCenter

    PurseButton
      anchors.left: slot3.left
      anchors.bottom: slot3.top   
      margin-bottom: 3

    Panel
      id: conditionPanel
      image-source: /images/ui/conditionPanel
      layout:
        type: horizontalBox
      height: 13
      padding: 2
      anchors.top: slot8.bottom
      anchors.left: slot6.left
      anchors.right: slot5.right
      margin-top: 3

    FightOffensiveBox
      id: fightOffensiveBox
      anchors.left: slot3.right
      anchors.top: slot3.top
      margin-left: 8

    FightBalancedBox
      id: fightBalancedBox
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1

    FightDefensiveBox
      id: fightDefensiveBox
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1
 
    CombatBox
      id: chaseModeBoxStand
      image-source: /images/game/combatmodes/standmode
      anchors.left: fightOffensiveBox.right
      anchors.top: fightOffensiveBox.top
      margin-left: 4
 
    CombatBox
      id: chaseModeBoxChase
      image-source: /images/game/combatmodes/chasemode
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1
 
    SafeFightBox
      id: safeFightBox
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1
  
    MountButton
      id: mountButton
      margin-top: 44
      anchors.left: prev.right
      anchors.top: parent.top

    InventoryButton
      !text: tr('Quests')
      anchors.top: fightDefensiveBox.bottom
      anchors.left: fightDefensiveBox.left
      anchors.right: safeFightBox.right
      margin-top: 3
      @onClick: modules.game_questlog.showQuestlog()

    InventoryButton
      !text: tr('Options')
      anchors.top: prev.bottom
      anchors.left: prev.left
      anchors.right: prev.right
      margin-top: 5
      @onClick: modules.client_options.toggle()
 
    InventoryButton
      id: help
      !text: tr('Hotkeys')
      anchors.top: prev.bottom
      anchors.left: prev.left
      anchors.right: prev.right
      margin-top: 3
      @onClick: modules.game_hotkeys.toggle()
 
    InventoryButton
      id: anotherButton
      !text: tr('Another Button')
      anchors.top: prev.bottom
      anchors.left: prev.left
      anchors.right: prev.right
      margin-top: 3
      @onClick: modules.game_hotkeys.showQuestlog()
 
Last edited:
Try this:

Lua:
function showQuestlog()
    g_game.requestQuestLog()
end

To create another button:

HTML:
InventoryItem < Item
  $on:
    image-source: /images/ui/item-blessed

HeadSlot < InventoryItem
  id: slot1
  image-source: /images/game/slots/head
  &position: {x=65535, y=1, z=0}
  $on:
    image-source: /images/game/slots/head-blessed

BodySlot < InventoryItem
  id: slot4
  image-source: /images/game/slots/body
  &position: {x=65535, y=4, z=0}
  $on:
    image-source: /images/game/slots/body-blessed

LegSlot < InventoryItem
  id: slot7
  image-source: /images/game/slots/legs
  &position: {x=65535, y=7, z=0}
  $on:
    image-source: /images/game/slots/legs-blessed

FeetSlot < InventoryItem
  id: slot8
  image-source: /images/game/slots/feet
  &position: {x=65535, y=8, z=0}
  $on:
    image-source: /images/game/slots/feet-blessed

NeckSlot < InventoryItem
  id: slot2
  image-source: /images/game/slots/neck
  &position: {x=65535, y=2, z=0}
  $on:
    image-source: /images/game/slots/neck-blessed

LeftSlot < InventoryItem
  id: slot6
  image-source: /images/game/slots/left-hand
  &position: {x=65535, y=6, z=0}
  $on:
    image-source: /images/game/slots/left-hand-blessed

FingerSlot < InventoryItem
  id: slot9
  image-source: /images/game/slots/finger
  &position: {x=65535, y=9, z=0}
  $on:
    image-source: /images/game/slots/finger-blessed

BackSlot < InventoryItem
  id: slot3
  image-source: /images/game/slots/back
  &position: {x=65535, y=3, z=0}
  $on:
    image-source: /images/game/slots/back-blessed

RightSlot < InventoryItem
  id: slot5
  image-source: /images/game/slots/right-hand
  &position: {x=65535, y=5, z=0}
  $on:
    image-source: /images/game/slots/right-hand-blessed

AmmoSlot < InventoryItem
  id: slot10
  image-source: /images/game/slots/ammo
  &position: {x=65535, y=10, z=0}
  $on:
    image-source: /images/game/slots/ammo-blessed

PurseButton < UIButton
  id: purseButton
  size: 34 12
  !tooltip: tr('Open purse')
  icon-source: /images/game/slots/purse
  icon-clip: 0 0 34 12
 
  $on:
    icon-clip: 0 12 34 12

  $pressed:
    icon-clip: 0 12 34 12

CombatBox < UICheckBox
  size: 20 20
  image-clip: 0 0 20 20

  $checked:
    image-clip: 0 20 20 20

InventoryButton < Button
  height: 20
  margin-top: 2
  text-align: center

SoulCapLabel < GameLabel
  text-align: center
  font: cipsoftFont
  margin-top: 4
  text-offset: 0 3
  width: 36
  height: 20
  icon-source: /images/game/slots/soulcap
 
FightOffensiveBox < CombatBox
  image-source: /images/game/combatmodes/fightoffensive
FightBalancedBox < CombatBox
  image-source: /images/game/combatmodes/fightbalanced
FightDefensiveBox < CombatBox
  image-source: /images/game/combatmodes/fightdefensive
SafeFightBox < CombatBox
  image-source: /images/game/combatmodes/safefight

MountButton < CombatBox
  image-source: /images/game/combatmodes/mount

NonClosableMiniWindow
  height: 170
  id: inventoryWindow
  @onClose: modules.game_inventory.onMiniWindowClose()
  &save: true
  &autoOpen: 3

  NonClosableMiniWindowContents
    NeckSlot
      anchors.top: parent.top
      anchors.left: parent.left
      margin-top: 18
      margin-right: 5
      margin-left: 5

    LeftSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      anchors.left: prev.left
      margin-top: 4

    FingerSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      anchors.left: prev.left
      margin-top: 4
 
    HeadSlot
      anchors.top: parent.top
      anchors.left: slot2.right
      margin-top: 4
      margin-left: 4

    BodySlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    LegSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    FeetSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4
 
    BackSlot
      anchors.top: slot2.top
      anchors.left: slot1.right
      margin-left: 4

    RightSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    AmmoSlot
      anchors.top: prev.bottom
      anchors.horizontalCenter: prev.horizontalCenter
      margin-top: 4

    SoulCapLabel
      id: capLabel
      anchors.top: slot10.bottom
      anchors.horizontalCenter: slot10.horizontalCenter
 
    SoulCapLabel
      id: soulLabel
      anchors.top: slot9.bottom
      anchors.horizontalCenter: slot9.horizontalCenter

    PurseButton
      anchors.left: slot3.left
      anchors.bottom: slot3.top 
      margin-bottom: 3

    Panel
      id: conditionPanel
      image-source: /images/ui/conditionPanel
      layout:
        type: horizontalBox
      height: 13
      padding: 2
      anchors.top: slot8.bottom
      anchors.left: slot6.left
      anchors.right: slot5.right
      margin-top: 3

    FightOffensiveBox
      id: fightOffensiveBox
      anchors.left: slot3.right
      anchors.top: slot3.top
      margin-left: 8

    FightBalancedBox
      id: fightBalancedBox
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1

    FightDefensiveBox
      id: fightDefensiveBox
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1
 
    CombatBox
      id: chaseModeBoxStand
      image-source: /images/game/combatmodes/standmode
      anchors.left: fightOffensiveBox.right
      anchors.top: fightOffensiveBox.top
      margin-left: 4
 
    CombatBox
      id: chaseModeBoxChase
      image-source: /images/game/combatmodes/chasemode
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1
 
    SafeFightBox
      id: safeFightBox
      anchors.left: prev.left
      anchors.top: prev.bottom
      margin-top: 1
 
    MountButton
      id: mountButton
      margin-top: 44
      anchors.left: prev.right
      anchors.top: parent.top

    InventoryButton
      !text: tr('Quests')
      anchors.top: fightDefensiveBox.bottom
      anchors.left: fightDefensiveBox.left
      anchors.right: safeFightBox.right
      margin-top: 3
      @onClick: modules.game_questlog.showQuestlog()

    InventoryButton
      !text: tr('Options')
      anchors.top: prev.bottom
      anchors.left: prev.left
      anchors.right: prev.right
      margin-top: 5
      @onClick: modules.client_options.toggle()
 
    InventoryButton
      id: help
      !text: tr('Hotkeys')
      anchors.top: prev.bottom
      anchors.left: prev.left
      anchors.right: prev.right
      margin-top: 3
      @onClick: modules.game_hotkeys.toggle()
 
    InventoryButton
      id: anotherButton
      !text: tr('Another Button')
      anchors.top: prev.bottom
      anchors.left: prev.left
      anchors.right: prev.right
      margin-top: 3
      @onClick: modules.game_hotkeys.showQuestlog()
Still nill error =(
 
Back
Top