Solved NPCs buy from EQ Slots bug. (clost it)

oshrigames

Intermediate OT User
Joined
Nov 9, 2012
Messages
103
Reaction score
14
Location
israel
i've seen many people with this issue, sadly none of the existing threads have a fix for it. (as far as i know.)

the issue:
NPCs buy item from EQ Slots, example i have royal helmet on me and one in my backpack, the NPC will buy the one im wearing and leave the other helmet in my backpack.

and since my server has upgraded items.
people losing their rare gear from this bug.

Notes: the Trade option Sell Equipped / Ignore Equipped don't fix this issue.

the fix:
i want the Npc to Ignore player Eq alots and buy or sell only from backpacks/bags (containers).

im useing:
cryingdamson 0.3.6 (8.60) V8.2

Lua:
-- Include the Advanced NPC System
dofile(getDataDir() .. 'npc/lib/npcsystem/npcsystem.lua')

function selfIdle()
    following = false
    attacking = false

    selfAttackCreature(0)
    target = 0
end

function selfSayChannel(cid, message)
    return selfSay(message, cid, false)
end

function selfMoveToCreature(id)
    if(not id or id == 0) then
        return
    end

    local t = getCreaturePosition(id)
    if(not t.x or t.x == nil) then
        return
    end

    selfMoveTo(t.x, t.y, t.z)
    return
end

function getNpcDistanceToCreature(id)
    if(not id or id == 0) then
        selfIdle()
        return nil
    end

    local c = getCreaturePosition(id)
    if(not c.x or c.x == 0) then
        return nil
    end

    local s = getCreaturePosition(getNpcId())
    if(not s.x or s.x == 0 or s.z ~= c.z) then
        return nil
    end

    return math.max(math.abs(s.x - c.x), math.abs(s.y - c.y))
end

function doMessageCheck(message, keyword)
    if(type(keyword) == "table") then
        return table.isStrIn(keyword, message)
    end

    local a, b = message:lower():find(keyword:lower())
    if(a ~= nil and b ~= nil) then
        return true
    end

    return false
end

function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
    local amount = amount or 1
    local subType = subType or 1
    local ignoreCap = ignoreCap and true or false

    local item = 0
    if(isItemStackable(itemid)) then
        item = doCreateItemEx(itemid, amount)
        if(doPlayerAddItemEx(cid, item, ignoreCap) ~= RETURNVALUE_NOERROR) then
            return 0, 0
        end

        return amount, 0
    end

    local a = 0
    if(inBackpacks) then
        local container = doCreateItemEx(backpack, 1)
        local b = 1
        for i = 1, amount do
            item = doAddContainerItem(container, itemid, subType)
            if(itemid == ITEM_PARCEL) then
                doAddContainerItem(item, ITEM_LABEL)
            end

            if(isInArray({(getContainerCapById(backpack) * b), amount}, i)) then
                if(doPlayerAddItemEx(cid, container, ignoreCap) ~= RETURNVALUE_NOERROR) then
                    b = b - 1
                    break
                end

                a = i
                if(amount > i) then
                    container = doCreateItemEx(backpack, 1)
                    b = b + 1
                end
            end
        end

        return a, b
    end

    for i = 1, amount do
        item = doCreateItemEx(itemid, subType)
        if(itemid == ITEM_PARCEL) then
            doAddContainerItem(item, ITEM_LABEL)
        end

        if(doPlayerAddItemEx(cid, item, ignoreCap) ~= RETURNVALUE_NOERROR) then
            break
        end

        a = i
    end

    return a, 0
end

function doRemoveItemIdFromPos (id, n, position)
    local thing = getThingFromPos({x = position.x, y = position.y, z = position.z, stackpos = 1})
    if(thing.itemid == id) then
        doRemoveItem(thing.uid, n)
        return true
    end

    return false
end

function getNpcName()
    return getCreatureName(getNpcId())
end

function getNpcPos()
    return getCreaturePosition(getNpcId())
end

function selfGetPosition()
    local t = getNpcPos()
    return t.x, t.y, t.z
end

