• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

Lua NPCs take from EQ Slots when selling items (rev. 3884/0.4)

Extrodus

|| Blazera.net ||
Joined
Dec 22, 2008
Messages
2,691
Solutions
7
Reaction score
549
Location
Canada
Hey guys, just woke up and Im a bit busy; although I do plan on looking into it later on today I figured its good to ask and see if anyone else has an understanding for the problem.

Basically, on 0.4 (rev.3884) the npcs will take your equipment went selling loot.
For example, you have 2 DSM in your backpack, and one in the armor slot.
When you open the trade window, it shows it will only allow you to sell 2. But it takes your equiped dsm and leaves you one in your backpack.

How exactly would I make it so NPCs will only collect items from the players container?

npc/lib/npc.lua
http://pastebin.com/GBfBari2

npc/lib/npcsystem/modules.lua
http://pastebin.com/nrrQ2aLu

@MatheusMkalo -- Do you have any ideas which part of the code deals with it?

To the top! I think it has something to do with line 275 in npc.lua
 
Last edited by a moderator:
line 275 in npc.lua does remove the items yes, either you can use [ ignoreEquipped = false] which is an optional argument (if 0.4 has it...), or you can remove those items from the players containers instead of using doPlayerRemoveItem
 
@Zothion - it has a custom function inbackpacks; but the removeitem always takes it from the eq slots. I almost think this might need a source edit

Does anyone else have any ideas? @Printer

There is an add item to container function, but no remove item from container.

At the end of the day I suppose I could modify sources and copy paste the add item to container and change additem to removeitem; maybe that would work.. then just edit line 275 to be "if removeitemfromcontainer then" because I think its a source issue.
 
Last edited by a moderator:
Couldn't you just scan the players backpack for the item and if there is a exiting item inside remove that first?
Similar to runes in backpack conjuring (blank runes -> rune)..

I doubt that this affords a source edit allthrough I havent taken a look into npc.lua/luascript.lua
 
A way it could be done (not recommended) is to iterate the backpack items and remove them that way, this way you would have full control of which items are taken and which ones are not
 
@Zothion - http://pastebin.com/ng7HYbwb

@Danger II @Milice - I tried using the "inBackpacks" tag in the doPlayerRemoveItem line but that brings back an error of ~
[Error - NpcScript Interface]
[5:33:54.515] (Unknown script file)
[5:33:54.515] Description:
[5:33:54.515] (luaDoPlayerRemoveItem) Player not found

So are you saying we should create a table to store the items, then remove them? I almost feel, even if we did this - it would still pull the EQ slot first since my theory is it has something to do with sources "doPlayerRemoveItem" checks the slots first before backpack.

Remember, the rev is 3884/3777 - either one would be suitable to look at for examples since both contain the issue Im dealing with. If needed, I can provide any files needed.

Thanks for the help guys! <3

Note: Did some searching and found this thread where people go over the same issue, the person states that doremoveitem always checks eq slots first - thats just how it works. So now the question is, how can we reverse that order?
Link: https://otland.net/threads/tfs-0-4-npc.227859/
 
Last edited:
@Zothion - http://pastebin.com/ng7HYbwb

@Danger II @Milice - I tried using the "inBackpacks" tag in the doPlayerRemoveItem line but that brings back an error of ~
[Error - NpcScript Interface]
[5:33:54.515] (Unknown script file)
[5:33:54.515] Description:
[5:33:54.515] (luaDoPlayerRemoveItem) Player not found

So are you saying we should create a table to store the items, then remove them? I almost feel, even if we did this - it would still pull the EQ slot first since my theory is it has something to do with sources "doPlayerRemoveItem" checks the slots first before backpack.

Remember, the rev is 3884/3777 - either one would be suitable to look at for examples since both contain the issue Im dealing with. If needed, I can provide any files needed.

Thanks for the help guys! <3

Note: Did some searching and found this thread where people go over the same issue, the person states that doremoveitem always checks eq slots first - thats just how it works. So now the question is, how can we reverse that order?
Link: https://otland.net/threads/tfs-0-4-npc.227859/

Now, i've never had a 0.4 server myself but i downloaded the sources just now and from a quick overview, what you could try is:


luascript.cpp Line 3238, change
Code:
int32_t LuaInterface::luaDoPlayerRemoveItem(lua_State* L)
{
   //doPlayerRemoveItem(cid, itemid, count[, subType = -1])
   int32_t subType = -1;
   if(lua_gettop(L) > 3)
       subType = popNumber(L);

   uint32_t count = popNumber(L);
   uint16_t itemId = (uint16_t)popNumber(L);

   ScriptEnviroment* env = getEnv();
   if(Player* player = env->getPlayerByUID(popNumber(L)))
       lua_pushboolean(L, g_game.removeItemOfType(player, itemId, count, subType));
   else
   {
       errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
       lua_pushboolean(L, false);
   }

   return 1;
}

to
Code:
int32_t LuaInterface::luaDoPlayerRemoveItem(lua_State* L)
{
   //doPlayerRemoveItem(cid, itemid, count[, subType = -1])
   int32_t subType = -1;
   if(lua_gettop(L) > 3)
       subType = popNumber(L);

   uint32_t count = popNumber(L);
   uint16_t itemId = (uint16_t)popNumber(L);

   ScriptEnviroment* env = getEnv();
   if(Player* player = env->getPlayerByUID(popNumber(L))) {
       if(Item* playerBackpackItem = player->getInventoryItem(SLOT_BACKPACK)) {
           if(Container* playerBackpack = playerBackpackItem->getContainer()) {
               lua_pushboolean(L, g_game.removeItemOfType(playerBackpack, itemId, count, subType));
           } else {
               errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
               lua_pushboolean(L, false);
           }
       } else {
           errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
           lua_pushboolean(L, false);
       }
   } else {
       errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
       lua_pushboolean(L, false);
   }

   return 1;
}


