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

Feature Perfect Autostacking Items 100,0% Stack All for 0.4 and 0.3.6pl1

Nubaza

LUA Scripter
Joined
Jun 5, 2011
Messages
330
Solutions
1
Reaction score
21
Location
New Zeland
Tested on TFS 0.4 and 0.3.6pl1

Retired from:
Autostacking Items - XTibia - A sua comunidade de Tibia e OTserv

Credits: Exedion
Find the functions and modify !

container.cpp
Code:
Cylinder* Container::__queryDestination(int32_t& index, const Thing* thing, Item** destItem, uint32_t&)
{
        if(index == 254 /*move up*/)
        {
                index = INDEX_WHEREEVER;
                *destItem = NULL;
 
                Container* parentContainer = dynamic_cast<Container*>(getParent());
                if(parentContainer)
                        return parentContainer;
 
                return this;
        }
        else if(index == 255 /*add wherever*/){
                index = INDEX_WHEREEVER;
                *destItem = NULL;
        }
        else if(index >= (int32_t)capacity()){
                        /*
                        if you have a container, maximize it to show all 20 slots
                        then you open a bag that is inside the container you will have a bag with 8 slots
                        and a "grey" area where the other 12 slots where from the container
                        if you drop the item on that grey area
                        the client calculates the slot position as if the bag has 20 slots
                        */
                        index = INDEX_WHEREEVER;
                *destItem = NULL;
        }
 
        const Item* item = thing->getItem();
        if(item == NULL){
                return this;
        }
 
        if(item->isStackable()){
                if(item->getParent() != this){
                        //try find a suitable item to stack with
                        uint32_t n = 0;
                        for(ItemList::iterator cit = itemlist.begin(); cit != itemlist.end(); ++cit){
                                if((*cit) != item && (*cit)->getID() == item->getID() && (*cit)->getItemCount() < 100){
                                        *destItem = (*cit);
                                        index = n;
                                        return this;
                                }
 
                                ++n;
                        }
                }
        }
 
        if(index != INDEX_WHEREEVER){
                Thing* destThing = __getThing(index);
                if(destThing)
                        *destItem = destThing->getItem();
 
                Cylinder* subCylinder = dynamic_cast<Cylinder*>(*destItem);
 
                if(subCylinder){
                        index = INDEX_WHEREEVER;
                        *destItem = NULL;
                        return subCylinder;
                }
        }
 
        return this;
}

item.cpp
Code:
void Item::setDefaultSubtype()
{
        setItemCount(1);
        const ItemType& it = items[id];
        if(it.charges)
                setCharges(it.charges);
}

player.cpp
Code:
Cylinder* Player::__queryDestination(int32_t& index, const Thing* thing, Item** destItem,
        uint32_t& flags)
{
        if(index == 0 /*drop to capacity window*/ || index == INDEX_WHEREEVER){
                *destItem = NULL;
 
                const Item* item = thing->getItem();
                if(item == NULL){
                        return this;
                }
 
                //find an appropiate slot
                std::list<Container*> containerList;
                for(int i = SLOT_FIRST; i < SLOT_LAST; ++i){
                        Item* inventoryItem = inventory[i];
 
                        if(inventoryItem == tradeItem){
                                continue;
                        }
 
                        if(inventoryItem == tradeItem){
                                continue;
                        }
 
                                if(inventoryItem){
                                        //try find an already existing item to stack with
                                if(inventoryItem != item && item->isStackable() && inventoryItem->getID() == item->getID() && inventoryItem->getItemCount() < 100){
                                        *destItem = inventoryItem;
                                        index = i;
                                        return this;
                                }
                                //check sub-containers
                                else if(Container* subContainer = inventoryItem->getContainer()){
                                        Cylinder* tmpCylinder = NULL;
                                        int32_t tmpIndex = INDEX_WHEREEVER;
                                        Item* tmpDestItem = NULL;
 
                                        tmpCylinder = subContainer->__queryDestination(tmpIndex, item, &tmpDestItem, flags);
                                        if(tmpCylinder && tmpCylinder->__queryAdd(tmpIndex, item, item->getItemCount(), flags) == RET_NOERROR){
                                                index = tmpIndex;
                                                *destItem = tmpDestItem;
                                                return tmpCylinder;
                                        }
 
                                        containerList.push_back(subContainer);
                                }
                        }
                        //empty slot
                        else if(__queryAdd(i, item, item->getItemCount(), flags) == RET_NOERROR){
                                index = i;
                                *destItem = NULL;
                                return this;
                        }
                }
 
                //check deeper in the containers
                for(std::list<Container*>::iterator it = containerList.begin(); it != containerList.end(); ++it){
                        for(ContainerIterator iit = (*it)->begin(); iit != (*it)->end(); ++iit){
                                if(Container* subContainer = (*iit)->getContainer()){
 
                                        if(subContainer == tradeItem){
                                                continue;
                                        }
 
                                        Cylinder* tmpCylinder = NULL;
                                        int32_t tmpIndex = INDEX_WHEREEVER;
                                        Item* tmpDestItem = NULL;
 
                                        tmpCylinder = subContainer->__queryDestination(tmpIndex, item, &tmpDestItem, flags);
                                        if(tmpCylinder && tmpCylinder->__queryAdd(tmpIndex, item, item->getItemCount(), flags) == RET_NOERROR){
                                                index = tmpIndex;
                                                *destItem = tmpDestItem;
                                                return tmpCylinder;
                                        }
                                }
                        }
                }
                return this;
        }
 
        Thing* destThing = __getThing(index);
        if(destThing)
                *destItem = destThing->getItem();
 
        Cylinder* subCylinder = dynamic_cast<Cylinder*>(destThing);
 
        if(subCylinder){
                index = INDEX_WHEREEVER;
                *destItem = NULL;
                return subCylinder;
        }
        else
                return this;
}

