• 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!

OTclientV8 ItemTooltip + rarity frames + custom color on item name

I manged to do everything with no errors using tfs 1.5 nekiro downgrade but but now Im getting
LUA:
ERROR: Unable to send extended opcode 201, extended opcodes are not enabled on this server.
you need to enable data/module/game_feature/feature.lua and g_game.enableFeature(GameExtendedOpcode). Check if there are still any errors. You can also disable it in protocolgame.cpp by setting features[GameExtendedOpcode] = false; – just change it from true to false and test it. It should work.
 
you need to enable data/module/game_feature/feature.lua and g_game.enableFeature(GameExtendedOpcode). Check if there are still any errors. You can also disable it in protocolgame.cpp by setting features[GameExtendedOpcode] = false; – just change it from true to false and test it. It should work.
Yes It was true :D
 
I added the commit from the link below, everything works on TFS 1.5 Nekiro ;)
 
Last edited:
This commit is only for TFS 1.4.2 (1098). For those with good knowledge, it's fine to apply it to TFS 1.5 NeKiRo. For those who don't, I did this a long time ago for TFS 1.5 in another commit. Here's the tutorial to apply and take advantage of it.

Just ignore the part about void ProtocolGame::sendFeatures() and others. I forgot to upload it earlier and later uploaded the tooltips as well.

 
For those using TFS 1.5 Nekiro or any downgrade version, here is the most updated and correct one without mistakes. This is the best option.

 
has anyone done it for TFS 1.2? my server has come with a lot of partial things done. I just want to put the color frame. the rarity system is working (is all through lua) but the code below in the client "modules/game_containers/containers.lua" does not work. The getTooltip returns nil, the getName() returns nil - it does not trigger an error, but the log shows nil (I've used print() to debug it - the item id with getItemId() finds the item correctly but the other methods don't work)

LUA:
local function setFrames()
  for _, container in pairs(g_game.getContainers()) do
      local window = container.itemsPanel
      for i, child in pairs(window:getChildren()) do
          if child:getItemId() ~= 0 then
            local name = child:getItem():getTooltip()
            
            child:setImageSource("/images/ui/item")
            if (name) then
              if (string.find(name, "rare")) then
                child:setImageSource('/images/ui/rarity_gold')
              elseif (string.find(name, "semirare")) then
                child:setImageSource('/images/ui/rarity_purple')
              elseif (string.find(name, "uncommon")) then
                child:setImageSource('/images/ui/rarity_blue')
              elseif (string.find(name, "common")) then
                child:setImageSource('/images/ui/rarity_white') --checking if frames work at all
              end
            end
          end
      end
  end
end
 
Here it is, complete and updated... You need to remember the server side if it's a name that will send 'Epic' to the client... So, you should set it like this here.
elseif (string.find(name, "Epic")) then

You need to check the modules game_inventory and container to see if they are lowercase or uppercase. If it's lowercase and you set it as lowercase on the server side, for example, 'Leo' or 'Oen' or any custom script, make sure the name is also lowercase, like rarity, epic, rare, etc. Understand? Both names need to match.
Post automatically merged:

Here it is, complete and updated... You need to remember the server side if it's a name that will send 'Epic' to the client... So, you should set it like this here.
elseif (string.find(name, "Epic")) then

You need to check the modules game_inventory and container to see if they are lowercase or uppercase. If it's lowercase and you set it as lowercase on the server side, for example, 'Leo' or 'Oen' or any custom script, make sure the name is also lowercase, like rarity, epic, rare, etc. Understand? Both names need to match.
Post automatically merged:

Does this work regardless of whether you have a rarity system? For example, if I don't have that system and I want to create an item from scratch called a rare sword... should the item's SQM recognize it with this?
 
Hi, I'd like to ask you a question. I managed to install everything right thanks to the help of a friend. I wanted to know how I can do to appear the name of the item + attack and defense with the same color as the rarity.

Exemplo:
Captura de tela 2025-04-02 195421.webp

how's :

1743637611094.webp
 
Hi, I'd like to ask you a question. I managed to install everything right thanks to the help of a friend. I wanted to know how I can do to appear the name of the item + attack and defense with the same color as the rarity.

Exemplo:
View attachment 91530

how's :

View attachment 91531
Enable tooltip in otclient+ the item should be named legendary,epic,.ettc you can fix that in tooltip.lua
 
Enable tooltip in otclient+ the item should be named legendary,epic,.ettc you can fix that in tooltip.lua
i added already. But the name of the item does not appear


LUA:
-- @docclass
g_tooltip = {}

-- private variables
local toolTipLabel
local currentHoveredWidget

