• 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 [creatureEvent] onMove very advanced

Doggynub

LUA / C++
Joined
Sep 28, 2008
Messages
2,541
Reaction score
186
support : 0.4 - 0.3.6


Okay the function is a bit long, but i have tryed to make it short but failed so :p, it works.
Code:
function onMoveItem(cid, item, formPosition, toPosition, fromItem, toItem, fromGround, toGround, status)
Structure :
            fromItem, toItem = -- return the item just below the moveditem, or returns the container it was moved from
            fromGround, toGround = --returns the tile , so if tile have many items and u removed first one, you can get the gorund moved from
      
            status.inInv =      0   -- unwearing
                    1   -- wearing
                    2   -- rearrange in inventory
                    3   -- action not included in inventory
          
            status.inInvBag=      0   -- removeing from bags
                    1   -- holding in bags
                    2   -- rearrange in bags
                    3   -- action not included in bags
          
            status.Slot = contain the slot that the item is moved to if it is included in inventory
          
            status.inDepot=     0   -- removeing from depot
                    1   -- holding in depot
                    2   -- rearrange in depot
                    3   -- action not included in depot

SetUp :

#go to creatureEvent.h :

find
Code:
CREATURE_EVENT_DEATH,

replace the line under it exactly with this
Code:
CREATURE_EVENT_PREPAREDEATH,
    //custom move
    CREATURE_EVENT_ONMOVE
    //

find
Code:
uint32_t executePrepareDeath(Creature* creature, DeathList deathList);

paste after
Code:
//custom move
        uint32_t executeOnMove(Player* player, Item* item, const Position& fromPosition, const Position& toPosition,
                Item* fromItem, Item* toItem, Item* fromGround, Item* toGround, std::map<std::string,int> status);
        //
-------------------------------------------------------------------------------------------------------

#goto creatureEvent.cpp

find
Code:
else if(tmpStr == "preparedeath")
        m_type = CREATURE_EVENT_PREPAREDEATH;
under it
Code:
//custom move
    else if(tmpStr == "move")
        m_type = CREATURE_EVENT_ONMOVE;
    //

find
Code:
case CREATURE_EVENT_PREPAREDEATH:
            return "onPrepareDeath";

under it
Code:
//custom move
        case CREATURE_EVENT_ONMOVE:
            return "onMoveItem";
        //
find
Code:
case CREATURE_EVENT_PREPAREDEATH:
            return "cid, deathList";

under it
Code:
//custom move
        case CREATURE_EVENT_ONMOVE:
            return "cid, item, formPosition, toPosition, fromItem, toItem, fromGround, toGround, status";
        //

now go to the end of file paste this

for 0.4
Code:
// custom move
uint32_t CreatureEvent::executeOnMove(Player* player, Item* item, const Position& fromPosition, const Position& toPosition,
    Item* fromItem, Item* toItem, Item* fromGround, Item* toGround, std::map<std::string,int> status)
{
    //onMoveItem(cid, item, formPosition, toPosition, fromItem, toItem, fromGround, toGround, status)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            env->streamThing(scriptstream, "item" ,item, env->addThing(item));
            env->streamPosition(scriptstream, "fromPosition", fromPosition);
            env->streamPosition(scriptstream, "toPosition", toPosition);

          
            env->streamThing(scriptstream, "fromItem",fromItem, env->addThing(fromItem));  
            env->streamThing(scriptstream, "toItem",toItem, env->addThing(toItem));
            env->streamThing(scriptstream, "fromGround",fromGround, env->addThing(fromGround));
            env->streamThing(scriptstream, "toGround",toGround, env->addThing(toGround));
      

      
            scriptstream << "local status = {}" << std::endl;
            for(std::map<std::string,int>::iterator it = status.begin(); it != status.end(); ++it)
            {
                scriptstream << "status."<< it->first << " = " << it->second;
          
            }


            if(m_scriptData)
                scriptstream << *m_scriptData;

            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[30];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEvent(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
          
            LuaInterface::pushThing(L, item, env->addThing(item));
            LuaInterface::pushPosition(L, fromPosition);
            LuaInterface::pushPosition(L, toPosition);

            LuaInterface::pushThing(L, fromItem, env->addThing(fromItem));
            LuaInterface::pushThing(L, toItem, env->addThing(toItem));
            LuaInterface::pushThing(L, fromGround, env->addThing(fromGround));
            LuaInterface::pushThing(L, toGround, env->addThing(toGround));


            lua_newtable(L);
            std::map<std::string,int>::iterator it = status.begin();
            for(std::map<std::string,int>::iterator it = status.begin(); it != status.end(); ++it)
            {
                LuaInterface::setField(L, it->first.c_str(), it->second);
            }
          
          
          


          
            bool result = m_interface->callFunction(9);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::clog << "[Error - CreatureEvent::executeMove] Call stack overflow." << std::endl;
        return 0;
    }
}
//

