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

Pick-up all and pick-up on doubleclick

2Rec

Excellent OT User
Joined
Jul 31, 2013
Messages
550
Solutions
48
Reaction score
885
Ok, so, i started to tinker with OTC and in order to understand this freaking thing i made those 2 quick features, that i think are pretty cool and useful.
I would really appreciate an advice from some OTClient big shots and enjoy other people to test shit out of it. Feel free to post fixes or remakes if you want.
I know it's not the most efficient way to make it, but i couldn't find a better way to code it than with exOpcodes. Therefore i'm asking for help.
Don't treat it like a complete code. Anyway, features work as intended so far.

Known issues:
- clone() stops actively decaying items, like 'lit torch' from decay;
- gotta find a way to hide button if container is not a part of players inventory;

---

1.Button

data/images/ui/miniwindow_pickbuttons.png
miniwindow_pickbuttons.png


modules/game_containers/container.otui
Code:
  UIButton
    id: pickAllButton
    anchors.top: upButton.top
    anchors.right: upButton.left
    margin-right: 3
    size: 14 14
    image-source: /images/ui/miniwindow_pickbuttons
    image-clip: 0 0 14 14

    $hover:
      image-clip: 0 14 14 14

    $pressed:
      image-clip: 0 28 14 14

2. Client

modules/game_containers/containers.lua
Inside function onOpenContainer()
Lua:
  -- pick up all button
  local pickButton = containerWindow:getChildById('pickAllButton')
  pickButton.onClick = function()
    local contId = container:getId()
    local protocolGame = g_game.getProtocolGame()
    if protocolGame then
      protocolGame:sendExtendedOpcode(52, contId)
    return true
    end
  end
--

modules/game_interface/widgets/uiitem.lua
Inside UIItem:eek:nMouseRelease()
Lua:
    -- drag on double click
  self.onDoubleClick = function()
    local itPos = "{x = ".. item:getPosition().x ..", y = ".. item:getPosition().y ..", z = ".. item:getPosition().z .."}"
    local protocolGame = g_game.getProtocolGame()
    if protocolGame then
      protocolGame:sendExtendedOpcode(51, itPos)
    return true
    end
  end
  --

3. Server
data/creaturescripts/extendedopcodes.lua
Lua:
local function parseT(s)
        local t = {}
        for k, v in string.gmatch(s, "(%w+) = (%w+)") do
            t[k] = v
        end
return t
end

