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

color+itens

Mateus Robeerto

Excellent OT User
Joined
Jun 5, 2016
Messages
1,553
Solutions
78
Reaction score
981
Location
ლ(ಠ益ಠლ)
I would like to clear some doubts. I noticed that in Sarah's post, she mentioned something interesting about that color item that was inside the backpack, indicated by a blue frame, the "Demon Helmet". I'm not sure if this only applies to backpacks or if it's possible for item slots as well. Is it possible to add colors to these items?


For example, if I want to create a forge system, whether in a modal window or not, where the common "Demon Helmet" has no color, but when refining to +1 Tier it turns gray, +2 Tier blue , +3 Tier with red color and +4 Tier with yellow color, indicating that it has become legendary...

Is it possible to implement these features? I'm using TFS 1.4.2 and I've already made some updates through the commits that Evil Punker posted. Can I find these functions? I just want to clarify this. Thanks!

 
Last edited:
Of course it is possible if you use OTCv8 for example in the bot module it has a section in the analyzer where it places the rarity frame for the items based on their name and price, and if you experiment with the function and make your own module you can see It is not very difficult to achieve what you want.




With patience you could achieve things like the ones I achieved on my server. And that also exists in many others.
1693573240197.png

1693573170352.png
 
Of course it is possible if you use OTCv8 for example in the bot module it has a section in the analyzer where it places the rarity frame for the items based on their name and price, and if you experiment with the function and make your own module you can see It is not very difficult to achieve what you want.




With patience you could achieve things like the ones I achieved on my server. And that also exists in many others.
View attachment 78090

View attachment 78089

Wow, what you've done is really amazing! It was very beautiful... I loved it. Thanks for sharing the link. I'll try calmly and patiently... Thank you very much!
 
I would like to clear some doubts. I noticed that in Sarah's post, she mentioned something interesting about that color item that was inside the backpack, indicated by a blue frame, the "Demon Helmet". I'm not sure if this only applies to backpacks or if it's possible for item slots as well. Is it possible to add colors to these items?


For example, if I want to create a forge system, whether in a modal window or not, where the common "Demon Helmet" has no color, but when refining to +1 Tier it turns gray, +2 Tier blue , +3 Tier with red color and +4 Tier with yellow color, indicating that it has become legendary...

Is it possible to implement these features? I'm using TFS 1.4.2 and I've already made some updates through the commits that Evil Punker posted. Can I find these functions? I just want to clarify this. Thanks!