for 0.3.6
Code:
//custom move
uint32_t CreatureEvent::executeOnMove(Player* player, Item* item, const Position& fromPosition, const Position& toPosition,
    Item* fromItem, Item* toItem, Item* fromGround, Item* toGround, std::map<std::string,int> status)
{
    //onMoveItem(cid, item, formPosition, toPosition, fromItem, toItem, fromGround, toGround, move)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            env->streamThing(scriptstream, "item" ,item, env->addThing(item));
            env->streamPosition(scriptstream, "fromPosition", fromPosition);
            env->streamPosition(scriptstream, "toPosition", toPosition);


            env->streamThing(scriptstream, "fromItem",fromItem, env->addThing(fromItem));  
            env->streamThing(scriptstream, "toItem",toItem, env->addThing(toItem));
            env->streamThing(scriptstream, "fromGround",fromGround, env->addThing(fromGround));
            env->streamThing(scriptstream, "toGround",toGround, env->addThing(toGround));

          
            scriptstream << "local status = {}" << std::endl;
            for(std::map<std::string,int>::iterator it = status.begin(); it != status.end(); ++it)
            {
                scriptstream << "status."<< it->first << " = " << it->second;
          
            }

            scriptstream << m_scriptData;

            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[30];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEvent(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));

            LuaScriptInterface::pushThing(L, item, env->addThing(item));
            LuaScriptInterface::pushPosition(L, fromPosition);
            LuaScriptInterface::pushPosition(L, toPosition);

            LuaScriptInterface::pushThing(L, fromItem, env->addThing(fromItem));
            LuaScriptInterface::pushThing(L, toItem, env->addThing(toItem));
            LuaScriptInterface::pushThing(L, fromGround, env->addThing(fromGround));
            LuaScriptInterface::pushThing(L, toGround, env->addThing(toGround));

            lua_newtable(L);
            std::map<std::string,int>::iterator it = status.begin();
            for(std::map<std::string,int>::iterator it = status.begin(); it != status.end(); ++it)
            {
                LuaScriptInterface::setField(L, it->first.c_str(), it->second);
            }

            bool result = m_interface->callFunction(9);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::clog << "[Error - CreatureEvent::executeMove] Call stack overflow." << std::endl;
        return 0;
    }
}

-------------------------------------------------------------------------------------------------------------------------------------

# goto game.cpp

replace this function all of it
Code:
bool Game::playerMoveItem(uint32_t playerId, const Position& fromPos,
    uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)

with this