msgcontains = doMessageCheck
moveToPosition = selfMoveTo
moveToCreature = selfMoveToCreature
selfMoveToPosition = selfMoveTo
selfGotoIdle = selfIdle
isPlayerPremiumCallback = isPremium
doPosRemoveItem = doRemoveItemIdFromPos
doNpcBuyItem = doPlayerRemoveItem
doNpcSetCreatureFocus = selfFocus
getNpcCid = getNpcId
getDistanceTo = getNpcDistanceTo
getDistanceToCreature = getNpcDistanceToCreature

modules.lua was way to long for the "thread creation" ill just add it as file.
Let me know if there's anything else you might need.

Thanks.
 

Attachments

Stigma

Veteran OT User
Joined
Feb 14, 2015
Messages
4,556
Reaction score
2,106
inside function ShopModule:callbackOnSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
change
if(doPlayerRemoveItem(cid, itemid, amount, subType)) then
to
if(doPlayerRemoveItem(cid, itemid, amount, subType, true)) then
that extra parameter sets ignoreEquipped to true, which in turn should only remove from everywhere else but your eq slots
 
OP
oshrigames

oshrigames

Intermediate OT User
Joined
Nov 9, 2012
Messages
103
Reaction score
14
Location
israel
inside function ShopModule:callbackOnSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
change
if(doPlayerRemoveItem(cid, itemid, amount, subType)) then
to
if(doPlayerRemoveItem(cid, itemid, amount, subType, true)) then
that extra parameter sets ignoreEquipped to true, which in turn should only remove from everywhere else but your eq slots
i will test it as soon as i get off from work..
thanks for fast reply ♥
 
OP
oshrigames

oshrigames

Intermediate OT User
Joined
Nov 9, 2012
Messages
103
Reaction score
14
Location
israel
inside function ShopModule:callbackOnSell(cid, itemid, subType, amount, ignoreCap, inBackpacks)
change
if(doPlayerRemoveItem(cid, itemid, amount, subType)) then
to
if(doPlayerRemoveItem(cid, itemid, amount, subType, true)) then
that extra parameter sets ignoreEquipped to true, which in turn should only remove from everywhere else but your eq slots
sadly don't work. (can't even sell the item)
when i try to sell to the npc, i get this error:

[23/02/2018 09:27:57] [Error - Npc interface]
[23/02/2018 09:27:57] (Unknown script file)
[23/02/2018 09:27:57] Description:
[23/02/2018 09:27:57] (luaDoPlayerRemoveItem) Player not found
 
Last edited:

Stigma

Veteran OT User
Joined
Feb 14, 2015
Messages
4,556
Reaction score
2,106
are you sure you were able to sell the item before? that extra param doesn't cause that error, it's cid not being found
 
OP
oshrigames

oshrigames

Intermediate OT User
Joined
Nov 9, 2012
Messages
103
Reaction score
14
Location
israel
i'm 100% sure.
my server open for few weeks, i never had issue to sell items.
well, other then this Eq slot sell bug, all of my npc work just fine.

npc 1.0.png

npc 1.1.png
 
Last edited:
OP
oshrigames

oshrigames

Intermediate OT User
Joined
Nov 9, 2012
Messages
103
Reaction score
14
Location
israel
any chance this error "Player not found" cid thing
because i use sqlite database? or is it unrelated?
 
OP
oshrigames

oshrigames

Intermediate OT User
Joined
Nov 9, 2012
Messages
103
Reaction score
14
Location
israel
kinda desperate, is there other way to fix Eq slot sell bug?
 
OP
oshrigames

oshrigames

Intermediate OT User
Joined
Nov 9, 2012
Messages
103
Reaction score
14
Location
israel
not really sloved, i just give up on this 0.3.6 and moved to tfs 1.1
 

Mummrik

Hey!
Joined
Oct 22, 2007
Messages
674
Reaction score
102
Location
Sweden
i've seen many people with this issue, sadly none of the existing threads have a fix for it. (as far as i know.)