Posted by Nubaza (Chavoz) in otland.net
Created by Exedion in xtibia.com/forum


Maybe this code ruins your firstitems, so i need the help of the forum to edit this code :S
 
Last edited:
Using this code the items will be autostacked 100%
But.. it bug firstitems, i think that we need update the firstitems (The firstitems go to the ground X:x)

Any ideas?
 
MartyX, Maraths, any of you know add extra code?

- - - Updated - - -

If you know help xd
 
you're true, for that reason.. i need the help of the forum to solve this problem D:
 
luascript.cpp
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItem(lua_State* L)

replace all function to:
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItem(lua_State* L)
{
	//doPlayerAddItem(cid, itemid[, count/subtype = 1[, canDropOnMap = true[, slot = 0]]])
	//doPlayerAddItem(cid, itemid[, count = 1[, canDropOnMap = true[, subtype = 1[, slot = 0]]]])
	int32_t params = lua_gettop(L), subType = 1, slot = SLOT_WHEREEVER;
	if(params > 5)
		slot = popNumber(L);

	if(params > 4)
	{
		if(params > 5)
			subType = popNumber(L);
		else
			slot = popNumber(L);
	}

	bool canDropOnMap = true;
	if(params > 3)
		canDropOnMap = popNumber(L);

	uint32_t count = 1;
	if(params > 2)
		count = popNumber(L);

	uint32_t itemId = popNumber(L);
	if(slot > SLOT_AMMO)
	{
		errorEx("Invalid slot.");
		lua_pushboolean(L, false);
		return 1;
	}

	ScriptEnviroment* env = getEnv();
	Player* player = env->getPlayerByUID((uint32_t)popNumber(L));
	if(!player)
	{
		errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
		lua_pushboolean(L, false);
		return 1;
	}

	const ItemType& it = Item::items[itemId];
	int32_t itemCount = 1;
	if(params > 4)
		itemCount = std::max((uint32_t)1, count);
	else if(it.hasSubType())
	{
		if(it.stackable)
			itemCount = (int32_t)std::ceil((float)count / 100);

		subType = count;
	}

	while(itemCount > 0)
	{
		int32_t stackCount = std::min(100, subType);
		Item* newItem = Item::CreateItem(itemId, stackCount);
		if(!newItem)
		{
			errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
			lua_pushboolean(L, false);
			return 1;
		}

		if(it.stackable)
			subType -= stackCount;

		ReturnValue ret = g_game.internalPlayerAddItem(NULL, player, newItem, canDropOnMap, (slots_t)slot);
		if(ret != RET_NOERROR)
		{
			delete newItem;
			lua_pushboolean(L, false);
			return 1;
		}

		--itemCount;
		if(itemCount)
			continue;

		if(newItem->getParent())
			lua_pushnumber(L, env->addThing(newItem));
		else //stackable item stacked with existing object, newItem will be released
			lua_pushnil(L);

		return 1;
	}

	lua_pushnil(L);
	return 1;
}

in
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItemEx(lua_State* L)

