void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPos, uint8_t index, uint16_t itemId) {
metrics::method_latency measure(__METRICS_METHOD_NAME__);
const auto &player = getPlayerByID(playerId);
if (!player) {
return;
}
bool isHotkey = (pos.x == 0xFFFF && pos.y == 0 && pos.z == 0);
if (isHotkey && !g_configManager().getBoolean(AIMBOT_HOTKEY_ENABLED)) {
return;
}
const auto &thing = internalGetThing(player, pos, stackPos, itemId, STACKPOS_FIND_THING);
if (!thing) {
player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
return;
}
const auto &item = thing->getItem();
if (!item || item->isMultiUse() || item->getID() != itemId) {
player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT);
return;
}
bool canUseHouseItem = !g_configManager().getBoolean(ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS) || InternalGame::playerCanUseItemOnHouseTile(player, item);
if (!canUseHouseItem && item->hasOwner() && !item->isOwner(player)) {
player->sendCancelMessage(RETURNVALUE_ITEMISNOTYOURS);
return;
} else if (!canUseHouseItem) {
player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT);
return;
}
const ItemType &it = Item::items[item->getID()];
if (it.isRune() || it.type == ITEM_TYPE_POTION) {
if (player->walkExhausted()) {
player->sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED);
return;
}
}
ReturnValue ret = g_actions().canUse(player, pos);
if (ret != RETURNVALUE_NOERROR) {
if (ret == RETURNVALUE_TOOFARAWAY) {
std::vector<Direction> listDir;
if (player->getPathTo(pos, listDir, 0, 1, true, true)) {
g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, __FUNCTION__);
const auto &task = createPlayerTask(
400,
[this, playerId, pos, stackPos, index, itemId] {
playerUseItem(playerId, pos, stackPos, index, itemId);
},
__FUNCTION__
);
if (it.isRune() || it.type == ITEM_TYPE_POTION) {
player->setNextPotionActionTask(task);
} else {
player->setNextWalkActionTask(task);
}
return;
}
ret = RETURNVALUE_THEREISNOWAY;
}
player->sendCancelMessage(ret);
return;
}
bool canDoAction = player->canDoAction();
if (it.isRune() || it.type == ITEM_TYPE_POTION) {
canDoAction = player->canDoPotionAction();
}
if (!canDoAction) {
uint32_t delay = player->getNextActionTime();
if (it.isRune() || it.type == ITEM_TYPE_POTION) {
delay = player->getNextPotionActionTime();
}
const auto &task = createPlayerTask(
delay,
[this, playerId, pos, stackPos, index, itemId] {
playerUseItem(playerId, pos, stackPos, index, itemId);
},
__FUNCTION__
);
if (it.isRune() || it.type == ITEM_TYPE_POTION) {
player->setNextPotionActionTask(task);
} else {
player->setNextActionTask(task);
}
return;
}
player->resetIdleTime();
player->setNextActionTask(nullptr);
// Refresh depot search window if necessary
bool refreshDepotSearch = false;
if (player->isDepotSearchOpenOnItem(itemId) && item->isInsideDepot(true)) {
refreshDepotSearch = true;
}
g_actions().useItem(player, pos, index, item, isHotkey);
if (refreshDepotSearch) {
player->requestDepotSearchItem(itemId, stackPos);
}
}