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

Solved Source edit - Action ID doesn't stack

fish04k

Member
Joined
Mar 23, 2008
Messages
102
Reaction score
19
Hello Otland,

I have a few ideas i'm trying to pursue on my server but hit a snag and after countless attempts i'm feeling exhausted and bummed out to say the least. Maybe there is someone out there that can lend me a helping hand!

Essentially all i'm trying to do is make a stack able item with X AID unable to be automatically stacked and RET_NOTPOSSIBLE.

https://otland.net/threads/autostacking-stackable-items-in-tfs-0-3-6pl1.162795/
I looked at the above forum post regarding source edits for "auto stacking" and started there but to no avail. Any help or tips to point me in the right direction would be greatly appreciated.
 
You can instead use something like:
Code:
function onMoveItem(cid, item, count, toContainer, fromContainer, fromPos, toPos)
local item2 = getItemFromPos(toPos)
if item.actionid == ACTION_ID and item2.actionid == ACTION_ID then
return false
end

return true
end
Its just a example, it wont work probably but will show you what I mean :)

If you do not have the function in your sources, take a look here:
https://otland.net/threads/creatureevent-onmoveitem-cid-item-count-tocontainer-fromcontainer.185781/
 
Well....a couple hours and an unhealthy amount of energy drinks later I still find myself pretty much where I started. It looks like i'll have to put this on the back burner and hopefully figure out a way to make this work in the future.

Thank you for trying to help me Danger. I appreciate the help!
 
Would mess up for stacking tho no? And would this work for moving item in containers?

local item2 = getItemFromPos(toPos)

It probably would....Just pretty exhausted. Have to take a look at it a littler later I guess.
 
Making some headway here. It seems everything is working except one thing.

If there is a duplicate item in my bag of the same ID it automatically stacks them. Is there anyway to force the item not to stack? Or possibly to force it to move to slot 0 of the backpack? Not sure if that would prevent auto stack or not.

Side note: I am using TFS 0.3 - 0.3.7-r5916-8.6

Thanks again for both the very useful information so far Danger II and MatheusMkalo!
 
i'm not sure if i got your problem...

container.cpp
Code:
 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;
                        }