for 0.4
Code:
bool Game::playerMoveItem(uint32_t playerId, const Position& fromPos,
    uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)
{
    Player* player = getPlayerByID(playerId);
    //Doggynub: custom move
    bool equip = false, deequip =false,fromDepot = false, toDepot = false;
    int32_t fr = 0,to = 0;
    //
    if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveItems))
        return false;

    if(!player->canDoAction())
    {
        uint32_t delay = player->getNextActionTime();
        SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveItem, this,
            playerId, fromPos, spriteId, fromStackpos, toPos, count));

        player->setNextActionTask(task);
        return false;
    }

    player->setNextActionTask(NULL);
    Cylinder* fromCylinder = internalGetCylinder(player, fromPos);


    uint8_t fromIndex = 0;
    if(fromPos.x == 0xFFFF)
    {
        if(fromPos.y & 0x40)
        {
            fromIndex = static_cast<uint8_t>(fromPos.z);
            fr = 1;
          
        }
        else
        {
            fromIndex = static_cast<uint8_t>(fromPos.y);
            fr = 2;
        }
    }
    else
    {
        fromIndex = fromStackpos;
        fr = 3;
    }



    Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
    if(!thing || !thing->getItem())
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    Item* item = thing->getItem();
    Cylinder* toCylinder = internalGetCylinder(player, toPos);

  

    uint8_t toIndex = 0;
    if(toPos.x == 0xFFFF)
    {
        if(toPos.y & 0x40)
        {
            toIndex = static_cast<uint8_t>(toPos.z);
            to = 1;
        }
        else
        {
            toIndex = static_cast<uint8_t>(toPos.y);
            to = 2;
        }
    }
    else
        to = 3;
      

  

    if(!fromCylinder || !toCylinder || !item || item->getClientID() != spriteId)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }


    if(!player->hasCustomFlag(PlayerCustomFlag_CanPushAllItems) && (!item->isPushable() || (item->isLoadedFromMap() &&
        (item->getUniqueId() != 0 || (item->getActionId() != 0 && item->getContainer())))))
    {
        player->sendCancelMessage(RET_NOTMOVABLE);
        return false;
    }

    const Position &mapToPos = toCylinder->getTile()->getPosition(), &playerPos = player->getPosition(),
        &mapFromPos = fromCylinder->getTile()->getPosition();


    if(playerPos.z > mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
        return false;
    }

    if(playerPos.z < mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
        return false;
    }

    if(!Position::areInRange<1,1,0>(playerPos, mapFromPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
    {
        //need to walk to the item first before using it
        std::list<Direction> listDir;
        if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
        {
            Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                this, player->getID(), listDir)));
            SchedulerTask* task = createSchedulerTask(std::max((int32_t)SCHEDULER_MINTICKS, player->getStepDuration()),
                boost::bind(&Game::playerMoveItem, this, playerId, fromPos, spriteId, fromStackpos, toPos, count));

            player->setNextWalkActionTask(task);
            return true;
        }

        player->sendCancelMessage(RET_THEREISNOWAY);
        return false;
    }

    //hangable item specific code
    if(item->isHangable() && toCylinder->getTile()->hasProperty(SUPPORTHANGABLE))
    {
        //destination supports hangable objects so need to move there first
        if(toCylinder->getTile()->hasProperty(ISVERTICAL))
        {
            if(player->getPosition().x + 1 == mapToPos.x)
            {
                player->sendCancelMessage(RET_NOTPOSSIBLE);
                return false;
            }
        }
        else if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
        {
            if(player->getPosition().y + 1 == mapToPos.y)
            {
                player->sendCancelMessage(RET_NOTPOSSIBLE);
                return false;
            }
        }

        if(!Position::areInRange<1,1,0>(playerPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
        {
            Position walkPos = mapToPos;
            if(toCylinder->getTile()->hasProperty(ISVERTICAL))
                walkPos.x -= -1;

            if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
                walkPos.y -= -1;

            Position itemPos = fromPos;
            int16_t itemStackpos = fromStackpos;
            if(fromPos.x != 0xFFFF && Position::areInRange<1,1,0>(mapFromPos, player->getPosition())
                && !Position::areInRange<1,1,0>(mapFromPos, walkPos))
            {
                //need to pickup the item first
                Item* moveItem = NULL;
                ReturnValue ret = internalMoveItem(player, fromCylinder, player, INDEX_WHEREEVER, item, count, &moveItem);
                if(ret != RET_NOERROR)
                {
                    player->sendCancelMessage(ret);
                    return false;
                }

                //changing the position since its now in the inventory of the player
                internalGetPosition(moveItem, itemPos, itemStackpos);
            }

            std::list<Direction> listDir;
            if(map->getPathTo(player, walkPos, listDir))
            {
                Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                    this, player->getID(), listDir)));
                SchedulerTask* task = createSchedulerTask(std::max((int32_t)SCHEDULER_MINTICKS, player->getStepDuration()),
                    boost::bind(&Game::playerMoveItem, this, playerId, itemPos, spriteId, itemStackpos, toPos, count));

                player->setNextWalkActionTask(task);
                return true;
            }

            player->sendCancelMessage(RET_THEREISNOWAY);
            return false;
        }
    }

    if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        if((std::abs(playerPos.x - mapToPos.x) > item->getThrowRange()) ||
            (std::abs(playerPos.y - mapToPos.y) > item->getThrowRange()) ||
            (std::abs(mapFromPos.z - mapToPos.z) * 4 > item->getThrowRange()))
        {
            player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
            return false;
        }
    }

    if(!canThrowObjectTo(mapFromPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        player->sendCancelMessage(RET_CANNOTTHROW);
        return false;
    }

    //Doggynub: custom move
    if(!item->getParent())
    {
        assert(fromCylinder == item->getParent());
    }

    Item* toItem = NULL;
    Item* fromItem = NULL;
    Item* toGround=NULL;
    Item* fromGround=NULL;
    Player* toPlayer = NULL;
    Player* fromPlayer= NULL;

    Item* toSlotItem= (player->getInventoryItem((slots_t)((unsigned)toIndex)));
    bool checkToSlot = false;

    if (toSlotItem)
        checkToSlot= toSlotItem->isContainer();

    if (fr == 1)
    {
        fromItem = fromCylinder->getItem();
        if (fromItem)
        {
            fromPlayer = fromItem->getHoldingPlayer();
            Item* parentFromItem = fromItem->getTopParent()->getItem();
            if (fromItem->isDepot() || (parentFromItem && parentFromItem->isDepot()) )
                fromDepot = true;
        }
    }
    else if (fr == 2)
        deequip = true;
    else
    {
        const TileItemVector* items = fromCylinder->getTile()->getItemList();
        fromItem = NULL;
        fromGround = fromCylinder->getTile()->ground;
        for(ItemVector::const_reverse_iterator it = items->rbegin(); it != items->rend(); ++it)
        {
            if((*it) != item)
                fromItem = (*it);
        }

        if(!fromItem || fromItem == item )
            fromItem = fromGround ;
    }

    if(to == 1)
    {
        toItem = toCylinder->getItem();
        if(toItem)
        {
            toPlayer = toItem->getHoldingPlayer();
            Item* parentToItem = toItem->getTopParent()->getItem();

            if (toItem->isDepot() || (parentToItem && parentToItem->isDepot()) )
                toDepot = true;
        }

    }
    else if(to == 2)
    {
        equip = true;
        Item* inveItem = player->getInventoryItem((slots_t)(unsigned)toIndex);
        if (inveItem  && inveItem->isContainer())
            toItem = inveItem;

    }
    else
    {
        toItem = toCylinder->getTile()->getTopDownItem();
        toGround = toCylinder->getTile()->ground;
        if(!toItem)
            toItem  = toGround;

    }

    bool Out = (fromPlayer) ? true : false;
    bool In = (toPlayer) ? true : false;
    std::map<std::string,int> status;

    status["inInv"] = (equip && !deequip && !checkToSlot) ? 1:( (!equip && deequip) || (deequip && equip && checkToSlot) ) ? 0 : (equip &&           deequip && !checkToSlot) ? 2 :3;
        status["inDepot"] = (fromDepot && !toDepot) ? 0 : (!fromDepot && toDepot) ? 1: (fromDepot && toDepot) ? 2:3;
        status["inInvBag"] = (Out && !In && !checkToSlot )? 0:((In && !Out) || (!Out && equip && checkToSlot)) ? 1:((In && Out) || (Out && equip && checkToSlot))?2:3;  
        status["slot"] = (int) toIndex;

    bool deny = false;
    CreatureEventList moveEvents = player->getCreatureEvents(CREATURE_EVENT_ONMOVE);
    for(CreatureEventList::iterator it = moveEvents.begin(); it != moveEvents.end(); ++it)
    {
        if(!(*it)->executeOnMove(player, item, mapFromPos, mapToPos, fromItem,toItem,fromGround,toGround,status))
            deny = true;
    }

    if(deny)
        return false;
    //end

    ReturnValue ret = internalMoveItem(player, fromCylinder, toCylinder, toIndex, item, count, NULL);
    if(ret != RET_NOERROR)
    {
        player->sendCancelMessage(ret);
        return false;
    }

    player->setNextAction(OTSYS_TIME() + g_config.getNumber(ConfigManager::ACTIONS_DELAY_INTERVAL) - 10);
    return true;
}
 
