Skip to content

Commit d5942dc

Browse files
fix: hotkey swaps, house potion use, and loot pouch equip handling (#519)
* fix: hotkey swaps, house potion use, and loot pouch equip handling opentibiabr/canary#3436 * fix: quiver swap * Code format - (Clang-format) --------- Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
1 parent 84f08f0 commit d5942dc

File tree

3 files changed

+88
-64
lines changed

3 files changed

+88
-64
lines changed

src/creatures/players/player.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3369,6 +3369,26 @@ bool Player::canDoAction() const {
33693369
return nextAction <= OTSYS_TIME();
33703370
}
33713371

3372+
void Player::setNextNecklaceAction(int64_t time) {
3373+
if (time > nextNecklaceAction) {
3374+
nextNecklaceAction = time;
3375+
}
3376+
}
3377+
3378+
void Player::setNextRingAction(int64_t time) {
3379+
if (time > nextRingAction) {
3380+
nextRingAction = time;
3381+
}
3382+
}
3383+
3384+
bool Player::canEquipNecklace() const {
3385+
return OTSYS_TIME() >= nextNecklaceAction;
3386+
}
3387+
3388+
bool Player::canEquipRing() const {
3389+
return OTSYS_TIME() >= nextRingAction;
3390+
}
3391+
33723392
void Player::setNextPotionAction(int64_t time) {
33733393
if (time > nextPotionAction) {
33743394
nextPotionAction = time;

src/creatures/players/player.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,12 @@ class Player final : public Creature, public Cylinder, public Bankable {
11151115
void setNextPotionAction(int64_t time);
11161116
bool canDoPotionAction() const;
11171117

1118+
void setNextNecklaceAction(int64_t time);
1119+
bool canEquipNecklace() const;
1120+
1121+
void setNextRingAction(int64_t time);
1122+
bool canEquipRing() const;
1123+
11181124
void setNextExAction(int64_t time);
11191125
bool canDoExAction() const;
11201126

@@ -1680,6 +1686,8 @@ class Player final : public Creature, public Cylinder, public Bankable {
16801686
int64_t nextExAction = 0;
16811687
int64_t nextImbuementAction = 0;
16821688
int64_t nextPotionAction = 0;
1689+
int64_t nextNecklaceAction = 0;
1690+
int64_t nextRingAction = 0;
16831691
int64_t nextMarketAction = 0;
16841692
int64_t lastQuickLootNotification = 0;
16851693
int64_t lastWalking = 0;

src/game/game.cpp

Lines changed: 60 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3473,6 +3473,10 @@ uint64_t Game::getItemMarketPrice(const std::map<uint16_t, uint64_t> &itemMap, b
34733473
}
34743474

34753475
std::shared_ptr<Item> searchForItem(const std::shared_ptr<Container> &container, uint16_t itemId, bool hasTier /* = false*/, uint8_t tier /* = 0*/) {
3476+
if (!container) {
3477+
return nullptr;
3478+
}
3479+
34763480
for (ContainerIterator it = container->iterator(); it.hasNext(); it.advance()) {
34773481
if ((*it)->getID() == itemId && (!hasTier || (*it)->getTier() == tier)) {
34783482
return *it;
@@ -3515,6 +3519,32 @@ void Game::playerEquipItem(uint32_t playerId, uint16_t itemId, bool hasTier /* =
35153519
return;
35163520
}
35173521

3522+
const ItemType &it = Item::items[itemId];
3523+
Slots_t slot = getSlotType(it);
3524+
3525+
if (slot == CONST_SLOT_NECKLACE) {
3526+
if (!player->canEquipNecklace()) {
3527+
return;
3528+
}
3529+
} else if (slot == CONST_SLOT_RING) {
3530+
if (!player->canEquipRing()) {
3531+
return;
3532+
}
3533+
} else if (!player->canDoAction()) {
3534+
uint32_t delay = player->getNextActionTime();
3535+
if (delay > 0) {
3536+
const auto &task = createPlayerTask(
3537+
delay,
3538+
[this, playerId, itemId, hasTier, tier] {
3539+
playerEquipItem(playerId, itemId, hasTier, tier);
3540+
},
3541+
__FUNCTION__
3542+
);
3543+
player->setNextActionTask(task);
3544+
}
3545+
return;
3546+
}
3547+
35183548
if (player->hasCondition(CONDITION_FEARED)) {
35193549
/*
35203550
* When player is feared the player can´t equip any items.
@@ -3524,32 +3554,22 @@ void Game::playerEquipItem(uint32_t playerId, uint16_t itemId, bool hasTier /* =
35243554
}
35253555

35263556
const auto &item = player->getInventoryItem(CONST_SLOT_BACKPACK);
3527-
if (!item) {
3528-
return;
3529-
}
3530-
3531-
const std::shared_ptr<Container> &backpack = item->getContainer();
3532-
if (!backpack) {
3533-
return;
3534-
}
3535-
3536-
if (player->getFreeBackpackSlots() == 0) {
3537-
player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM);
3538-
return;
3539-
}
3540-
3541-
const ItemType &it = Item::items[itemId];
3542-
Slots_t slot = getSlotType(it);
3557+
const auto &backpack = item ? item->getContainer() : nullptr;
35433558

35443559
const auto &slotItem = player->getInventoryItem(slot);
3545-
const auto &equipItem = searchForItem(backpack, it.id, hasTier, tier);
3560+
auto equipItem = searchForItem(backpack, it.id, hasTier, tier);
3561+
if (!equipItem) {
3562+
const auto &lootPouch = player->getLootPouch();
3563+
equipItem = searchForItem(lootPouch, it.id, hasTier, tier);
3564+
}
35463565
ReturnValue ret = RETURNVALUE_NOERROR;
3547-
if (slotItem && slotItem->getID() == it.id && (!it.stackable || slotItem->getItemCount() == slotItem->getStackSize() || !equipItem)) {
3548-
ret = internalMoveItem(slotItem->getParent(), player, CONST_SLOT_WHEREEVER, slotItem, slotItem->getItemCount(), nullptr);
3549-
g_logger().debug("Item {} was unequipped", slotItem->getName());
3566+
3567+
if (slotItem && slotItem->getID() == it.id && (!hasTier || slotItem->getTier() == tier) && !equipItem) {
3568+
ret = internalCollectManagedItems(player, slotItem, getObjectCategory(slotItem), false);
35503569
} else if (equipItem) {
35513570
// Shield slot item
35523571
const auto &rightItem = player->getInventoryItem(CONST_SLOT_RIGHT);
3572+
35533573
// Check Ammo item
35543574
if (it.weaponType == WEAPON_AMMO) {
35553575
if (rightItem && rightItem->isQuiver()) {
@@ -3559,62 +3579,39 @@ void Game::playerEquipItem(uint32_t playerId, uint16_t itemId, bool hasTier /* =
35593579
const auto &leftItem = player->getInventoryItem(CONST_SLOT_LEFT);
35603580

35613581
const int32_t &slotPosition = equipItem->getSlotPosition();
3562-
35633582
// Checks if a two-handed item is being equipped in the left slot when the right slot is already occupied and move to backpack
35643583
if (
35653584
(slotPosition & SLOTP_LEFT)
35663585
&& (slotPosition & SLOTP_TWO_HAND)
35673586
&& rightItem
3568-
&& !(it.weaponType == WEAPON_DISTANCE)
35693587
&& !rightItem->isQuiver()
3570-
&& (!leftItem || leftItem->getWeaponType() != WEAPON_DISTANCE)
35713588
) {
35723589
ret = internalCollectManagedItems(player, rightItem, getObjectCategory(rightItem), false);
35733590
}
35743591

3575-
/* FIX: Auto-unequip shield when equipping two-handed bow */
3576-
if (slot == CONST_SLOT_LEFT && (slotPosition & SLOTP_TWO_HAND) && equipItem->getWeaponType() == WEAPON_DISTANCE) {
3577-
if (rightItem && !rightItem->isQuiver()) {
3578-
// Unequip item from right slot (shield or other item)
3579-
ret = internalMoveItem(rightItem->getParent(), player, INDEX_WHEREEVER, rightItem, rightItem->getItemCount(), nullptr);
3580-
if (ret == RETURNVALUE_NOERROR) {
3581-
g_logger().debug("Item {} was unequipped to equip two-handed bow", rightItem->getName());
3582-
} else {
3583-
player->sendCancelMessage(ret);
3584-
return;
3585-
}
3586-
}
3587-
}
3588-
35893592
// Check if trying to equip a shield while a two-handed weapon is equipped in the left slot
3590-
if (slot == CONST_SLOT_RIGHT && leftItem && leftItem->getSlotPosition() & SLOTP_TWO_HAND) {
3591-
// FIX: Don't unequip bow if quiver is equipped */
3592-
if (!it.isQuiver() || leftItem->getWeaponType() != WEAPON_DISTANCE) {
3593-
// Unequip the two-handed weapon from the left slot
3594-
ret = internalMoveItem(leftItem->getParent(), player, INDEX_WHEREEVER, leftItem, leftItem->getItemCount(), nullptr);
3595-
if (ret == RETURNVALUE_NOERROR) {
3596-
g_logger().debug("Two-handed weapon {} was unequipped to equip shield", leftItem->getName());
3597-
} else {
3598-
player->sendCancelMessage(ret);
3599-
return;
3600-
}
3593+
if (slot == CONST_SLOT_RIGHT && !it.isQuiver() && leftItem && leftItem->getSlotPosition() & SLOTP_TWO_HAND) {
3594+
ret = internalMoveItem(leftItem->getParent(), player, INDEX_WHEREEVER, leftItem, leftItem->getItemCount(), nullptr);
3595+
if (ret != RETURNVALUE_NOERROR) {
3596+
player->sendCancelMessage(ret);
3597+
return;
36013598
}
36023599
}
36033600

3604-
if (slotItem) {
3605-
ret = internalMoveItem(slotItem->getParent(), player, INDEX_WHEREEVER, slotItem, slotItem->getItemCount(), nullptr);
3606-
g_logger().debug("Item {} was moved back to player", slotItem->getName());
3607-
}
3608-
36093601
ret = internalMoveItem(equipItem->getParent(), player, slot, equipItem, equipItem->getItemCount(), nullptr);
3610-
if (ret == RETURNVALUE_NOERROR) {
3611-
g_logger().debug("Item {} was equipped", equipItem->getName());
3612-
}
36133602
}
36143603
}
36153604

36163605
if (ret != RETURNVALUE_NOERROR) {
36173606
player->sendCancelMessage(ret);
3607+
return;
3608+
}
3609+
if (slot == CONST_SLOT_NECKLACE) {
3610+
player->setNextNecklaceAction(OTSYS_TIME() + g_configManager().getNumber(ACTIONS_DELAY_INTERVAL));
3611+
} else if (slot == CONST_SLOT_RING) {
3612+
player->setNextRingAction(OTSYS_TIME() + g_configManager().getNumber(ACTIONS_DELAY_INTERVAL));
3613+
} else {
3614+
player->setNextAction(OTSYS_TIME() + g_configManager().getNumber(ACTIONS_DELAY_INTERVAL));
36183615
}
36193616
}
36203617

@@ -4140,14 +4137,13 @@ void Game::playerUseWithCreature(uint32_t playerId, const Position &fromPos, uin
41404137
return;
41414138
}
41424139

4143-
if (g_configManager().getBoolean(ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS)) {
4144-
if (std::shared_ptr<HouseTile> houseTile = std::dynamic_pointer_cast<HouseTile>(item->getTile())) {
4145-
const auto &house = houseTile->getHouse();
4146-
if (house && item->getRealParent() && item->getRealParent() != player && (!house->isInvited(player) || house->getHouseAccessLevel(player) == HOUSE_GUEST)) {
4147-
player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT);
4148-
return;
4149-
}
4150-
}
4140+
bool canUseHouseItem = !g_configManager().getBoolean(ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS) || InternalGame::playerCanUseItemOnHouseTile(player, item);
4141+
if (!canUseHouseItem && item->hasOwner() && !item->isOwner(player)) {
4142+
player->sendCancelMessage(RETURNVALUE_ITEMISNOTYOURS);
4143+
return;
4144+
} else if (!canUseHouseItem) {
4145+
player->sendCancelMessage(RETURNVALUE_ITEMCANNOTBEMOVEDTHERE);
4146+
return;
41514147
}
41524148

41534149
const ItemType &it = Item::items[item->getID()];

0 commit comments

Comments
 (0)