-- private functions
local function moveToolTip(first)
  if not first and (not toolTipLabel:isVisible() or toolTipLabel:getOpacity() < 0.1) then return end

  local pos = g_window.getMousePosition()
  local windowSize = g_window.getSize()
  local labelSize = toolTipLabel:getSize()

  pos.x = pos.x + 1
  pos.y = pos.y + 1

  if windowSize.width - (pos.x + labelSize.width) < 10 then
    pos.x = pos.x - labelSize.width - 10
  else
    pos.x = pos.x + 10
  end

  if windowSize.height - (pos.y + labelSize.height) < 10 then
    pos.y = pos.y - labelSize.height - 10
  else
    pos.y = pos.y + 10
  end

  toolTipLabel:setPosition(pos)

  -- Now calculate the position for the second tooltip (toolTipLabel2)
  if not first and (not toolTipLabel2:isVisible() or toolTipLabel2:getOpacity() < 0.1) then return end
  local label2Size = toolTipLabel2:getSize()
  local pos2 = { x = pos.x, y = pos.y + labelSize.height } -- here you can offset the second tooltip, labelSize.height +2 will create a small gap
  if windowSize.height - (pos2.y + label2Size.height) < 10 then
    pos2.y = pos2.y - label2Size.height - 10
  end

  -- Set the position of the second tooltip
  toolTipLabel2:setPosition(pos2)
end

local function onWidgetHoverChange(widget, hovered)
  if hovered then
    if widget.tooltip and not g_mouse.isPressed() then
      g_tooltip.display(widget.tooltip)
      currentHoveredWidget = widget
    end
  else
    if widget == currentHoveredWidget then
      g_tooltip.hide()
      currentHoveredWidget = nil
    end
  end
end

local function onWidgetStyleApply(widget, styleName, styleNode)
  if styleNode.tooltip then
    widget.tooltip = styleNode.tooltip
  end
end

-- public functions
function g_tooltip.init()
  connect(UIWidget, {
    onStyleApply = onWidgetStyleApply,
    onHoverChange = onWidgetHoverChange
  })

  addEvent(function()
    toolTipLabel = g_ui.createWidget('UILabel', rootWidget)
    toolTipLabel:setId('toolTip')
    toolTipLabel:setBackgroundColor('#111111cc')
    toolTipLabel:setTextAlign(AlignCenter)
    toolTipLabel:hide()

    toolTipLabel2 = g_ui.createWidget('UILabel', rootWidget)
    toolTipLabel2:setId('toolTip')
    toolTipLabel2:setBackgroundColor('#111111cc')
    toolTipLabel2:setTextAlign(AlignCenter)
    toolTipLabel2:hide()
  end)
end

function g_tooltip.terminate()
  disconnect(UIWidget, {
    onStyleApply = onWidgetStyleApply,
    onHoverChange = onWidgetHoverChange
  })

  currentHoveredWidget = nil
  toolTipLabel:destroy()
  toolTipLabel = nil

  g_tooltip = nil
end

function g_tooltip.display(text)
  if text == nil or text:len() == 0 then return end
  if not toolTipLabel or not toolTipLabel2 then return end

  -- Split the text into two parts: first line and rest
  local firstLine = text:match("^(.-)\n") or text -- If no newline, treat the entire text as firstLine
  local rest = text:match("\n(.*)") or ""         -- Empty if no second part
  local itemNameLower = firstLine:lower()
  -- Set color for the first line
  -- Rarity colors used from WoW wiki https://wowpedia.fandom.com/wiki/API_GetItemQualityColor
  toolTipLabel:setColor("#ffffff")
  if string.find(itemNameLower, "legendary") then
    toolTipLabel:setColor("#ff8000")
  elseif string.find(itemNameLower, "epic") then
    toolTipLabel:setColor("#a335ee")
  elseif string.find(itemNameLower, "rare") then
    toolTipLabel:setColor("#0070dd")
  end

 -- Set text for the first label
  toolTipLabel:setText(firstLine)
  toolTipLabel:resizeToText()
-- Set text for the second label (rest of the text)
toolTipLabel2:setColor("#ffffff")
toolTipLabel2:setText(rest)
toolTipLabel2:resizeToText()

-- Calculate maximum width between the two labels
local maxWidth = math.max(toolTipLabel:getWidth(), toolTipLabel2:getWidth())

-- Resize both tooltips to have the same width
toolTipLabel:resize(maxWidth + 4, toolTipLabel:getHeight() + 4)
toolTipLabel2:resize(maxWidth + 4, toolTipLabel2:getHeight() + 4)

-- Show both tooltips  toolTipLabel:show()
  toolTipLabel:raise()
  toolTipLabel:enable()

  toolTipLabel2:show()
  toolTipLabel2:raise()
  toolTipLabel2:enable()

  -- Handle fade-in effects
  g_effects.fadeIn(toolTipLabel, 100)
  g_effects.fadeIn(toolTipLabel2, 100)

  -- Move tooltips together on mouse move
  moveToolTip(true) -- Position tooltips initially 
  connect(rootWidget, {
    onMouseMove = moveToolTip,
  }) 
end