Last edited:

for 0.3.6

Code:
bool Game::playerMoveItem(uint32_t playerId, const Position& fromPos,
    uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)
{
    Player* player = getPlayerByID(playerId);
    //custom move
    bool equip = false, deequip =false,fromDepot = false, toDepot = false;
    //
    if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveItems))
        return false;

    if(!player->canDoAction())
    {
        uint32_t delay = player->getNextActionTime();
        SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveItem, this,
            playerId, fromPos, spriteId, fromStackpos, toPos, count));

        player->setNextActionTask(task);
        return false;
    }

    player->setNextActionTask(NULL);
    Cylinder* fromCylinder = internalGetCylinder(player, fromPos);

    //custom move
    Item* fromItem = NULL;
    Item* fromGround = NULL;
    Player* fromPlayer= 0;

    //

    uint8_t fromIndex = 0;
    if(fromPos.x == 0xFFFF)
    {
        if(fromPos.y & 0x40)
        {
            fromIndex = static_cast<uint8_t>(fromPos.z);

            fromItem = fromCylinder->getItem();
            if (fromItem)
            {
                fromPlayer = fromItem->getHoldingPlayer();
                Item* parentFromItem = fromItem->getTopParent()->getItem();
                if (fromItem->isDepot() || (parentFromItem && parentFromItem->isDepot()) )
                    fromDepot = true;
            }
        }
        else
        {
            fromIndex = static_cast<uint8_t>(fromPos.y);
            //custom move
            deequip = true;
            //
        }
    }
    else
    {
        fromIndex = fromStackpos;
        const TileItemVector* items = fromCylinder->getTile()->getItemList();

        Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);