Take a look on this guy project: Darkrest.Online - Nostalgia Redefined - Discussion Thread (https://otland.net/threads/darkrest-online-nostalgia-redefined-discussion-thread.285667/#post-2729207)
68777-9ea79497f375dd12468644a8a7e60c98.data
 
Of course it is possible if you use OTCv8 for example in the bot module it has a section in the analyzer where it places the rarity frame for the items based on their name and price, and if you experiment with the function and make your own module you can see It is not very difficult to achieve what you want.




With patience you could achieve things like the ones I achieved on my server. And that also exists in many others.
View attachment 78090

View attachment 78089
Would it be possible to apply this rarity system for the same price in the bot, directly in the inventory module, or would it be necessary to create another module?

I'm new to the subject, I don't know anything about otcv8, but I wanted to add colored items to this system by rarity, id, name, or something that makes it easier, how do you recommend I start?
 
Would it be possible to apply this rarity system for the same price in the bot, directly in the inventory module, or would it be necessary to create another module?

I'm new to the subject, I don't know anything about otcv8, but I wanted to add colored items to this system by rarity, id, name, or something that makes it easier, how do you recommend I start?

When I mentioned the function of the bot module it is so that you can have a clear example of how it works, it is best to use your own module, from scratch with the precise functions to obtain the "thing" of the item in question, in this case, can be the tooltip information which, once obtained, you can create variables to generate things in question, such as your own tooltip or, failing that, the desired colorful box according to its rarity, which can be obtained through the attributes of the item.

The specific function through the client is:

item:getCustomAttribute()







Of course, your server base must also have the CustomAttributes() added. or failing that you can use any other get function.
 
When I mentioned the function of the bot module it is so that you can have a clear example of how it works, it is best to use your own module, from scratch with the precise functions to obtain the "thing" of the item in question, in this case, can be the tooltip information which, once obtained, you can create variables to generate things in question, such as your own tooltip or, failing that, the desired colorful box according to its rarity, which can be obtained through the attributes of the item.

The specific function through the client is:

item:getCustomAttribute()







Of course, your server base must also have the CustomAttributes() added. or failing that you can use any other get function.
but I have a complete module that I received from a guy a few days ago. Will it be necessary to make changes to the font to use it? So, will I need to create a script to send and recognize the opcode on the otclient side?
 
but I have a complete module that I received from a guy a few days ago. Will it be necessary to make changes to the font to use it? So, will I need to create a script to send and recognize the opcode on the otclient side?

I'm not at all good with modules, much less opcodes. In fact, on my part everything is very rudimentary, I use a list of items used as a library in the client. I did not send information from the server at any time other than for the rarity of the items. But I get the information table directly from a file.

At least I could "have" this to test locally. It could further expand its functionalities, even give the information window an attractive appearance. But since I'm not usually one of those who likes to pay for something that is obtained with the same information from the server/client. That's why I don't have a way to fully explain it. In fact, part of what I have is information that I was able to deduce thanks to the fact that I bought some modules from Oen in the past, which did not have directly to do with the topic of the colorful rarity box, much less the Tooltip. But it did help me to be able to analyze this topic a lot.
Post automatically merged:

Without further ado, I think I can give you some information about the module I made for this. The way it works and how I place the colorful frame on the items is as follows:

LUA:
-- Update the frame of an item in the user interface
function updateUIItemFrame(uiItem, item, oldItem)
  local currentItem = uiItem:getItem()

  -- Set the rarity frame image of the current item if applicable
  if currentItem then
    local currentRarityId = currentItem:getCustomAttribute(ATTR_RARITY)
    if currentRarityId and currentRarityId > 1 then
      uiItem:setImageSource("/images/rarity/"..Rarities[currentRarityId].."_rarity")
    else
      uiItem:setImageSource("/images/ui/item") -- No rarity found, set default image
    end
  else
    uiItem:setImageSource("/images/ui/item") -- There is no item, set default image
  end

  -- Remove rarity image from previous item if applicable
  if oldItem then
    local oldRarityId = oldItem:getCustomAttribute(ATTR_RARITY)
    if oldRarityId and oldRarityId > 1 and (not currentItem or oldRarityId ~= currentItem:getCustomAttribute(ATTR_RARITY)) then
      modules.game_interface.getContainerItemWidget(uiItem):setImageSource("/images/ui/item") -- set default image
    end
  end
end

For the other methods and everything else, I already helped you a lot in the whole discussion, you have all the information necessary to build your own module. It is always good to learn a little, if we had everything done we would never strive to achieve it.
 
Last edited:
Wow, what you've done is really amazing! It was very beautiful... I loved it. Thanks for sharing the link. I'll try calmly and patiently... Thank you very much!
Good morning friend, man, I'm trying to do this, I'm not succeeding, I even understand the modules but I'm not able to create one, is there any way you can help me???
 
Of course it is possible if you use OTCv8 for example in the bot module it has a section in the analyzer where it places the rarity frame for the items based on their name and price, and if you experiment with the function and make your own module you can see It is not very difficult to achieve what you want.




With patience you could achieve things like the ones I achieved on my server. And that also exists in many others.
View attachment 78090

View attachment 78089
bro can you help me with this?
 
I'm not at all good with modules, much less opcodes. In fact, on my part everything is very rudimentary, I use a list of items used as a library in the client. I did not send information from the server at any time other than for the rarity of the items. But I get the information table directly from a file.

At least I could "have" this to test locally. It could further expand its functionalities, even give the information window an attractive appearance. But since I'm not usually one of those who likes to pay for something that is obtained with the same information from the server/client. That's why I don't have a way to fully explain it. In fact, part of what I have is information that I was able to deduce thanks to the fact that I bought some modules from Oen in the past, which did not have directly to do with the topic of the colorful rarity box, much less the Tooltip. But it did help me to be able to analyze this topic a lot.
Post automatically merged:

Without further ado, I think I can give you some information about the module I made for this. The way it works and how I place the colorful frame on the items is as follows:

LUA:
-- Update the frame of an item in the user interface
function updateUIItemFrame(uiItem, item, oldItem)
  local currentItem = uiItem:getItem()

  -- Set the rarity frame image of the current item if applicable
  if currentItem then
    local currentRarityId = currentItem:getCustomAttribute(ATTR_RARITY)
    if currentRarityId and currentRarityId > 1 then
      uiItem:setImageSource("/images/rarity/"..Rarities[currentRarityId].."_rarity")
    else
      uiItem:setImageSource("/images/ui/item") -- No rarity found, set default image
    end
  else
    uiItem:setImageSource("/images/ui/item") -- There is no item, set default image
  end

  -- Remove rarity image from previous item if applicable
  if oldItem then
    local oldRarityId = oldItem:getCustomAttribute(ATTR_RARITY)
    if oldRarityId and oldRarityId > 1 and (not currentItem or oldRarityId ~= currentItem:getCustomAttribute(ATTR_RARITY)) then
      modules.game_interface.getContainerItemWidget(uiItem):setImageSource("/images/ui/item") -- set default image
    end
  end
end

For the other methods and everything else, I already helped you a lot in the whole discussion, you have all the information necessary to build your own module. It is always good to learn a little, if we had everything done we would never strive to achieve it.
I put this code, but it didn't work, this is my containers.lua
LUA:
local gameStart = 0

function init()
  connect(Container, { onOpen = onContainerOpen,
                       onClose = onContainerClose,
                       onSizeChange = onContainerChangeSize,
                       onUpdateItem = onContainerUpdateItem })
  connect(g_game, {
    onGameStart = markStart,
    onGameEnd = clean
  })

  reloadContainers()
end

function terminate()
  disconnect(Container, { onOpen = onContainerOpen,
                          onClose = onContainerClose,
                          onSizeChange = onContainerChangeSize,
                          onUpdateItem = onContainerUpdateItem })
  disconnect(g_game, {
    onGameStart = markStart,
    onGameEnd = clean
  })
end

function reloadContainers()
  clean()
  for _,container in pairs(g_game.getContainers()) do
    onContainerOpen(container)
  end
end

function clean()
  for containerid,container in pairs(g_game.getContainers()) do
    destroy(container)
  end
end

function markStart()
  gameStart = g_clock.millis()
end

function destroy(container)
  if container.window then
    container.window:destroy()
    container.window = nil
    container.itemsPanel = nil
  end
end

function refreshContainerItems(container)
  for slot=0,container:getCapacity()-1 do
    local itemWidget = container.itemsPanel:getChildById('item' .. slot)
    itemWidget:setItem(container:getItem(slot))
  end

  if container:hasPages() then
    refreshContainerPages(container)
  end
end

function toggleContainerPages(containerWindow, hasPages)
  if hasPages == containerWindow.pagePanel:isOn() then
    return
  end
  containerWindow.pagePanel:setOn(hasPages)
  if hasPages then
    containerWindow.miniwindowScrollBar:setMarginTop(containerWindow.miniwindowScrollBar:getMarginTop() + containerWindow.pagePanel:getHeight())
    containerWindow.contentsPanel:setMarginTop(containerWindow.contentsPanel:getMarginTop() + containerWindow.pagePanel:getHeight()) 
  else 
    containerWindow.miniwindowScrollBar:setMarginTop(containerWindow.miniwindowScrollBar:getMarginTop() - containerWindow.pagePanel:getHeight())
    containerWindow.contentsPanel:setMarginTop(containerWindow.contentsPanel:getMarginTop() - containerWindow.pagePanel:getHeight())
  end
end

function refreshContainerPages(container)
  local currentPage = 1 + math.floor(container:getFirstIndex() / container:getCapacity())
  local pages = 1 + math.floor(math.max(0, (container:getSize() - 1)) / container:getCapacity())
  container.window:recursiveGetChildById('pageLabel'):setText(string.format('Page %i of %i', currentPage, pages))

  local prevPageButton = container.window:recursiveGetChildById('prevPageButton')
  if currentPage == 1 then
    prevPageButton:setEnabled(false)
  else
    prevPageButton:setEnabled(true)
    prevPageButton.onClick = function() g_game.seekInContainer(container:getId(), container:getFirstIndex() - container:getCapacity()) end
  end

  local nextPageButton = container.window:recursiveGetChildById('nextPageButton')
  if currentPage >= pages then
    nextPageButton:setEnabled(false)
  else
    nextPageButton:setEnabled(true)
    nextPageButton.onClick = function() g_game.seekInContainer(container:getId(), container:getFirstIndex() + container:getCapacity()) end
  end
 
  local pagePanel = container.window:recursiveGetChildById('pagePanel')
  if pagePanel then
    pagePanel.onMouseWheel = function(widget, mousePos, mouseWheel)
      if pages == 1 then return end
      if mouseWheel == MouseWheelUp then
        return prevPageButton.onClick()
      else
        return nextPageButton.onClick()
      end
    end
  end
end

local function setFrames()
  for _, container in pairs(g_game.getContainers()) do
      local window = container.itemsPanel
      for i, child in pairs(window:getChildren()) do
          local id = child:getItemId()
          local price = 0

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

      end
  end
end

function onContainerOpen(container, previousContainer)
  local containerWindow
  if previousContainer then
    containerWindow = previousContainer.window
    previousContainer.window = nil
    previousContainer.itemsPanel = nil
  else
    containerWindow = g_ui.createWidget('ContainerWindow', modules.game_interface.getContainerPanel())

    -- white border flash effect
    containerWindow:setBorderWidth(2)
    containerWindow:setBorderColor("#FFFFFF")
    scheduleEvent(function()
      if containerWindow then
        containerWindow:setBorderWidth(0)
      end
    end, 300)
  end
 
  containerWindow:setId('container' .. container:getId())
  if gameStart + 1000 < g_clock.millis() then
    containerWindow:clearSettings()
  end
 
  local containerPanel = containerWindow:getChildById('contentsPanel')
  local containerItemWidget = containerWindow:getChildById('containerItemWidget')
  containerWindow.onClose = function()
    g_game.close(container)
    containerWindow:hide()
  end
  containerWindow.onDrop = function(container, widget, mousePos)
    if containerPanel:getChildByPos(mousePos) then
      return false
    end
    local child = containerPanel:getChildByIndex(-1)
    if child then
      child:onDrop(widget, mousePos, true)       
    end
  end
 
  containerWindow.onMouseRelease = function(widget, mousePos, mouseButton)
    if mouseButton == MouseButton4 then
      if container:hasParent() then
        return g_game.openParent(container)
      end
    elseif mouseButton == MouseButton5 then
      for i, item in ipairs(container:getItems()) do
        if item:isContainer() then
          return g_game.open(item, container)
        end
      end
    end
  end

  -- this disables scrollbar auto hiding
  local scrollbar = containerWindow:getChildById('miniwindowScrollBar')
  scrollbar:mergeStyle({ ['$!on'] = { }})

  local upButton = containerWindow:getChildById('upButton')
  upButton.onClick = function()
    g_game.openParent(container)
  end
  upButton:setVisible(container:hasParent())

  local name = container:getName()
  name = name:sub(1,1):upper() .. name:sub(2)
  containerWindow:setText(name)

  containerItemWidget:setItem(container:getContainerItem())

  containerPanel:destroyChildren()
  for slot=0,container:getCapacity()-1 do
    local itemWidget = g_ui.createWidget('Item', containerPanel)
    itemWidget:setId('item' .. slot)
    itemWidget:setItem(container:getItem(slot))
    itemWidget:setMargin(0)
    itemWidget.position = container:getSlotPosition(slot)

    if not container:isUnlocked() then
      itemWidget:setBorderColor('red')
    end
  end

  container.window = containerWindow
  container.itemsPanel = containerPanel

  toggleContainerPages(containerWindow, container:hasPages())
  refreshContainerPages(container)

  local layout = containerPanel:getLayout()
  local cellSize = layout:getCellSize()
  containerWindow:setContentMinimumHeight(cellSize.height)
  containerWindow:setContentMaximumHeight(cellSize.height*layout:getNumLines())

  if container:hasPages() then
    local height = containerWindow.miniwindowScrollBar:getMarginTop() + containerWindow.pagePanel:getHeight()+17
    if containerWindow:getHeight() < height then
      containerWindow:setHeight(height)
    end
  end

  if not previousContainer then
    local filledLines = math.max(math.ceil(container:getItemsCount() / layout:getNumColumns()), 1)
    containerWindow:setContentHeight(filledLines*cellSize.height)
  end
  setFrames()
  containerWindow:setup()
end

function onContainerClose(container)
  destroy(container)
end

function onContainerChangeSize(container, size)
  if not container.window then return end
  refreshContainerItems(container)
  setFrames()
end

function onContainerUpdateItem(container, slot, item, oldItem)
  if not container.window then return end
  local itemWidget = container.itemsPanel:getChildById('item' .. slot)
  itemWidget:setItem(item)
  setFrames()
end
 
I put this code, but it didn't work, this is my containers.lua
LUA:
local gameStart = 0

function init()
  connect(Container, { onOpen = onContainerOpen,
                       onClose = onContainerClose,
                       onSizeChange = onContainerChangeSize,
                       onUpdateItem = onContainerUpdateItem })
  connect(g_game, {
    onGameStart = markStart,
    onGameEnd = clean
  })

  reloadContainers()
end

function terminate()
  disconnect(Container, { onOpen = onContainerOpen,
                          onClose = onContainerClose,
                          onSizeChange = onContainerChangeSize,
                          onUpdateItem = onContainerUpdateItem })
  disconnect(g_game, {
    onGameStart = markStart,
    onGameEnd = clean
  })
end

function reloadContainers()
  clean()
  for _,container in pairs(g_game.getContainers()) do
    onContainerOpen(container)
  end
end

function clean()
  for containerid,container in pairs(g_game.getContainers()) do
    destroy(container)
  end
end

function markStart()
  gameStart = g_clock.millis()
end

function destroy(container)
  if container.window then
    container.window:destroy()
    container.window = nil
    container.itemsPanel = nil
  end
end

function refreshContainerItems(container)
  for slot=0,container:getCapacity()-1 do
    local itemWidget = container.itemsPanel:getChildById('item' .. slot)
    itemWidget:setItem(container:getItem(slot))
  end

  if container:hasPages() then
    refreshContainerPages(container)
  end
end

function toggleContainerPages(containerWindow, hasPages)
  if hasPages == containerWindow.pagePanel:isOn() then
    return
  end
  containerWindow.pagePanel:setOn(hasPages)
  if hasPages then
    containerWindow.miniwindowScrollBar:setMarginTop(containerWindow.miniwindowScrollBar:getMarginTop() + containerWindow.pagePanel:getHeight())
    containerWindow.contentsPanel:setMarginTop(containerWindow.contentsPanel:getMarginTop() + containerWindow.pagePanel:getHeight())
  else
    containerWindow.miniwindowScrollBar:setMarginTop(containerWindow.miniwindowScrollBar:getMarginTop() - containerWindow.pagePanel:getHeight())
    containerWindow.contentsPanel:setMarginTop(containerWindow.contentsPanel:getMarginTop() - containerWindow.pagePanel:getHeight())
  end
end

function refreshContainerPages(container)
  local currentPage = 1 + math.floor(container:getFirstIndex() / container:getCapacity())
  local pages = 1 + math.floor(math.max(0, (container:getSize() - 1)) / container:getCapacity())
  container.window:recursiveGetChildById('pageLabel'):setText(string.format('Page %i of %i', currentPage, pages))

  local prevPageButton = container.window:recursiveGetChildById('prevPageButton')
  if currentPage == 1 then
    prevPageButton:setEnabled(false)
  else
    prevPageButton:setEnabled(true)
    prevPageButton.onClick = function() g_game.seekInContainer(container:getId(), container:getFirstIndex() - container:getCapacity()) end
  end

  local nextPageButton = container.window:recursiveGetChildById('nextPageButton')
  if currentPage >= pages then
    nextPageButton:setEnabled(false)
  else
    nextPageButton:setEnabled(true)
    nextPageButton.onClick = function() g_game.seekInContainer(container:getId(), container:getFirstIndex() + container:getCapacity()) end
  end
 
  local pagePanel = container.window:recursiveGetChildById('pagePanel')
  if pagePanel then
    pagePanel.onMouseWheel = function(widget, mousePos, mouseWheel)
      if pages == 1 then return end
      if mouseWheel == MouseWheelUp then
        return prevPageButton.onClick()
      else
        return nextPageButton.onClick()
      end
    end
  end
end

local function setFrames()
  for _, container in pairs(g_game.getContainers()) do
      local window = container.itemsPanel
      for i, child in pairs(window:getChildren()) do
          local id = child:getItemId()
          local price = 0

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

      end
  end
end

function onContainerOpen(container, previousContainer)
  local containerWindow
  if previousContainer then
    containerWindow = previousContainer.window
    previousContainer.window = nil
    previousContainer.itemsPanel = nil
  else
    containerWindow = g_ui.createWidget('ContainerWindow', modules.game_interface.getContainerPanel())

    -- white border flash effect
    containerWindow:setBorderWidth(2)
    containerWindow:setBorderColor("#FFFFFF")
    scheduleEvent(function()
      if containerWindow then
        containerWindow:setBorderWidth(0)
      end
    end, 300)
  end
 
  containerWindow:setId('container' .. container:getId())
  if gameStart + 1000 < g_clock.millis() then
    containerWindow:clearSettings()
  end
 
  local containerPanel = containerWindow:getChildById('contentsPanel')
  local containerItemWidget = containerWindow:getChildById('containerItemWidget')
  containerWindow.onClose = function()
    g_game.close(container)
    containerWindow:hide()
  end
  containerWindow.onDrop = function(container, widget, mousePos)
    if containerPanel:getChildByPos(mousePos) then
      return false
    end
    local child = containerPanel:getChildByIndex(-1)
    if child then
      child:onDrop(widget, mousePos, true)      
    end
  end
 
  containerWindow.onMouseRelease = function(widget, mousePos, mouseButton)
    if mouseButton == MouseButton4 then
      if container:hasParent() then
        return g_game.openParent(container)
      end
    elseif mouseButton == MouseButton5 then
      for i, item in ipairs(container:getItems()) do
        if item:isContainer() then
          return g_game.open(item, container)
        end
      end
    end
  end

  -- this disables scrollbar auto hiding
  local scrollbar = containerWindow:getChildById('miniwindowScrollBar')
  scrollbar:mergeStyle({ ['$!on'] = { }})

  local upButton = containerWindow:getChildById('upButton')
  upButton.onClick = function()
    g_game.openParent(container)
  end
  upButton:setVisible(container:hasParent())

  local name = container:getName()
  name = name:sub(1,1):upper() .. name:sub(2)
  containerWindow:setText(name)

  containerItemWidget:setItem(container:getContainerItem())

  containerPanel:destroyChildren()
  for slot=0,container:getCapacity()-1 do
    local itemWidget = g_ui.createWidget('Item', containerPanel)
    itemWidget:setId('item' .. slot)
    itemWidget:setItem(container:getItem(slot))
    itemWidget:setMargin(0)
    itemWidget.position = container:getSlotPosition(slot)

    if not container:isUnlocked() then
      itemWidget:setBorderColor('red')
    end
  end

  container.window = containerWindow
  container.itemsPanel = containerPanel

  toggleContainerPages(containerWindow, container:hasPages())
  refreshContainerPages(container)

  local layout = containerPanel:getLayout()
  local cellSize = layout:getCellSize()
  containerWindow:setContentMinimumHeight(cellSize.height)
  containerWindow:setContentMaximumHeight(cellSize.height*layout:getNumLines())

  if container:hasPages() then
    local height = containerWindow.miniwindowScrollBar:getMarginTop() + containerWindow.pagePanel:getHeight()+17
    if containerWindow:getHeight() < height then
      containerWindow:setHeight(height)
    end
  end

  if not previousContainer then
    local filledLines = math.max(math.ceil(container:getItemsCount() / layout:getNumColumns()), 1)
    containerWindow:setContentHeight(filledLines*cellSize.height)
  end
  setFrames()
  containerWindow:setup()
end

function onContainerClose(container)
  destroy(container)
end

function onContainerChangeSize(container, size)
  if not container.window then return end
  refreshContainerItems(container)
  setFrames()
end

function onContainerUpdateItem(container, slot, item, oldItem)
  if not container.window then return end
  local itemWidget = container.itemsPanel:getChildById('item' .. slot)
  itemWidget:setItem(item)
  setFrames()
end

Hi, I'm back. I have a question about your code: does the item have the name directly, or is it added via an attribute? Does the console show you the entire name of the item, including the 'legendary' part?
 
Hi, I'm back. I have a question about your code: does the item have the name directly, or is it added via an attribute? Does the console show you the entire name of the item, including the 'legendary' part?
This is the script I'm using for randomstats, I know it's old, but I feel it does its job well and I like how simple it is:
randomstats.lua:
LUA:
local rare_popup = true
local rare_text = "*rare*"
local rare_effect = true
local rare_effect_id = CONST_ME_MAGIC_GREEN

local tiers = {
    [1] = {
        prefix = 'rare',
        showattr = true, -- attr prefix will be shown instead
        extra = {0, 0},
        chance = {
            [1] = 10000, -- chance for basic stat
            [2] = 5000 -- chance for second stat
        }
    },

    [2] = {
        prefix = 'epic',
        extra = {7, 20}, -- additional percent bonus
        chance = {
            [1] = 3333,
            [2] = 25000
        }
    },

    [3] = {
        prefix = 'legendary',
        extra = {20, 35},
        chance = {
            [1] = 1000,
            [2] = 100000 -- 2 bonuses always
        }
    },
}

--! attributes
local attr = {
    atk = {
        name = 'atk',
        prefix = 'sharpened',
        percent = {7, 25},
    },
    def = {
        name = 'def',
        prefix = 'fortified',
        percent = {7, 25},
    },
    extradef = {
        name = 'extra def',
        prefix = 'balanced',
        percent = {7, 25},
    },
    arm = {
        name = 'arm',
        prefix = 'flawless',
        percent = {7, 20},
    },
    hitchance = {
        name = 'accuracy',
        prefix = 'accurate',
        percent = {10, 25},
    },
    shootrange = {
        name = 'range',
        prefix = 'powerful',
        percent = {17, 34},
    },
    charges = {
        name = 'charges',
        prefix = 'charged',
        percent = {30, 45},
    },
    duration = {
        name = 'time',
        prefix = 'unique',
        percent = {35, 50},
    },

    --[[ not available in 1.1
    attackSpeed = {},
    extraAttack = {},
    ]]
}

local stats = {
    [1] = {ITEM_ATTRIBUTE_ATTACK, attr.atk},
    [2] = {ITEM_ATTRIBUTE_DEFENSE, attr.def},
    [3] = {ITEM_ATTRIBUTE_EXTRADEFENSE, attr.extradef},
    [4] = {ITEM_ATTRIBUTE_ARMOR, attr.arm},
    [5] = {ITEM_ATTRIBUTE_HITCHANCE, attr.hitchance},
    [6] = {ITEM_ATTRIBUTE_SHOOTRANGE, attr.shootrange},
    [7] = {ITEM_ATTRIBUTE_CHARGES, attr.charges},
    [8] = {ITEM_ATTRIBUTE_DURATION, attr.duration},
    -- not available in 1.1
    -- [9] = {ITEM_ATTRIBUTE_ATTACKSPEED, attr.attackSpeed},
    -- [10] = {ITEM_ATTRIBUTE_EXTRAATTACK, attr.extraAttack},
}

function stat_getItemDuration(item)
    local it_id = item:getId()
    local tid = ItemType(it_id):getTransformEquipId()
    if tid > 0 then
        item:transform(tid)
        local vx = item:getAttribute(ITEM_ATTRIBUTE_DURATION)
        item:transform(it_id)
        item:removeAttribute(ITEM_ATTRIBUTE_DURATION)
        return vx
    end
    return 0
end

function loot_attrToVal(item, attr)
    local id = ItemType(item:getId())
    local v = {
        [ITEM_ATTRIBUTE_ATTACK] = id:getAttack(),
        [ITEM_ATTRIBUTE_DEFENSE] = id:getDefense(),
        [ITEM_ATTRIBUTE_EXTRADEFENSE] = id:getExtraDefense(),
        [ITEM_ATTRIBUTE_ARMOR] = id:getArmor(),
        [ITEM_ATTRIBUTE_HITCHANCE] = id:getHitChance(),
        [ITEM_ATTRIBUTE_SHOOTRANGE] = id:getShootRange(),
        [ITEM_ATTRIBUTE_CHARGES] = id:getCharges(),
        [ITEM_ATTRIBUTE_DURATION] = stat_getItemDuration(item),

        -- not available in 1.1
        -- [ITEM_ATTRIBUTE_ATTACKSPEED] = item:getAttackSpeed(),
        -- [ITEM_ATTRIBUTE_EXTRAATTACK] = item:getExtraAttack(),
    }
    return v[attr]
end

function assign_loot_Stat(c)
    local rares = 0
    local h = c:getItemHoldingCount()
    if h > 0 then
        for i = 1, h do
            local available_stats = {}
            local it_u = c:getItem(i - 1)
            local it_id = ItemType(it_u:getId())
            if it_u:isContainer() then
                local crares = assign_loot_Stat(it_u)
                rares = rares + crares
            else
                if not it_id:isStackable() then
                    local wp = it_id:getWeaponType()
                    if wp > 0 then
                        if wp == WEAPON_SHIELD then -- type shield
                            table.insert(available_stats, stats[2])
                        elseif wp == WEAPON_DISTANCE then -- type bow
                            table.insert(available_stats, stats[1])
                            table.insert(available_stats, stats[5])
                            table.insert(available_stats, stats[6])
                            -- not available in 1.1
                            -- table.insert(available_stats, stats[9])
                        elseif wp == WEAPON_WAND then -- type wand
                            table.insert(available_stats, stats[6])
                        -- not available in 1.1
                        -- table.insert(available_stats, stats[9])
                        elseif isInArray({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE}, wp) then -- melee weapon

                            if it_id:getAttack() > 0 then
                                table.insert(available_stats, stats[1])
                            end
                            
                            if it_id:getDefense() > 0 then
                                table.insert(available_stats, stats[2])
                            end
                            
                            if it_id:getExtraDefense() ~= 0 then
                                table.insert(available_stats, stats[3])
                            end
                            -- not available in 1.1
                            -- table.insert(available_stats, stats[10])
                        end
                    else -- armors, amulets, runes and rings
                        if it_id:getArmor() > 0 then
                            table.insert(available_stats, stats[4])
                        end

                        if it_id:getCharges() > 0 then
                            table.insert(available_stats, stats[7])
                        end

                        local eq_id = it_id:getTransformEquipId()
                        if eq_id > 0 then
                            table.insert(available_stats, stats[8])
                        end
                    end
                end
            end

            if #available_stats > 0 then
                -- skips it all if it's empty
                local tier = math.random(1, #tiers)
                if #tiers[tier].chance > 0 then
                    local statsStored = 0
                    local stats_used = {}
                    for stat = 1, #tiers[tier].chance do
                        if #available_stats > 0 then
                            -- stops if no more stats available
                            if stat - 1 == statsStored then
                                -- checks when it's time to stop adding stats
                                if math.random(1, 100000) <= tiers[tier].chance[stat] then
                                    statsStored = statsStored + 1

                                    local selected_stat = math.random(1, #available_stats)
                                    table.insert(stats_used, available_stats[selected_stat])
                                    table.remove(available_stats, selected_stat)
                                end
                            end
                        end
                    end

                    if #stats_used > 0 then
                        rares = rares + 1
                        local stat_desc = {}
                        for stat = 1, #stats_used do
                            local v = math.random(
                                stats_used[stat][2].percent[1],
                                stats_used[stat][2].percent[2]
                            ) + math.random(
                                tiers[tier].extra[1],
                                tiers[tier].extra[2]
                            )
                            local basestat = loot_attrToVal(it_u, stats_used[stat][1])
                            it_u:setAttribute(stats_used[stat][1], basestat + math.abs(basestat * v / 100))
                            table.insert(stat_desc, '[' .. stats_used[stat][2].name .. ': +' .. v .. '%]')
                        end

                        if tiers[tier].showattr then
                            for stat = 1, #stats_used do
                                it_u:setAttribute(ITEM_ATTRIBUTE_NAME, "[" .. stats_used[stat][2].prefix .. "]" .. it_u:getAttribute(ITEM_ATTRIBUTE_NAME))
                            end
                            it_u:setAttribute(ITEM_ATTRIBUTE_NAME, it_u:getAttribute(ITEM_ATTRIBUTE_NAME) .. " " .. it_id:getName())
                        else
                            it_u:setAttribute(ITEM_ATTRIBUTE_NAME, tiers[tier].prefix .. " " .. it_id:getName())
                        end

                        it_u:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, table.concat(stat_desc, "\n"))
                    end
                end
            end
        end
    end
    return rares
end

function find_loot_Container(pos)
    local rares = 0
    local c = Tile(pos):getTopDownItem()
    if c ~= nil then
        if c:isContainer() then
            rares = rares + assign_loot_Stat(c)
            if rares > 0 then
                if rare_popup then
                    local spectators = Game.getSpectators(pos, false, true, 7, 7, 5, 5)
                    for i = 1, #spectators do
                        spectators[i]:say(rare_text, TALKTYPE_MONSTER_SAY, false, spectators[i], pos)
                    end
                end

                if rare_effect then
                    pos:sendMagicEffect(rare_effect_id)
                end
            end
            return true
        end
    end
end

function onKill(player, target, lastHit)
    if (not isSummon(target)) then
        addEvent(find_loot_Container, 2, target:getPosition())
    end
    return true
end

function onLogin(player)
    player:registerEvent("randomstats_loot")
    return true
end
nestooor.png
I don't know if the error is in the scripth, or I don't know why you don't take it... The script works, it has a mistake just in giving me a specific stats, but I think it fulfills its function well, I don't know what I'm doing wrong
 
This is the script I'm using for randomstats, I know it's old, but I feel it does its job well and I like how simple it is:
randomstats.lua:
LUA:
local rare_popup = true
local rare_text = "*rare*"
local rare_effect = true
local rare_effect_id = CONST_ME_MAGIC_GREEN

local tiers = {
    [1] = {
        prefix = 'rare',
        showattr = true, -- attr prefix will be shown instead
        extra = {0, 0},
        chance = {
            [1] = 10000, -- chance for basic stat
            [2] = 5000 -- chance for second stat
        }
    },

    [2] = {
        prefix = 'epic',
        extra = {7, 20}, -- additional percent bonus
        chance = {
            [1] = 3333,
            [2] = 25000
        }
    },

    [3] = {
        prefix = 'legendary',
        extra = {20, 35},
        chance = {
            [1] = 1000,
            [2] = 100000 -- 2 bonuses always
        }
    },
}

--! attributes
local attr = {
    atk = {
        name = 'atk',
        prefix = 'sharpened',
        percent = {7, 25},
    },
    def = {
        name = 'def',
        prefix = 'fortified',
        percent = {7, 25},
    },
    extradef = {
        name = 'extra def',
        prefix = 'balanced',
        percent = {7, 25},
    },
    arm = {
        name = 'arm',
        prefix = 'flawless',
        percent = {7, 20},
    },
    hitchance = {
        name = 'accuracy',
        prefix = 'accurate',
        percent = {10, 25},
    },
    shootrange = {
        name = 'range',
        prefix = 'powerful',
        percent = {17, 34},
    },
    charges = {
        name = 'charges',
        prefix = 'charged',
        percent = {30, 45},
    },
    duration = {
        name = 'time',
        prefix = 'unique',
        percent = {35, 50},
    },

    --[[ not available in 1.1
    attackSpeed = {},
    extraAttack = {},
    ]]
}

local stats = {
    [1] = {ITEM_ATTRIBUTE_ATTACK, attr.atk},
    [2] = {ITEM_ATTRIBUTE_DEFENSE, attr.def},
    [3] = {ITEM_ATTRIBUTE_EXTRADEFENSE, attr.extradef},
    [4] = {ITEM_ATTRIBUTE_ARMOR, attr.arm},
    [5] = {ITEM_ATTRIBUTE_HITCHANCE, attr.hitchance},
    [6] = {ITEM_ATTRIBUTE_SHOOTRANGE, attr.shootrange},
    [7] = {ITEM_ATTRIBUTE_CHARGES, attr.charges},
    [8] = {ITEM_ATTRIBUTE_DURATION, attr.duration},
    -- not available in 1.1
    -- [9] = {ITEM_ATTRIBUTE_ATTACKSPEED, attr.attackSpeed},
    -- [10] = {ITEM_ATTRIBUTE_EXTRAATTACK, attr.extraAttack},
}

function stat_getItemDuration(item)
    local it_id = item:getId()
    local tid = ItemType(it_id):getTransformEquipId()
    if tid > 0 then
        item:transform(tid)
        local vx = item:getAttribute(ITEM_ATTRIBUTE_DURATION)
        item:transform(it_id)
        item:removeAttribute(ITEM_ATTRIBUTE_DURATION)
        return vx
    end
    return 0
end

function loot_attrToVal(item, attr)
    local id = ItemType(item:getId())
    local v = {
        [ITEM_ATTRIBUTE_ATTACK] = id:getAttack(),
        [ITEM_ATTRIBUTE_DEFENSE] = id:getDefense(),
        [ITEM_ATTRIBUTE_EXTRADEFENSE] = id:getExtraDefense(),
        [ITEM_ATTRIBUTE_ARMOR] = id:getArmor(),
        [ITEM_ATTRIBUTE_HITCHANCE] = id:getHitChance(),
        [ITEM_ATTRIBUTE_SHOOTRANGE] = id:getShootRange(),
        [ITEM_ATTRIBUTE_CHARGES] = id:getCharges(),
        [ITEM_ATTRIBUTE_DURATION] = stat_getItemDuration(item),

        -- not available in 1.1
        -- [ITEM_ATTRIBUTE_ATTACKSPEED] = item:getAttackSpeed(),
        -- [ITEM_ATTRIBUTE_EXTRAATTACK] = item:getExtraAttack(),
    }
    return v[attr]
end

function assign_loot_Stat(c)
    local rares = 0
    local h = c:getItemHoldingCount()
    if h > 0 then
        for i = 1, h do
            local available_stats = {}
            local it_u = c:getItem(i - 1)
            local it_id = ItemType(it_u:getId())
            if it_u:isContainer() then
                local crares = assign_loot_Stat(it_u)
                rares = rares + crares
            else
                if not it_id:isStackable() then
                    local wp = it_id:getWeaponType()
                    if wp > 0 then
                        if wp == WEAPON_SHIELD then -- type shield
                            table.insert(available_stats, stats[2])
                        elseif wp == WEAPON_DISTANCE then -- type bow
                            table.insert(available_stats, stats[1])
                            table.insert(available_stats, stats[5])
                            table.insert(available_stats, stats[6])
                            -- not available in 1.1
                            -- table.insert(available_stats, stats[9])
                        elseif wp == WEAPON_WAND then -- type wand
                            table.insert(available_stats, stats[6])
                        -- not available in 1.1
                        -- table.insert(available_stats, stats[9])
                        elseif isInArray({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE}, wp) then -- melee weapon

                            if it_id:getAttack() > 0 then
                                table.insert(available_stats, stats[1])
                            end
                           
                            if it_id:getDefense() > 0 then
                                table.insert(available_stats, stats[2])
                            end
                           
                            if it_id:getExtraDefense() ~= 0 then
                                table.insert(available_stats, stats[3])
                            end
                            -- not available in 1.1
                            -- table.insert(available_stats, stats[10])
                        end
                    else -- armors, amulets, runes and rings
                        if it_id:getArmor() > 0 then
                            table.insert(available_stats, stats[4])
                        end

                        if it_id:getCharges() > 0 then
                            table.insert(available_stats, stats[7])
                        end

                        local eq_id = it_id:getTransformEquipId()
                        if eq_id > 0 then
                            table.insert(available_stats, stats[8])
                        end
                    end
                end
            end

            if #available_stats > 0 then
                -- skips it all if it's empty
                local tier = math.random(1, #tiers)
                if #tiers[tier].chance > 0 then
                    local statsStored = 0
                    local stats_used = {}
                    for stat = 1, #tiers[tier].chance do
                        if #available_stats > 0 then
                            -- stops if no more stats available
                            if stat - 1 == statsStored then
                                -- checks when it's time to stop adding stats
                                if math.random(1, 100000) <= tiers[tier].chance[stat] then
                                    statsStored = statsStored + 1

                                    local selected_stat = math.random(1, #available_stats)
                                    table.insert(stats_used, available_stats[selected_stat])
                                    table.remove(available_stats, selected_stat)
                                end
                            end
                        end
                    end

                    if #stats_used > 0 then
                        rares = rares + 1
                        local stat_desc = {}
                        for stat = 1, #stats_used do
                            local v = math.random(
                                stats_used[stat][2].percent[1],
                                stats_used[stat][2].percent[2]
                            ) + math.random(
                                tiers[tier].extra[1],
                                tiers[tier].extra[2]
                            )
                            local basestat = loot_attrToVal(it_u, stats_used[stat][1])
                            it_u:setAttribute(stats_used[stat][1], basestat + math.abs(basestat * v / 100))
                            table.insert(stat_desc, '[' .. stats_used[stat][2].name .. ': +' .. v .. '%]')
                        end

                        if tiers[tier].showattr then
                            for stat = 1, #stats_used do
                                it_u:setAttribute(ITEM_ATTRIBUTE_NAME, "[" .. stats_used[stat][2].prefix .. "]" .. it_u:getAttribute(ITEM_ATTRIBUTE_NAME))
                            end
                            it_u:setAttribute(ITEM_ATTRIBUTE_NAME, it_u:getAttribute(ITEM_ATTRIBUTE_NAME) .. " " .. it_id:getName())
                        else
                            it_u:setAttribute(ITEM_ATTRIBUTE_NAME, tiers[tier].prefix .. " " .. it_id:getName())
                        end

                        it_u:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, table.concat(stat_desc, "\n"))
                    end
                end
            end
        end
    end
    return rares
end

function find_loot_Container(pos)
    local rares = 0
    local c = Tile(pos):getTopDownItem()
    if c ~= nil then
        if c:isContainer() then
            rares = rares + assign_loot_Stat(c)
            if rares > 0 then
                if rare_popup then
                    local spectators = Game.getSpectators(pos, false, true, 7, 7, 5, 5)
                    for i = 1, #spectators do
                        spectators[i]:say(rare_text, TALKTYPE_MONSTER_SAY, false, spectators[i], pos)
                    end
                end

                if rare_effect then
                    pos:sendMagicEffect(rare_effect_id)
                end
            end
            return true
        end
    end
end

function onKill(player, target, lastHit)
    if (not isSummon(target)) then
        addEvent(find_loot_Container, 2, target:getPosition())
    end
    return true
end

function onLogin(player)
    player:registerEvent("randomstats_loot")
    return true
end
View attachment 81168
I don't know if the error is in the scripth, or I don't know why you don't take it... The script works, it has a mistake just in giving me a specific stats, but I think it fulfills its function well, I don't know what I'm doing wrong
Ok, I will put it to the test tomorrow and tell you the solution.
 
i found the problem, i didnt found any way to obtain itemname on OTC, it must be send via opcode from server to client, i noticed when i saw this:

1712258035047.png
im thinking a way to make it work, any ideas? was wondering if an onThink() function sent every second updating the online players items when they open a container (maybe triggered by an action on the containers to avoid lag or crash), it send the container info to the client. When you call setFrames() it must detect the "rare", "epic", "legendary" names and set the frame, i guess its the only way...
LUA:
local function setFrames()
  for _, container in pairs(g_game.getContainers()) do
    print("Container ID: " .. container:getId()) -- veryfing containers
    local window = container.itemsPanel
    for i, child in pairs(window:getChildren()) do
      print("Child ID: " .. child:getId()) -- the only thing i could do is to get the item position on container
          local id = child:getItemId()
          local price = 0
          local name = child:getTooltip() -- this is nil, OTC cant get itemnames from server
          print("name: " .. name)
          -- local name = child:getTooltip('rowItemName'):getText()
          child:setImageSource("/images/ui/item.png")
          if (name) then
          print("name: " .. name)
            if (string.find(name, "legendary")) then
              child:setImageSource('/images/ui/rarity_gold.png')
            elseif (string.find(name, "epic")) then
              child:setImageSource('/images/ui/rarity_purple.png')
            elseif (string.find(name, "rare")) then
              child:setImageSource('/images/ui/rarity_blue.png')
            end
          end
      end
  end
end
 
Last edited:
Of course it is possible if you use OTCv8 for example in the bot module it has a section in the analyzer where it places the rarity frame for the items based on their name and price, and if you experiment with the function and make your own module you can see It is not very difficult to achieve what you want.




With patience you could achieve things like the ones I achieved on my server. And that also exists in many others.
View attachment 78090

View attachment 78089
how do tooltip with image??
1712270832265.png
 
i found the problem, i didnt found any way to obtain itemname on OTC, it must be send via opcode from server to client, i noticed when i saw this:

View attachment 83480
im thinking a way to make it work, any ideas? was wondering if an onThink() function sent every second updating the online players items when they open a container (maybe triggered by an action on the containers to avoid lag or crash), it send the container info to the client. When you call setFrames() it must detect the "rare", "epic", "legendary" names and set the frame, i guess its the only way...
LUA:
local function setFrames()
  for _, container in pairs(g_game.getContainers()) do
    print("Container ID: " .. container:getId()) -- veryfing containers
    local window = container.itemsPanel
    for i, child in pairs(window:getChildren()) do
      print("Child ID: " .. child:getId()) -- the only thing i could do is to get the item position on container
          local id = child:getItemId()
          local price = 0
          local name = child:getTooltip() -- this is nil, OTC cant get itemnames from server
          print("name: " .. name)
          -- local name = child:getTooltip('rowItemName'):getText()
          child:setImageSource("/images/ui/item.png")
          if (name) then
          print("name: " .. name)
            if (string.find(name, "legendary")) then
              child:setImageSource('/images/ui/rarity_gold.png')
            elseif (string.find(name, "epic")) then
              child:setImageSource('/images/ui/rarity_purple.png')
            elseif (string.find(name, "rare")) then
              child:setImageSource('/images/ui/rarity_blue.png')
            end
          end
      end
  end
end
Nvm, misunderstood
 
I would like to clear some doubts. I noticed that in Sarah's post, she mentioned something interesting about that color item that was inside the backpack, indicated by a blue frame, the "Demon Helmet". I'm not sure if this only applies to backpacks or if it's possible for item slots as well. Is it possible to add colors to these items?


For example, if I want to create a forge system, whether in a modal window or not, where the common "Demon Helmet" has no color, but when refining to +1 Tier it turns gray, +2 Tier blue , +3 Tier with red color and +4 Tier with yellow color, indicating that it has become legendary...

Is it possible to implement these features? I'm using TFS 1.4.2 and I've already made some updates through the commits that Evil Punker posted. Can I find these functions? I just want to clarify this. Thanks!

Hey! Wondering if you ever got anywhere with this? I'm barely starting to work on modules for OTC myself so I'm still lacking in that area so any help would be appreciated.
 
Back
Top