function g_tooltip.hide()
  g_effects.fadeOut(toolTipLabel, 100)
  g_effects.fadeOut(toolTipLabel2, 100)

 
  disconnect(rootWidget, {
    onMouseMove = moveToolTip,
  }) 
end


-- @docclass UIWidget @{

-- UIWidget extensions
function UIWidget:setTooltip(text)
  self.tooltip = text
end

function UIWidget:removeTooltip()
  self.tooltip = nil
end

function UIWidget:getTooltip()
  return self.tooltip
end

-- @}

g_tooltip.init()
connect(g_app, { onTerminate = g_tooltip.terminate })
 
Hello @jakub742
You said that you tested it on Nekiro 1.5 downgrade, but few of the commits from Added tooltips for inventory items · OTCv8/forgottenserver@7f5b4fb (https://github.com/OTCv8/forgottenserver/commit/7f5b4fbc08711124dec86b0fcd7bfd78dd1165c4) inside file protocolgame.cpp are commented in nekiro (I use Nekiro 1.5 Downgraded to 772 protocol). Any advice how you bypass this?
1743978048142.webp

1743978089252.webp

Found this commit:

but in networkmessage it does not make any sense

1743978825590.webp

In 1.5 Nekiro:

1743978933458.webp


Hi, I recently started to implement item tooltip into my server and i would like to share my current progress. Maybe it will help some people.

Tfs source changes: Added tooltips for inventory items · OTCv8/forgottenserver@7f5b4fb (https://github.com/OTCv8/forgottenserver/commit/7f5b4fbc08711124dec86b0fcd7bfd78dd1165c4)

Otclientv8:

How can I add colors to the sqm of rare, epic, legendary items? OTclient (https://otland.net/threads/how-can-i-add-colors-to-the-sqm-of-rare-epic-legendary-items-otclient.287456/#post-2741182)

From this post i edited containers.lua with "setFrames()" function.

Rarity frames worked in containers, however i wanted to have rarity frames in inventory aswell.
EDIT: there was bug in containers.lua that was causing frames to be still visible in containers after moving them to another container. (Thanks @Mateus Robeerto) updates are present in the PR link below.

Inventory frames:
To show rarity frame inside inventory add following function in modules/game_inventory/inventory.lua:

LUA:
local function setFrames(item, itemWidget)
  local name = item:getTooltip()
  if (name) then
    if (string.find(name, "legendary")) then
      itemWidget:setImageSource('/images/ui/rarity_gold')
    elseif (string.find(name, "epic")) then
      itemWidget:setImageSource('/images/ui/rarity_purple')
    elseif (string.find(name, "rare")) then
      itemWidget:setImageSource('/images/ui/rarity_blue')
    end
  end
end

above function
Code:
onInventoryChange(player, slot, item, oldItem)

inside onInventoryChange add
Code:
setFrames(item, itemWidget)
after
Code:
itemWidget:setItem(item)

View attachment 87568

After this frames are visible in inventory
View attachment 87569

Tooltip different color for item name based on rarity:
Next i tried to change the color of text in modules/corelib/ui/tooltip.lua
I wanted different color in tooltips based on item rarity.
My first attempt resulted in full text in color similar to @Itutorial in OTClient - Where are otclient's tooltips handled? (https://otland.net/threads/where-are-otclients-tooltips-handled.290034/)
View attachment 87573
(maybe u can use this as example :D)

In tooltip.lua i made second label widget toolTipLabel2.

toolTipLabel - contains item name (split after first new line \n)
toolTipLabel2 - contains rest of text


So we can set different colors for those 2 labels by :setColor()
Color codes used for "rare", "epic" and "legendary" used from WoW wiki: API GetItemQualityColor (https://wowpedia.fandom.com/wiki/API_GetItemQualityColor)

You can use this example to create another widget that will hold bonus stats, for example that can have different color.

Video:


If you hate my code dont hesitate to comment :D

Using this for rarity drops - [TFS 1.X] Rarity Rolls & Custom Attributes Library

Full commit with changes for OTclientV8 - Itemtooltip + rarity frames + name by jakub742 · Pull Request #1 · jakub742/otclientv8 (https://github.com/jakub742/otclientv8/pull/1/files)

Hope it will help someone ;) (Tested in Nekiro TFS 1.5 Downgrade)
 

Attachments

Last edited:
Hello @jakub742
You said that you tested it on Nekiro 1.5 downgrade, but few of the commits from Added tooltips for inventory items · OTCv8/forgottenserver@7f5b4fb (https://github.com/OTCv8/forgottenserver/commit/7f5b4fbc08711124dec86b0fcd7bfd78dd1165c4) inside file protocolgame.cpp are commented in nekiro (I use Nekiro 1.5 Downgraded to 772 protocol). Any advice how you bypass this?
View attachment 91616

View attachment 91617

Found this commit:

but in networkmessage it does not make any sense

View attachment 91624

In 1.5 Nekiro:

View attachment 91625
You need to uncomment those functions if i remember correctly.
 
Back
Top