function searchContainer(container, items)
    items = items or {}
    for i = container:getSize()-1, 0, -1 do
        local item = container:getItem(i)
        if item:getType():isContainer() then
            searchContainer(item, items)
        else
            items[#items+1] = item
        end
    end
    return items
end

function onExtendedOpcode(player, opcode, buffer)

    if opcode == OPCODE_ITEMONDOUBLECLICK then
        local t = parseT(buffer)
        local contY = t.y
        local container = player:getContainerById(contY - 64)
        local playerBp = player:getSlotItem(CONST_SLOT_BACKPACK)
        local item = container:getItem(t.z)
        
        if not playerBp then
        return false
        end
        
        if playerBp:getEmptySlots(true) == 0 then
            player:sendCancelMessage(RETURNVALUE_NOTENOUGHROOM)
            return false
        end       
            
        if item:getTopParent():getId() == player:getId() then
            return false
        end
        
        if item:getWeight() > player:getFreeCapacity() then
            player:sendCancelMessage(RETURNVALUE_NOTENOUGHCAPACITY)
            return false
        end
        
    local clone = item:clone()
    player:addItemEx(clone)
    item:remove()
    end
    
    if opcode == OPCODE_PICKUPALL then
        local container = player:getContainerById(tonumber(buffer))
        local items = searchContainer(container)
        local playerBp = player:getSlotItem(CONST_SLOT_BACKPACK)
        local weight = 0
        if not playerBp then
        return false
        end
        
        for i = 1, #items do
            weight = weight + items[i]:getWeight()
        end

        for k, v in pairs(items) do
            if playerBp:getEmptySlots(true) == 0 then
                player:sendCancelMessage(RETURNVALUE_NOTENOUGHROOM)
                return false
            end
        
            if weight > player:getFreeCapacity() then
                player:sendCancelMessage(RETURNVALUE_NOTENOUGHCAPACITY)
                return false
            end
                
            if v:getTopParent():getId() == player:getId() then
                return false
            end
            
        local clone = v:clone()
        player:addItemEx(clone)
        v:remove()
        end
    end
            
end
-- searchContainer() is either mine or made by Stigma if i recall, didn't have this one credited in my lib, and i forgot :v

Cheers
 
Last edited:
Tks for this good contribution, btw for wich tfs distro is this?
 
I like how you start your adventure with OTC. Therefore, I help.
Add in gameinterface.lua something like:
Lua:
moveItemToBackpack = 0
In function processMouseAction add then:
Lua:
  if useThing and mouseButton == MouseLeftButton then
    if moveItemToBackpack == useThing then
        toPos = {x = 65535, y = 3, z = 0 }
        g_game.move(moveItemToBackpack, toPos, moveItemToBackpack:getCount())
        moveItemToBackpack = 0
        return true
    else
        moveItemToBackpack = useThing
        moveItemToBackpackDelay()
    end
  end
And the moveItemToBackpackDelay() function:
Lua:
function moveItemToBackpackDelay()
    scheduleEvent(function() moveItemToBackpack = 0 end, 500)
end

Keep it up.
 
I like how you start your adventure with OTC. Therefore, I help.
Add in gameinterface.lua something like:
Lua:
moveItemToBackpack = 0
In function processMouseAction add then:
Lua:
  if useThing and mouseButton == MouseLeftButton then
    if moveItemToBackpack == useThing then
        toPos = {x = 65535, y = 3, z = 0 }
        g_game.move(moveItemToBackpack, toPos, moveItemToBackpack:getCount())
        moveItemToBackpack = 0
        return true
    else
        moveItemToBackpack = useThing
        moveItemToBackpackDelay()
    end
  end
And the moveItemToBackpackDelay() function:
Lua:
function moveItemToBackpackDelay()
    scheduleEvent(function() moveItemToBackpack = 0 end, 500)
end

Keep it up.
Thanks, but in your code, you're using predefined container id(y.position) and i see couple potential problems.
Wouldn't it differ(id) in some cases?
Wouldn't it be necessary to have container open due to work?
And i'm pretty sure it's not recursive(for more containers in player's inventory).

That was a problem for me. To get all those player information in otc, so i wouldnt have to use server.

Thanks for your help, gonna tinker with it a bit later yet.
Cheers
 
Wouldn't it differ(id) in some cases?
No.
Wouldn't it be necessary to have container open due to work?
No.
And i'm pretty sure it's not recursive(for more containers in player's inventory).
I understand your point now. It only works for the main backpack, it doesn't iterate over another but I think it's possible.
All you need to do is change this line:
Lua:
toPos = {x = 65535, y = 3, z = 0 }
You would have to iterate by items in the main container, check if the item is a new container (function getContainerItem()), then you'll need to check if new container's getItemsCount() is less than new container's getSize() and if it is then toPos is main container's getSlotPosition(iterate number of next container).

#Edit:
Sorry, I just made a research and in processCloseContainer (src\client\game.cpp) there's:
C++:
m_containers[containerId] = nullptr;
so if it's not the main backpack, g_game.getContainers() is working only for opened containers right now.
 
Last edited:
Hell, im stupid. y = 3 is a backpack slot...
I guess i would have to write some function that checks for a free slots in a whole character.
Because what if player don't have a backpack, but have a free hands or is carrying free container on some other slot.
That's a lot of if's and loops.

//But then i would have to have a container open as you mentioned.

// @4drik maybe you could help me with the button issue then?
 
Last edited:
I see two options.
If we want only a button to appear if container is on the ground (like corpse), we should check if pos.x ~= 65535.
If we want to check if the container is in the character's inventory, then again the server-side function checking every character's container will be needed probably.

#Edit:
Better idea is to check if the container hasParent. If not then check the pos.x and pos.y.
If pos.y belongs to inventory (not sure values but something like 1-13), and pos.x is 65535 then do not create a button and save that if you will open next container from this container, do not create the button and again save that for next try.
 
Last edited:
Back
Top