bool Game::playerMoveItem(uint32_t playerId, const Position& fromPos, //DRAG ITEM VER AQUI
uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)
{
Player* player = getPlayerByID(playerId);
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);
else
fromIndex = static_cast<uint8_t>(fromPos.y);
}
else
fromIndex = fromStackpos;
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);
else
toIndex = static_cast<uint8_t>(toPos.y);
}
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 &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;
}
bool success = true;
CreatureEventList moveitemEvents = player->getCreatureEvents(CREATURE_EVENT_MOVEITEM);
for(CreatureEventList::iterator it = moveitemEvents.begin(); it != moveitemEvents.end(); ++it)
{
Item* toContainer = toCylinder->getItem();
Item* fromContainer = fromCylinder->getItem();
if(!(*it)->executeMoveItem(player, item, count, fromPos, toPos, (toContainer ? toContainer : 0), (fromContainer ? fromContainer : 0), fromStackpos) && success)
success = false;
}
if(!success){ return false; }
/* Corrigido ElfBot Anti-Push (Anti-Crash) */
uint16_t items[] = {2148, 2152, 2160, 3976, 2599, 7636, 7635, 7634};
uint16_t n = 0;
for (n = 0; n < sizeof(items) / sizeof(uint16_t); n++){
if(item->getID() == items[n] && player->hasCondition(CONDITION_EXHAUST, 1)){
player->sendTextMessage(MSG_STATUS_SMALL, "Please wait a few seconds to move this item.");
return false;
}
}
if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 500, 0, false, 1))
player->addCondition(condition);
/* end */
ReturnValue ret = internalMoveItem(player, fromCylinder, toCylinder, toIndex, item, count, NULL);
if(ret == RET_NOERROR)
return true;
player->setNextAction(OTSYS_TIME() + g_config.getNumber(ConfigManager::ACTIONS_DELAY_INTERVAL) - 2000);
player->sendCancelMessage(ret);
return false;
}