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

Nubaza

LUA Scripter
Joined
Jun 5, 2011
Messages
322
Reaction score
17
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:
OP
Nubaza

Nubaza

LUA Scripter
Joined
Jun 5, 2011
Messages
322
Reaction score
17
Location
New Zeland
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

I'm renewing
Joined
Jun 6, 2007
Messages
1,223
Reaction score
154
Location
El Grullo
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?
Require add other extra to code :D
 

Maraths

Intermediate OT User
Joined
Jul 29, 2010
Messages
196
Reaction score
2
Yea, fix in doPlayerAddItem and doPlayerAddItemEx (luascript.cpp) :D
 
OP
Nubaza

Nubaza

LUA Scripter
Joined
Jun 5, 2011
Messages
322
Reaction score
17
Location
New Zeland
MartyX, Maraths, any of you know add extra code?

- - - Updated - - -

If you know help xd
 
OP
Nubaza

Nubaza

LUA Scripter
Joined
Jun 5, 2011
Messages
322
Reaction score
17
Location
New Zeland
you're true, for that reason.. i need the help of the forum to solve this problem D:
 

Fire Element

Member
Joined
Sep 10, 2010
Messages
194
Reaction score
22
Location
Brazil
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;
}
 
OP
Nubaza

Nubaza

LUA Scripter
Joined
Jun 5, 2011
Messages
322
Reaction score
17
Location
New Zeland
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:


Who can solve this? :S
 

Fresh

Quack!
Joined
Oct 21, 2009
Messages
1,555
Reaction score
140
Location
Lublin, Poland
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.
 

Andréew

Humble mapper.
Premium User
Joined
Apr 14, 2015
Messages
563
Reaction score
804
Location
Sweden
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?
 

Andréew

Humble mapper.
Premium User
Joined
Apr 14, 2015
Messages
563
Reaction score
804
Location
Sweden
in that Source there is no theforgottenserver.dev which i need to compile?
 

Eduardo170

Intermediate OT User
Joined
Jan 7, 2014
Messages
281
Reaction score
26
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;
}
 
Top