if(thing && thing->getItem())
        {
            Item* movingItem = thing->getItem();

            fromItem = NULL;

            fromGround = fromCylinder->getTile()->ground;
            for(ItemVector::const_reverse_iterator it = items->rbegin(); it != items->rend(); ++it)
            {
                if((*it) != movingItem)
                    fromItem = (*it);
            }

            if(!fromItem || fromItem == movingItem )
                fromItem = fromGround ;
        }
    }



    Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
    if(!thing || !thing->getItem())
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    Item* item = thing->getItem();
    Cylinder* toCylinder = internalGetCylinder(player, toPos);

    //custom move
    Item* toItem = NULL;
    Item* toGround=NULL;
    Player* toPlayer = NULL;


    uint8_t toIndex = 0;
    if(toPos.x == 0xFFFF)
    {
        if(toPos.y & 0x40)
        {
            toIndex = static_cast<uint8_t>(toPos.z);
            if(toCylinder)
            {
                toItem = toCylinder->getItem();

                if(toItem)
                {
                    toPlayer = toItem->getHoldingPlayer();
                    Item* parentToItem = toItem->getTopParent()->getItem();

                    if (toItem->isDepot() || (parentToItem && parentToItem->isDepot()) )
                        toDepot = true;
                }
            }
        }
        else
        {
            toIndex = static_cast<uint8_t>(toPos.y);
            equip = true;
            //custom move
            Item* inveItem = player->getInventoryItem((slots_t)(unsigned)toIndex);
            if (inveItem  && inveItem->isContainer())
                toItem = inveItem;


            //
        }
    }
    else
    {
        if(toCylinder)
        {
            toItem = toCylinder->getTile()->getTopDownItem();
            toGround = toCylinder->getTile()->ground;
            if(!toItem)
                toItem  = toGround;
        }
    }

    //custom move
    Item* toSlotItem= (player->getInventoryItem((slots_t)((unsigned)toIndex)));
    bool checkToSlot = false;

    if (toSlotItem)
        checkToSlot= toSlotItem->isContainer();;
    //

    if(!fromCylinder || !toCylinder || !item || item->getClientID() != spriteId)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    if(!player->hasCustomFlag(PlayerCustomFlag_CanPushAllItems) && (!item->isPushable() || (item->isLoadedFromMap() &&
        (item->getUniqueId() != 0 || (item->getActionId() != 0 && item->getContainer())))))
    {
        player->sendCancelMessage(RET_NOTMOVEABLE);
        return false;
    }

    const Position& mapFromPos = fromCylinder->getTile()->getPosition();
    const Position& mapToPos = toCylinder->getTile()->getPosition();

    const Position& playerPos = player->getPosition();
    if(playerPos.z > mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
        return false;
    }

    if(playerPos.z < mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
        return false;
    }

    if(!Position::areInRange<1,1,0>(playerPos, mapFromPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
    {
        //need to walk to the item first before using it
        std::list<Direction> listDir;
        if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
        {
            Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                this, player->getID(), listDir)));
            SchedulerTask* task = createSchedulerTask(player->getStepDuration(), boost::bind(&Game::playerMoveItem, this,
                playerId, fromPos, spriteId, fromStackpos, toPos, count));

            player->setNextWalkActionTask(task);
            return true;
        }

        player->sendCancelMessage(RET_THEREISNOWAY);
        return false;
    }

    //hangable item specific code
    if(item->isHangable() && toCylinder->getTile()->hasProperty(SUPPORTHANGABLE))
    {
        //destination supports hangable objects so need to move there first
        if(toCylinder->getTile()->hasProperty(ISVERTICAL))
        {
            if(player->getPosition().x + 1 == mapToPos.x)
            {
                player->sendCancelMessage(RET_NOTPOSSIBLE);
                return false;
            }
        }
        else if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
        {
            if(player->getPosition().y + 1 == mapToPos.y)
            {
                player->sendCancelMessage(RET_NOTPOSSIBLE);
                return false;
            }
        }

        if(!Position::areInRange<1,1,0>(playerPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
        {
            Position walkPos = mapToPos;
            if(toCylinder->getTile()->hasProperty(ISVERTICAL))
                walkPos.x -= -1;

            if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
                walkPos.y -= -1;

            Position itemPos = fromPos;
            int16_t itemStackpos = fromStackpos;
            if(fromPos.x != 0xFFFF && Position::areInRange<1,1,0>(mapFromPos, player->getPosition())
                && !Position::areInRange<1,1,0>(mapFromPos, walkPos))
            {
                //need to pickup the item first
                Item* moveItem = NULL;
                ReturnValue ret = internalMoveItem(player, fromCylinder, player, INDEX_WHEREEVER, item, count, &moveItem);
                if(ret != RET_NOERROR)
                {
                    player->sendCancelMessage(ret);
                    return false;
                }

                //changing the position since its now in the inventory of the player
                internalGetPosition(moveItem, itemPos, itemStackpos);
            }

            std::list<Direction> listDir;
            if(map->getPathTo(player, walkPos, listDir))
            {
                Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                    this, player->getID(), listDir)));
                SchedulerTask* task = createSchedulerTask(player->getStepDuration(), boost::bind(&Game::playerMoveItem, this,
                    playerId, itemPos, spriteId, itemStackpos, toPos, count));

                player->setNextWalkActionTask(task);
                return true;
            }

            player->sendCancelMessage(RET_THEREISNOWAY);
            return false;
        }
    }

    if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        if((std::abs(playerPos.x - mapToPos.x) > item->getThrowRange()) ||
            (std::abs(playerPos.y - mapToPos.y) > item->getThrowRange()) ||
            (std::abs(mapFromPos.z - mapToPos.z) * 4 > item->getThrowRange()))
        {
            player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
            return false;
        }
    }

    if(!canThrowObjectTo(mapFromPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        player->sendCancelMessage(RET_CANNOTTHROW);
        return false;
    }

    //custom move
    bool Out = (fromPlayer) ? true : false;
    bool In = (toPlayer) ? true : false;
    std::map<std::string,int> status;

    status["inInv"] = (equip && !deequip && !checkToSlot) ? 1:( (!equip && deequip) || (deequip && equip && checkToSlot) ) ? 0 : (equip && deequip && !checkToSlot) ? 2 :3;
    status["inDepot"] = (fromDepot && !toDepot) ? 0 : (!fromDepot && toDepot) ? 1: (fromDepot && toDepot) ? 2:3;
    status["inInvBag"] = (Out && !In && !checkToSlot )? 0:((In && !Out) || (!Out && equip && checkToSlot)) ? 1:((In && Out) || (Out && equip && checkToSlot))?2:3;  
    status["slot"] = (int) toIndex;
  

    bool deny = false;
    CreatureEventList moveEvents = player->getCreatureEvents(CREATURE_EVENT_ONMOVE);
    for(CreatureEventList::iterator it = moveEvents.begin(); it != moveEvents.end(); ++it)
    {
        if(!(*it)->executeOnMove(player, item, mapFromPos, mapToPos, fromItem,toItem,fromGround,toGround,status))
            deny = true;
    }

    if(deny)
        return false;

    ReturnValue ret = internalMoveItem(player, fromCylinder, toCylinder, toIndex, item, count, NULL);
    if(ret == RET_NOERROR)
        return true;

    player->sendCancelMessage(ret);
    return false;
}