replace all func..
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItemEx(lua_State* L)
{
	//doPlayerAddItemEx(cid, uid[, canDropOnMap = false[, slot = 0]])
	int32_t params = lua_gettop(L), slot = SLOT_WHEREEVER;
	if(params > 3)
		slot = popNumber(L);

	bool canDropOnMap = false;
	if(params > 2)
		canDropOnMap = popNumber(L);

	uint32_t uid = (uint32_t)popNumber(L);
	if(slot > SLOT_AMMO)
	{
		errorEx("Invalid slot.");
		lua_pushboolean(L, false);
		return 1;
	}

	ScriptEnviroment* env = getEnv();
	Player* player = env->getPlayerByUID(popNumber(L));
	if(!player)
	{
		errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
		lua_pushboolean(L, false);
		return 1;
	}

	Item* item = env->getItemByUID(uid);
	if(!item)
	{
		errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
		lua_pushboolean(L, false);
		return 1;
	}

	if(item->getParent() == VirtualCylinder::virtualCylinder)
		lua_pushnumber(L, g_game.internalPlayerAddItem(NULL, player, item, canDropOnMap, (slots_t)slot));
	else
		lua_pushboolean(L, false);

	return 1;
}
 
luascript.cpp
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItem(lua_State* L)

replace all function to:
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItem(lua_State* L)
{
	//doPlayerAddItem(cid, itemid[, count/subtype = 1[, canDropOnMap = true[, slot = 0]]])
	//doPlayerAddItem(cid, itemid[, count = 1[, canDropOnMap = true[, subtype = 1[, slot = 0]]]])
	int32_t params = lua_gettop(L), subType = 1, slot = SLOT_WHEREEVER;
	if(params > 5)
		slot = popNumber(L);

	if(params > 4)
	{
		if(params > 5)
			subType = popNumber(L);
		else
			slot = popNumber(L);
	}

	bool canDropOnMap = true;
	if(params > 3)
		canDropOnMap = popNumber(L);

	uint32_t count = 1;
	if(params > 2)
		count = popNumber(L);

	uint32_t itemId = popNumber(L);
	if(slot > SLOT_AMMO)
	{
		errorEx("Invalid slot.");
		lua_pushboolean(L, false);
		return 1;
	}

	ScriptEnviroment* env = getEnv();
	Player* player = env->getPlayerByUID((uint32_t)popNumber(L));
	if(!player)
	{
		errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
		lua_pushboolean(L, false);
		return 1;
	}

	const ItemType& it = Item::items[itemId];
	int32_t itemCount = 1;
	if(params > 4)
		itemCount = std::max((uint32_t)1, count);
	else if(it.hasSubType())
	{
		if(it.stackable)
			itemCount = (int32_t)std::ceil((float)count / 100);

		subType = count;
	}

	while(itemCount > 0)
	{
		int32_t stackCount = std::min(100, subType);
		Item* newItem = Item::CreateItem(itemId, stackCount);
		if(!newItem)
		{
			errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
			lua_pushboolean(L, false);
			return 1;
		}

		if(it.stackable)
			subType -= stackCount;

		ReturnValue ret = g_game.internalPlayerAddItem(NULL, player, newItem, canDropOnMap, (slots_t)slot);
		if(ret != RET_NOERROR)
		{
			delete newItem;
			lua_pushboolean(L, false);
			return 1;
		}

		--itemCount;
		if(itemCount)
			continue;

		if(newItem->getParent())
			lua_pushnumber(L, env->addThing(newItem));
		else //stackable item stacked with existing object, newItem will be released
			lua_pushnil(L);

		return 1;
	}

	lua_pushnil(L);
	return 1;
}

in
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItemEx(lua_State* L)

replace all func..
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItemEx(lua_State* L)
{
	//doPlayerAddItemEx(cid, uid[, canDropOnMap = false[, slot = 0]])
	int32_t params = lua_gettop(L), slot = SLOT_WHEREEVER;
	if(params > 3)
		slot = popNumber(L);

	bool canDropOnMap = false;
	if(params > 2)
		canDropOnMap = popNumber(L);

	uint32_t uid = (uint32_t)popNumber(L);
	if(slot > SLOT_AMMO)
	{
		errorEx("Invalid slot.");
		lua_pushboolean(L, false);
		return 1;
	}

	ScriptEnviroment* env = getEnv();
	Player* player = env->getPlayerByUID(popNumber(L));
	if(!player)
	{
		errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
		lua_pushboolean(L, false);
		return 1;
	}

	Item* item = env->getItemByUID(uid);
	if(!item)
	{
		errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
		lua_pushboolean(L, false);
		return 1;
	}

	if(item->getParent() == VirtualCylinder::virtualCylinder)
		lua_pushnumber(L, g_game.internalPlayerAddItem(NULL, player, item, canDropOnMap, (slots_t)slot));
	else
		lua_pushboolean(L, false);

	return 1;
}


Fire Element i have errors with the compilation:
scaled.php


Who can solve this? :S
 