you can change this line:
if((*cit) != item && (*cit)->getID() == item->getID() && (*cit)->getItemCount() < 100){

inserting something like (*cit)->getActionId() != item->getActionId()

the items will only stack if have the same actionId
 
Yeah. I actually just figured that out. Now I noticed that attributes and the Action ID do not transfer when moving an item that is stackable.

I was looking at item.cpp and a few things I noticed that could possibly be used? Thanks!

Item* Item::clone() const
void Item::copyAttributes(Item* item)
void Item::setActionId(int32_t aid, bool callEvent/* = true*/)

*Also this is for an item upgrading system i've been working on. So things like attack speed and all other attributes would need to transfer to the bag. This is the last snag in the entire system.

EDIT:
Guessing it has something to do with game.cpp's Item* Game::transformItem


Code:
Item* Game::transformItem(Item* item, uint16_t newId, int32_t newCount/* = -1*/)
{
    if(item->getID() == newId && (newCount == -1 || (newCount == item->getSubType() && newCount)))
        return item;

    Cylinder* cylinder = item->getParent();
    if(!cylinder)
        return NULL;

    int32_t itemIndex = cylinder->__getIndexOfThing(item);
    if(itemIndex == -1)
    {
#ifdef __DEBUG__
        std::clog << "Error: transformItem, itemIndex == -1" << std::endl;
#endif
        return item;
    }

    if(!item->canTransform())
        return item;

    const ItemType &curType = Item::items[item->getID()], &newType = Item::items[newId];
    if(curType.alwaysOnTop != newType.alwaysOnTop)
    {
        // This only occurs when you transform items on tiles from a downItem to a topItem (or vice versa)
        // Remove the old, and add the new
        ReturnValue ret = internalRemoveItem(NULL, item);
        if(ret != RET_NOERROR)
            return item;

        Item* newItem = NULL;
        if(newCount == -1)
            newItem = Item::CreateItem(newId);
        else
            newItem = Item::CreateItem(newId, newCount);

        if(!newItem)
            return NULL;

        newItem->copyAttributes(item);
        if(internalAddItem(NULL, cylinder, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
        {
            delete newItem;
            return NULL;
        }

        newItem->makeUnique(item);
        return newItem;
    }

    if(curType.type == newType.type)
    {
        //Both items has the same type so we can safely change id/subtype
        if(!newCount && (item->isStackable() || item->hasCharges()))
        {
            if(!item->isStackable() && (!item->getDefaultDuration() || item->getDuration() <= 0))
            {
                int16_t tmp = newId;
                if(curType.id == newId)
                    tmp = curType.decayTo;

                if(tmp != -1)
                    return transformItem(item, tmp);
            }

            internalRemoveItem(NULL, item);
            return NULL;
        }

        cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, false);
        uint16_t tmp = item->getID();
        if(curType.id != newId)
        {
            tmp = newId;
            if(newType.group != curType.group)
                item->setDefaultSubtype();

            if(curType.hasSubType() && !newType.hasSubType())
            {
                item->resetFluidType();
                item->resetCharges();
            }
        }

        int32_t count = item->getSubType();
        if(newCount != -1 && newType.hasSubType())
            count = newCount;

        cylinder->__updateThing(item, tmp, count);
        cylinder->postAddNotification(NULL, item, cylinder, itemIndex);
        return item;
    }

    //Replacing the the old item with the new while maintaining the old position
    Item* newItem = NULL;
    if(newCount == -1)
        newItem = Item::CreateItem(newId);
    else
        newItem = Item::CreateItem(newId, newCount);

    if(!newItem)
        return NULL;

    newItem->copyAttributes(item);
    newItem->makeUnique(item);
    cylinder->__replaceThing(itemIndex, newItem);

    cylinder->postAddNotification(NULL, newItem, cylinder, itemIndex);
    item->setParent(NULL);
    cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, true);

    freeThing(item);
    return newItem;
}
 
Last edited:
Yes it did! Thank you. But it appears everything works up until the point of transferring stats and action id to the item. It appears to create a brand new item with no stats on it.

(Essentially id like the item name, attack speed, attack dmg, action id and charges to all transfer over. )
 
Not sure if this is against the rules or not. But just wanted to send out an alert to let ya know I figured it out! Thank you all so much! It now works exactly as it should!!!
 
well i'm still not sure if I got your problem but please give a try:

game.cpp
http://pastebin.com/YA9uRbP2

container.cpp
Code:
 for(ItemList::iterator cit = itemlist.begin(); cit != itemlist.end(); ++cit){
                                if((*cit) != item && (*cit)->getID() == item->getID() && (*cit)->getItemCount() < 100){
                                        if((*cit)->getActionId() != item->getActionId()){
                                                        index = INDEX_WHEREEVER;
                                                        *destItem = NULL;
                                        }
                                        else {
                                        *destItem = (*cit);
                                        index = n;
                                        return this;
                                        }
                                }
                                ++n;
                        }
 
Last edited:
Not sure if this is against the rules or not. But just wanted to send out an alert to let ya know I figured it out! Thank you all so much! It now works exactly as it should!!!
If you figure it out then share the solution, its a way of paying it forward as the solution can help someone else with a similar issue.
 
Well...It was a combination of many things tbh. Was going to make a guide on how to do this entire system I'm making later. But i'll share what I did to get this working.

First add: https://otland.net/threads/creatureevent-onmoveitem-cid-item-count-tocontainer-fromcontainer.185781/

In Container.cpp

Find within : Cylinder* Container::__queryDestination
Change:
Code:
if(!((flags & FLAG_IGNOREAUTOSTACK) == FLAG_IGNOREAUTOSTACK)
        && item->isStackable() && item->getParent() != this)
To (XXXXX being the aid you are using)
Code:
    if(!((flags & FLAG_IGNOREAUTOSTACK) == FLAG_IGNOREAUTOSTACK)
        && item->isStackable() && item->getParent() != this && item->getActionId() != XXXXX)

And Change:
Code:
    if((*cit)->getID() == item->getID() && (*cit)->getItemCount() < 100)
To (XXXXX being the aid you are using)
Code:
    if((*cit)->getID() == item->getID() && (*cit)->getItemCount() < 100 && (*cit)->getActionId() != XXXXX)


Then in Game.cpp
Find within ReturnValue Game::internalMoveItem:
Change:
Code:
    if(item->isStackable())
    {
        uint8_t n = 0;
        if(toItem && toItem->getID() == item->getID())
To: (XXXXX being the aid you are using)
Code:
    if(item->isStackable() && item->getActionId() != XXXXX)
    {
        uint8_t n = 0;
        if(toItem && toItem->getID() == item->getID())

Then this is the basic creaturescript I've been messing with. Change the XXXXX for your aid you're using

Code:
function onMoveItem(cid, item, count, toContainer, fromContainer, fromPos, toPos)
    if(count > 1 and item.actionid == XXXXX) then
            doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_RED, "This item should not be stacked. Something is wrong. Contact admin.")
            doPlayerSendCancel(cid, "Contact Admin.")
            return false
    elseif(toPos.y == 10) then   --- Checks arrow slot
        if(item.itemid == getPlayerSlotItem(cid, 10).itemid) then
            if(item.actionid == XXXXX or getPlayerSlotItem(cid, 10).actionid == XXXXX) then
                doPlayerSendCancel(cid, "Sorry, not possible. You can not stack upgraded items.")
                return false
            end
        end
    elseif(toPos.y == 6) then   --- Checks hand slot
        if(item.itemid == getPlayerSlotItem(cid, 6).itemid) then
            if(item.actionid == XXXXX or getPlayerSlotItem(cid, 6).actionid == XXXXX) then
                doPlayerSendCancel(cid, "Sorry, not possible. You can not stack upgraded items.")
                return false
            end
        end
    elseif(toPos.y == 5) then   --- Checks hand slot
        if(item.itemid == getPlayerSlotItem(cid, 5).itemid) then
            if(item.actionid == XXXXX or getPlayerSlotItem(cid, 5).actionid == XXXXX) then
                doPlayerSendCancel(cid, "Sorry, not possible. You can not stack upgraded items.")
                return false
            end
        end
    elseif(toContainer.uid >= 70000) then -- Checks if its going to a backpack
        if(item.actionid == XXXXX) then
          
            if(getContainerItem(toContainer.uid, toPos.z).itemid == item.itemid) then
                doPlayerSendCancel(cid, "Sorry, not possible. You can not stack upgraded items.")
                return false
            end
          
        elseif(getContainerItem(toContainer.uid, toPos.z).actionid == XXXXX) then
            doPlayerSendCancel(cid, "Sorry, not possible. You can not stack upgraded items.")
            return false      
        end
    elseif(getThingfromPos({x=toPos.x, y=toPos.y, z=toPos.z, stackpos=1}).actionid == XXXXX) then --- Checks if destination aid exhists
        if(getThingfromPos({x=toPos.x, y=toPos.y, z=toPos.z, stackpos=1}).itemid == item.id) then
            doPlayerSendCancel(cid, "Sorry, not possible. You can not stack upgraded items.")
            return false
        end
    elseif(item.actionid == XXXXX) then
        if(getThingfromPos({x=toPos.x, y=toPos.y, z=toPos.z, stackpos=1}).itemid == item.id) then
            doPlayerSendCancel(cid, "Sorry, not possible. You can not stack upgraded items.")
            return false
        end
    elseif(getThingfromPos({x=toPos.x, y=toPos.y, z=toPos.z, stackpos=1}).actionid == XXXXX and getThingfromPos({x=toPos.x, y=toPos.y, z=toPos.z, stackpos=1}).itemid == item.itemid) then
        doPlayerSendCancel(cid, "Sorry, not possible. You can not stack upgraded items.")
        return false
    end
      
    return true
end
 

Similar threads

Back
Top