-------------------------------------------------------------------------------------------------------------------------------------


Lets say you want an item whenever a player hold it he cant throw on ground , but he can move to depot, in bag,in inventory :

Code:
function onMoveItem(cid, item, formPosition, toPosition, fromItem, toItem, fromGround, toGround, status)
    if item.itemid == 2466 then
        if (status.inInv == 0 and status.inInvBag == 3 and status.inDepot == 3) or (status.inDepot == 0 and status.inInv == 3 and status.inInvBag == 3 ) or (status.inInvBag == 0 and status.inDepot == 3 and status.inInv == 3) then
            doPlayerSendCancel(cid,"you can't throw this item on ground.")
            return false
        end
    end
    return true
end


NOTE:
for old 0.4 ( less than 9.0 client support) you may get 2 errors in:


1- creatureevent.cpp Here is Fix
2- game.cpp Here is Fix
 
Last edited:
Great idea for unique items like starting potions or something like this :)
How to do that with trade ?
 
well you have these already :
Code:
	onTradeRequest(cid, target, item)
			onTradeAccept(cid, target, item, targetItem)
 
I was just getting this error here:
Code:
if(m_scriptData)
	scriptstream << *m_scriptData;

so I just replaced it with:
Code:
scriptstream << m_scriptData;

Like all the other functions on creatureevent.cpp. Hope it works, compiled alright. Gonna test it now.