the issue:
NPCs buy item from EQ Slots, example i have royal helmet on me and one in my backpack, the NPC will buy the one im wearing and leave the other helmet in my backpack.

and since my server has upgraded items.
people losing their rare gear from this bug.

Notes: the Trade option Sell Equipped / Ignore Equipped don't fix this issue.

the fix:
i want the Npc to Ignore player Eq alots and buy or sell only from backpacks/bags (containers).

im useing:
cryingdamson 0.3.6 (8.60) V8.2

Lua:
-- Include the Advanced NPC System
dofile(getDataDir() .. 'npc/lib/npcsystem/npcsystem.lua')

function selfIdle()
    following = false
    attacking = false

    selfAttackCreature(0)
    target = 0
end

function selfSayChannel(cid, message)
    return selfSay(message, cid, false)
end

function selfMoveToCreature(id)
    if(not id or id == 0) then
        return
    end

    local t = getCreaturePosition(id)
    if(not t.x or t.x == nil) then
        return
    end

    selfMoveTo(t.x, t.y, t.z)
    return
end

function getNpcDistanceToCreature(id)
    if(not id or id == 0) then
        selfIdle()
        return nil
    end

    local c = getCreaturePosition(id)
    if(not c.x or c.x == 0) then
        return nil
    end

    local s = getCreaturePosition(getNpcId())
    if(not s.x or s.x == 0 or s.z ~= c.z) then
        return nil
    end

    return math.max(math.abs(s.x - c.x), math.abs(s.y - c.y))
end

function doMessageCheck(message, keyword)
    if(type(keyword) == "table") then
        return table.isStrIn(keyword, message)
    end

    local a, b = message:lower():find(keyword:lower())
    if(a ~= nil and b ~= nil) then
        return true
    end

    return false
end

function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
    local amount = amount or 1
    local subType = subType or 1
    local ignoreCap = ignoreCap and true or false

    local item = 0
    if(isItemStackable(itemid)) then
        item = doCreateItemEx(itemid, amount)
        if(doPlayerAddItemEx(cid, item, ignoreCap) ~= RETURNVALUE_NOERROR) then
            return 0, 0
        end

        return amount, 0
    end

    local a = 0
    if(inBackpacks) then
        local container = doCreateItemEx(backpack, 1)
        local b = 1
        for i = 1, amount do
            item = doAddContainerItem(container, itemid, subType)
            if(itemid == ITEM_PARCEL) then
                doAddContainerItem(item, ITEM_LABEL)
            end

            if(isInArray({(getContainerCapById(backpack) * b), amount}, i)) then
                if(doPlayerAddItemEx(cid, container, ignoreCap) ~= RETURNVALUE_NOERROR) then
                    b = b - 1
                    break
                end

                a = i
                if(amount > i) then
                    container = doCreateItemEx(backpack, 1)
                    b = b + 1
                end
            end
        end

        return a, b
    end

    for i = 1, amount do
        item = doCreateItemEx(itemid, subType)
        if(itemid == ITEM_PARCEL) then
            doAddContainerItem(item, ITEM_LABEL)
        end

        if(doPlayerAddItemEx(cid, item, ignoreCap) ~= RETURNVALUE_NOERROR) then
            break
        end

        a = i
    end

    return a, 0
end

function doRemoveItemIdFromPos (id, n, position)
    local thing = getThingFromPos({x = position.x, y = position.y, z = position.z, stackpos = 1})
    if(thing.itemid == id) then
        doRemoveItem(thing.uid, n)
        return true
    end

    return false
end

function getNpcName()
    return getCreatureName(getNpcId())
end

function getNpcPos()
    return getCreaturePosition(getNpcId())
end

function selfGetPosition()
    local t = getNpcPos()
    return t.x, t.y, t.z
end

msgcontains = doMessageCheck
moveToPosition = selfMoveTo
moveToCreature = selfMoveToCreature
selfMoveToPosition = selfMoveTo
selfGotoIdle = selfIdle
isPlayerPremiumCallback = isPremium
doPosRemoveItem = doRemoveItemIdFromPos
doNpcBuyItem = doPlayerRemoveItem
doNpcSetCreatureFocus = selfFocus
getNpcCid = getNpcId
getDistanceTo = getNpcDistanceTo
getDistanceToCreature = getNpcDistanceToCreature