Note, that if this works it will only remove items from a players backpack and not from the inventory at all, so my recommendation would be in this case to put this as a new lua function, perhaps doPlayerRemoveBackpackItem?

Best of luck!



- A side note:
If you iterate the items you would use doRemoveItem(item.uid, 1) which would remove that specific item and have no regard to where it is. I believe this is the way to go if you wouldn't wanna sourceedit.

Something along the lines of this:
Code:
local backpackItems = getContainerItems(getPlayerSlotItem(CONST_SLOT_BACKPACK).uid)
for i = 1, #backpackItems do
   if(backpackItems[i].itemid == ID_YOU_WANT_TO_REMOVE) then
       doRemoveItem(backpackItems[i].uid)
       break
   end
end



I have not actually tested any of this, these are all theoretical.
 
Last edited:
you can use something like this to go through all the players bps and find the uids of items with a specific id in the bp (and all sub bps), and it will stop running after the desired amount is found (and you just have to remove all items in the list it returns after)
(havent done any coding for tfs in quite a while and not tested so prob needs some changes to make it work)
Code:
function scanBp(uid, id, count, n)
    local items = {}
    for i=0,getContainerSize(uid) do
        if n == count then
            break
        end
        local item = getContainerItem(uid, i)
        if isContainer(item) then
            local tmp = scanBp(item, id, count, n)
            for i=1,#tmp do
                items[#items+1] = tmp[i]
                n = n+1
            end
        else if item.id == id then
                items[#items+1] = item.uid
                n = n+1
        end
    end
    return items
end

and use it like this with appropriate 0.4 functions
Code:
scanBp(getPlayerSlotItem(CONST_SLOT_BACKPACK), sell id, amount to sell, 0)

or if you want to be lazy and use a simpler function you can use this to return all the uids of desired id the player owns, so you have to use the sellcount check after (but worse for perf)
Code:
function scanBp(uid, id)
    local items = {}
    for i=0,getContainerSize(uid) do
        local item = getContainerItem(uid, i)
        if isContainer(item) then
            local tmp = scanBp(item, id)
            for i=1,#tmp do
                items[#items+1] = tmp[i]
            end
        else if item.id == id then
            items[#items+1] = item.uid
        end
    end
    return items
end

another lazy way is to remove n+1 of the id, and add back one to the player on the inventory slot
 
Last edited:
@Milice - Thank you so much, that patch worked perfectly! My player's will never lose their upgraded gear from their EQ slots anymore!

@Zothion - That would work as well, I ended up compiling his patch before testing but awesome work guys; I can't thank you enough!

Issue Resolved!
--------------------
New Update:

New issue, if the item is inside another backpack within your main backpack - it returns "you dont have the item" - so like when we create a loot backpack within the main backpack it doesnt work.

For example, one player has 30 warrior helmets and now he has to move all of them to his main bp/make that his main backpack while selling.
 
Last edited:
his code now tries to remove the specific items from the container id instead of the player, something in the internal remove function probably doesnt check sub bps if it gets a container id
 
his code now tries to remove the specific items from the container id instead of the player, something in the internal remove function probably doesnt check sub bps if it gets a container id
removeItemOfType searches sub bps
Code:
std::list<Container*> listContainer;
Code:
while(listContainer.size() > 0 && count > 0)
    {
        Container* container = listContainer.front();
        listContainer.pop_front();
        for(int32_t i = 0; i < (int32_t)container->size() && count > 0;)
        {
            Item* item = container->getItem(i);
            if(item->getID() == itemId)
            {
                if(item->isStackable())
                {
                    if(item->getItemCount() > count)
                    {
                        internalRemoveItem(NULL, item, count);
                        count = 0;
                    }
                    else
                    {
                        count-= item->getItemCount();
                        internalRemoveItem(NULL, item);
                    }
                }
                else if(subType == -1 || subType == item->getSubType())
                {
                    --count;
                    internalRemoveItem(NULL, item);
                }
                else
                    ++i;
            }
            else
            {
                ++i;
                if((tmpContainer = item->getContainer()))
                    listContainer.push_back(tmpContainer);
            }
        }
    }
 
@Xeraphus - you think we could add that to the doplayerremoveitem function for it to check all backpacks?

Edit: just checked and he is using "removeItemOfType(playerBackpack, itemId, count, subType)" in his source edit.. shouldnt that work?
 
@Xeraphus - you think we could add that to the doplayerremoveitem function for it to check all backpacks?

Edit: just checked and he is using "removeItemOfType(playerBackpack, itemId, count, subType)" in his source edit.. shouldnt that work?
It should work, i'll compile and setup a test server and see what i can do about this in a bit if you don't figgure it out.
 
@Milice - Thanks a million, I will try to find the removeItemofType in source to replace that with Xeraphus code - but if you could figure it out as well, that would be awesome!

@Xeraphus - Which file is that in so I can replace it and try?
 

Similar threads

Back
Top