Edit.:

Am I doing it right?
Code:
	<event type="move" name="Moving" event="script" value="move.lua"/>
 
Last edited:
I'm using TFS 0.4, which one did you use? Cuz it's not working here. I mean, it's compiling alright with that change I showed you above, but it ain't working. I'm making the example script you posted and it just doesn't do anything :/
 
have you register it in login.lua
and i used 8.70 rev , 8.71, and 8.90 to test
 
It's working now, the only problem is that I can only compile on my laptop. When I try compiling on this desktop, I get the following error:
Code:
 no match for 'operator!=' in 'it != TileItemVector::rend()()'
Here:
Code:
 for(ItemVector::const_reverse_iterator it = items->rbegin(); it != items->rend(); ++it)
Is there a missing library or something that could cause this? Cuz it's really odd the fact that it's compiling alright on the other computer but not here, the one I use more often.

PS.: My laptop is 64bit so I use Stian's Repack 2.0, and here I downloaded Stian's Repack 1.0, but it was compiling just fine
 
Oh, and could you give me an idea on how exactly would it detect that, when I'm moving a bag, the item that I don't want to be moved is inside this bag?!

edit: Nvm, just did a function that does that checking :D
 
Last edited:
If you mean when player move from place to another , then not. It warms when a Player or a creature moves an item according to how u registered it in creatureevent. xml
 
error on compiling :S

Code:
1279 game.cpp no match for 'operator<' in 'it < TileItemVector::rend()()'

line

Code:
for(ItemVector::const_reverse_iterator it = items->rbegin(); it < items->rend(); ++it)


help-me
 
change (game.cpp):

TileItemVector* items = fromCylinder->getTile()->getItemList();
to
const TileItemVector* items = fromCylinder->getTile()->getItemList();
 
Code:
...\game.cpp In member function `bool Game::playerMoveItem(uint32_t, const Position&, uint16_t, int16_t, const Position&, uint8_t)': 

...\game.cpp `RET_NOTMOVABLE' was not declared in this scope 

...\Makefile.win [Build Error]  [obj//game.o] Error 1

@Edit

i Fix it. sorry for spam

Code:
player->sendCancelMessage(RET_NOTMOVABLE);

to

Code:
player->sendCancelMessage(RET_NOTMOVEABLE);


Really good job, usefull function
 
Last edited:

Similar threads

Replies
7
Views
938
Back
Top