modules.lua was way to long for the "thread creation" ill just add it as file.
Let me know if there's anything else you might need.

Thanks.
If you still want to use 0.3.6 or if someone else want to update doPlayerRemoveItem(cid, itemid, count[, subtype[, ignoreEquipped = false]]) to include the ignoreEquipped
You have to edit the source and recompile

luascript.cpp

change
C++:
int32_t LuaScriptInterface::luaDoPlayerRemoveItem(lua_State* L)
{
    //doPlayerRemoveItem(cid, itemid, count[, subType])
    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
C++:
int32_t LuaScriptInterface::luaDoPlayerRemoveItem(lua_State* L)
{
    //doPlayerRemoveItem(cid, itemid, count[, subtype[, ignoreEquipped = false]])
    int32_t parameters = lua_gettop(L);

    bool ignoreEquipped = false;
    if(parameters > 4)
        ignoreEquipped = popBoolean(L);

    int32_t subType = -1;
    if(parameters > 3)
        subType = popNumber(L);

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

    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID(cid);
    if(player)
    {
        lua_pushboolean(L, g_game.removeItemOfType(player, itemId, count, subType, ignoreEquipped));
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}
game.cpp
change
C++:
bool Game::removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType /*= -1*/)
{
    if(!cylinder || ((int32_t)cylinder->__getItemTypeCount(itemId, subType) < count))
        return false;

    if(count <= 0)
        return true;

    std::list<Container*> listContainer;
    Container* tmpContainer = NULL;

    Thing* thing = NULL;
    Item* item = NULL;
    for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && count > 0;)
    {
        if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
        {
            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;
                if((tmpContainer = item->getContainer()))
                    listContainer.push_back(tmpContainer);
            }
        }
        else
            ++i;
    }

    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;
                if((tmpContainer = item->getContainer()))
                    listContainer.push_back(tmpContainer);
            }
        }
    }

    return (count == 0);
}
to
C++:
bool Game::removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType /*= -1*/, bool onlySubContainers/* = false*/)
{
    if(cylinder == NULL || ((int32_t)cylinder->__getItemTypeCount(itemId, subType) < count))
        return false;

    if(count <= 0)
        return true;

    std::list<Container*> listContainer;
    Container* tmpContainer = NULL;
    Thing* thing = NULL;
    Item* item = NULL;

    for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && count > 0;)
    {
        if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
        {
            if(!onlySubContainers && 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);
            }
        }
        else
            ++i;
    }

    while(!listContainer.empty() && 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);
            }
        }
    }
    return (count == 0);
}
game.h
change
C++:
        /**
          * Remove item(s) of a certain type
          * \param cylinder to remove the item(s) from
          * \param itemId is the item to remove
          * \param count is the amount to remove
          * \param subType is the extra type an item can have such as charges/fluidtype, default is -1
            * meaning it's not used
          * \returns true if the removal was successful
          */
        bool removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType = -1);
to
C++:
        /**
          * Remove item(s) of a certain type
          * \param cylinder to remove the item(s) from
          * \param itemId is the item to remove
          * \param count is the amount to remove
          * \param subType is the extra type an item can have such as charges/fluidtype, default is -1
            * meaning it's not used
          * \param onlySubContainers if true it will remove only items from containers in cylinder, default is false
          * \returns true if the removal was successful
          */
        bool removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType = -1, bool onlySubContainers = false);
compile source and you should be able to use doPlayerRemoveItem(cid, itemid, count[, subtype[, ignoreEquipped = false]])

To make the npc ignore equipped items when selling items
data/npc/lib/npcsystem/modules.lua
search for
Lua:
if(doPlayerRemoveItem(cid, itemid, amount, subType)) then
replace it whit
Lua:
if(doPlayerRemoveItem(cid, itemid, amount, subType, true)) then
and the npc's should ignore equipped items when selling
 
Top