It's an bug in NPC system after add this to TFS:
PHP:
[Error - Npc interface]
(Unknown script file)
Description:
data/npc/lib/npcsystem/modules.lua:1151: bad argument #2 to 'error' (number expe
cted, got string)
stack traceback:
        [C]: in function 'error'
        data/npc/lib/npcsystem/modules.lua:1151: in function 'callbackOnBuy'
        data/npc/lib/npcsystem/npchandler.lua:263: in function 'processModuleCal
lback'
        data/npc/lib/npcsystem/npchandler.lua:440: in function 'onBuy'
        data/npc/lib/npcsystem/modules.lua:1292: in function <data/npc/lib/npcsy
stem/modules.lua:1291>

When i buy item error appear.

Selling is bugless - working.
 
i use "cryingdamson 0.3.6 (8.60) V8.2" and i dont even have any container.cpp/item.cpp/player.cpp on my server, i have an OTserv 8.60 aswell which has a src map with cpp files in it ( /src/src/container.cpp ) but how do i do on my Cryingdamson server if it aint got cpp files?
 
in that Source there is no theforgottenserver.dev which i need to compile?
 
Some Solution for It?
I solved this for TFS 0.4, the problem with luascript.cpp is simple and thank you @Fire Element.
change this
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItem(lua_State* L)
to
Code:
int32_t LuaInterface::luaDoPlayerAddItem(lua_State* L)
change this
Code:
int32_t LuaScriptInterface::luaDoPlayerAddItemEx(lua_State* L)
to
Code:
int32_t LuaInterface::luaDoPlayerAddItemEx(lua_State* L)


here code
Code:
int32_t LuaInterface::luaDoPlayerAddItem(lua_State* L)
{
    //doPlayerAddItem(cid, itemid[, count/subtype = 1[, canDropOnMap = true[, slot = 0]]])
    //doPlayerAddItem(cid, itemid[, count = 1[, canDropOnMap = true[, subtype = 1[, slot = 0]]]])
    int32_t params = lua_gettop(L), subType = 1, slot = SLOT_WHEREEVER;
    if(params > 5)
        slot = popNumber(L);
    if(params > 4)
    {
        if(params > 5)
            subType = popNumber(L);
        else
            slot = popNumber(L);
    }
    bool canDropOnMap = true;
    if(params > 3)
        canDropOnMap = popNumber(L);
    uint32_t count = 1;
    if(params > 2)
        count = popNumber(L);
    uint32_t itemId = popNumber(L);
    if(slot > SLOT_AMMO)
    {
        errorEx("Invalid slot.");
        lua_pushboolean(L, false);
        return 1;
    }
    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID((uint32_t)popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }
    const ItemType& it = Item::items[itemId];
    int32_t itemCount = 1;
    if(params > 4)
        itemCount = std::max((uint32_t)1, count);
    else if(it.hasSubType())
    {
        if(it.stackable)
            itemCount = (int32_t)std::ceil((float)count / 100);
        subType = count;
    }
    while(itemCount > 0)
    {
        int32_t stackCount = std::min(100, subType);
        Item* newItem = Item::CreateItem(itemId, stackCount);
        if(!newItem)
        {
            errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
        if(it.stackable)
            subType -= stackCount;
        ReturnValue ret = g_game.internalPlayerAddItem(NULL, player, newItem, canDropOnMap, (slots_t)slot);
        if(ret != RET_NOERROR)
        {
            delete newItem;
            lua_pushboolean(L, false);
            return 1;
        }
        --itemCount;
        if(itemCount)
            continue;
        if(newItem->getParent())
            lua_pushnumber(L, env->addThing(newItem));
        else //stackable item stacked with existing object, newItem will be released
            lua_pushnil(L);
        return 1;
    }
    lua_pushnil(L);
    return 1;
}

Code:
int32_t LuaInterface::luaDoPlayerAddItemEx(lua_State* L)
{
    //doPlayerAddItemEx(cid, uid[, canDropOnMap = false[, slot = 0]])
    int32_t params = lua_gettop(L), slot = SLOT_WHEREEVER;
    if(params > 3)
        slot = popNumber(L);
    bool canDropOnMap = false;
    if(params > 2)
        canDropOnMap = popNumber(L);
    uint32_t uid = (uint32_t)popNumber(L);
    if(slot > SLOT_AMMO)
    {
        errorEx("Invalid slot.");
        lua_pushboolean(L, false);
        return 1;
    }
    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }
    Item* item = env->getItemByUID(uid);
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }
    if(item->getParent() == VirtualCylinder::virtualCylinder)
        lua_pushnumber(L, g_game.internalPlayerAddItem(NULL, player, item, canDropOnMap, (slots_t)slot));
    else
        lua_pushboolean(L, false);
    return 1;
}
 
Back
Top