From 4a661ef2c1a5333e189dbdeb15483f9dba44ab55 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Mon, 18 Mar 2024 20:36:46 -0300 Subject: [PATCH 1/7] fix: register weapon with chain attribute (#2421) Log moved to trace and fixed a minor error in the deactivation logic. --- src/items/functions/item/item_parse.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/items/functions/item/item_parse.cpp b/src/items/functions/item/item_parse.cpp index e4195c0aefb..5bb10307e9d 100644 --- a/src/items/functions/item/item_parse.cpp +++ b/src/items/functions/item/item_parse.cpp @@ -1166,13 +1166,14 @@ void ItemParse::createAndRegisterScript(ItemType &itemType, pugi::xml_node attri g_logger().warn("[{}] - wandtype '{}' does not exist", __FUNCTION__, elementName); } } else if (stringKey == "chain" && weapon) { - if (auto value = subValueAttribute.as_double()) { - weapon->setChainSkillValue(value); - g_logger().trace("Found chain skill value '{}' for weapon: {}", value, itemType.name); + auto doubleValue = subValueAttribute.as_double(); + if (doubleValue > 0) { + weapon->setChainSkillValue(doubleValue); + g_logger().trace("Found chain skill value '{}' for weapon: {}", doubleValue, itemType.name); } - if (subValueAttribute.as_bool() == false) { + if (doubleValue < 0.1 && subValueAttribute.as_bool() == false) { weapon->setDisabledChain(); - g_logger().warn("Chain disabled for weapon: {}", itemType.name); + g_logger().trace("Chain disabled for weapon: {}", itemType.name); } } } From 1e70b577434c905c66f4ce5c933536728ff089a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Lu=C3=ADs=20Lucarelo=20Lamonato?= Date: Mon, 18 Mar 2024 20:58:35 -0300 Subject: [PATCH 2/7] improve: banking NPC behavior for gold withdraw (#2414) This update significantly improves the interaction with banking NPCs by addressing the issue where NPCs would drop gold on the ground if a player didn't have enough free slots in their backpack or enough carrying capacity. Now, instead of dropping the gold, the NPC will warn the player about the lack of space or capacity, preventing potential loss of gold. This change ensures a smoother and more intuitive banking experience, keeping players' assets secure and enhancing overall gameplay satisfaction. Fixes #2290. Tested scenarios include withdrawing gold with full backpacks and exceeding carrying capacity, with NPCs now providing warnings instead of dropping gold. --- data/npclib/npc_system/bank_system.lua | 40 ++++++++++++++++++++------ 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/data/npclib/npc_system/bank_system.lua b/data/npclib/npc_system/bank_system.lua index 02e47da9de7..0b4a8e97f54 100644 --- a/data/npclib/npc_system/bank_system.lua +++ b/data/npclib/npc_system/bank_system.lua @@ -180,19 +180,41 @@ function Npc:parseBank(message, npc, creature, npcHandler) return true elseif npcHandler:getTopic(playerId) == 7 then if MsgContains(message, "yes") then + local totalValue = count[playerId] + local crystalCoins = math.floor(totalValue / 10000) + totalValue = totalValue % 10000 + local platinumCoins = math.floor(totalValue / 100) + totalValue = totalValue % 100 + local goldCoins = math.floor(totalValue / 1) + local crystalPiles = math.floor((crystalCoins + 99) / 100) + local platinumPiles = math.floor((platinumCoins + 99) / 100) + local goldPiles = math.floor((goldCoins + 99) / 100) + local totalPiles = crystalPiles + platinumPiles + goldPiles if player:getFreeCapacity() >= getMoneyWeight(count[playerId]) then - if not player:withdrawMoney(count[playerId]) then - npcHandler:say("There is not enough gold on your account.", npc, creature) + if player:getFreeBackpackSlots() >= totalPiles then + if not player:withdrawMoney(count[playerId]) then + npcHandler:say("There is not enough gold on your account.", npc, creature) + else + npcHandler:say(string.format("Here you are, %i gold. Please let me know if there is something else I can do for you.", count[playerId]), npc, creature) + end else - npcHandler:say(string.format("Here you are, %d gold. Please let me know if there is something else I can do for you.", count[playerId]), npc, creature) + npcHandler:say( + string.format( + "Hold on, you don't have enough room in your backpack to carry all these coins. \nI don't want you to drop them on the floor, perhaps come back when you have more space in your backpack!\nYou will receive %i crystal stacks (%i coins), %i platinum stacks (%i coins), and %i gold stacks (%i coins). Please ensure you have at least %i free slots in your backpack.\n", + crystalPiles, + crystalCoins, + platinumPiles, + platinumCoins, + goldPiles, + goldCoins, + totalPiles + ), + npc, + creature + ) end else - npcHandler:say( - "Whoah, hold on, you have no room in your inventory to carry all those coins. \z - I don't want you to drop it on the floor, maybe come back with a cart!", - npc, - creature - ) + npcHandler:say("Whoah, hold on, you have no free capacity to carry all those coins!", npc, creature) end npcHandler:setTopic(playerId, 0) elseif MsgContains(message, "no") then From cb30f3ff82c4701697d9bc3f0804ce0a6c0295b9 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Mon, 18 Mar 2024 20:59:15 -0300 Subject: [PATCH 3/7] fix: correct configure weapon wand (#2465) Fix related from the pr: #1494 Resolves #2464 Resolves #2383 --- src/items/functions/item/item_parse.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/items/functions/item/item_parse.cpp b/src/items/functions/item/item_parse.cpp index 5bb10307e9d..2d1ba9301c5 100644 --- a/src/items/functions/item/item_parse.cpp +++ b/src/items/functions/item/item_parse.cpp @@ -1165,6 +1165,7 @@ void ItemParse::createAndRegisterScript(ItemType &itemType, pugi::xml_node attri } else { g_logger().warn("[{}] - wandtype '{}' does not exist", __FUNCTION__, elementName); } + } else if (stringKey == "chain" && weapon) { auto doubleValue = subValueAttribute.as_double(); if (doubleValue > 0) { @@ -1183,6 +1184,7 @@ void ItemParse::createAndRegisterScript(ItemType &itemType, pugi::xml_node attri g_logger().trace("Added weapon damage from '{}', to '{}'", fromDamage, toDamage); weaponWand->setMinChange(fromDamage); weaponWand->setMaxChange(toDamage); + weaponWand->configureWeapon(itemType); } auto combat = weapon->getCombat(); From 18ec4a7b180e0068a98a4131899001d24915a900 Mon Sep 17 00:00:00 2001 From: Carlos Eduardo Silva <104630060+CarlosE-Dev@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:01:24 -0300 Subject: [PATCH 4/7] fix: incorrect pricing for enchant/recharge with silver tokens (#2463) The NPC Cledwyn, who performs enchant/recharge of various items in exchange for silver tokens is ALWAYS charging 2 silver tokens for each operation. However, some of them should cost 5 silver tokens. --- data-otservbr-global/npc/cledwyn.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/data-otservbr-global/npc/cledwyn.lua b/data-otservbr-global/npc/cledwyn.lua index 6e9efd9f76c..7bea164c4b6 100644 --- a/data-otservbr-global/npc/cledwyn.lua +++ b/data-otservbr-global/npc/cledwyn.lua @@ -97,6 +97,8 @@ end local charge = {} +local chargePrice = {} + local chargeItem = { ["pendulet"] = { noChargeID = 29429, ChargeID = 30344 }, ["sleep shawl"] = { noChargeID = 29428, ChargeID = 30342 }, @@ -137,18 +139,20 @@ local function creatureSayCallback(npc, creature, type, message) elseif table.contains({ "pendulet", "sleep shawl", "blister ring", "theurgic amulet", "ring of souls", "turtle amulet" }, message:lower()) and npcHandler:getTopic(playerId) == 1 then npcHandler:say("Should I enchant the item " .. message .. " for 2 " .. ItemType(npc:getCurrency()):getPluralName():lower() .. "?", npc, creature) charge = message:lower() + chargePrice = 2 npcHandler:setTopic(playerId, 2) elseif table.contains({ "spiritthorn ring", "alicorn ring", "arcanomancer sigil", "arboreal ring" }, message:lower()) and npcHandler:getTopic(playerId) == 1 then npcHandler:say("Should I enchant the item " .. message .. " for 5 " .. ItemType(npc:getCurrency()):getPluralName():lower() .. "?", npc, creature) charge = message:lower() + chargePrice = 5 npcHandler:setTopic(playerId, 2) elseif npcHandler:getTopic(playerId) == 2 then if MsgContains(message, "yes") then if not chargeItem[charge] then npcHandler:say("Sorry, you don't have an unenchanted " .. charge .. ".", npc, creature) else - if (player:getItemCount(npc:getCurrency()) >= 2) and (player:getItemCount(chargeItem[charge].noChargeID) >= 1) then - player:removeItem(npc:getCurrency(), 2) + if (player:getItemCount(npc:getCurrency()) >= chargePrice) and (player:getItemCount(chargeItem[charge].noChargeID) >= 1) then + player:removeItem(npc:getCurrency(), chargePrice) player:removeItem(chargeItem[charge].noChargeID, 1) local itemAdd = player:addItem(chargeItem[charge].ChargeID, 1) npcHandler:say("Ah, excellent. Here is your " .. itemAdd:getName():lower() .. ".", npc, creature) From 944c74b25a1e757d9806d7526924f9bc70cc1779 Mon Sep 17 00:00:00 2001 From: Aerwix Date: Tue, 19 Mar 2024 06:33:55 -0600 Subject: [PATCH 5/7] fix: set isBlocking to false for area runes (#2468) Resolves #2467 --- data/scripts/runes/avalanche.lua | 1 + data/scripts/runes/energy_bomb.lua | 2 +- data/scripts/runes/energy_wall.lua | 2 +- data/scripts/runes/fire_bomb.lua | 2 +- data/scripts/runes/fire_wall.lua | 2 +- data/scripts/runes/great_fireball.lua | 2 +- data/scripts/runes/poison_bomb.lua | 2 +- data/scripts/runes/poison_wall.lua | 2 +- data/scripts/runes/stone_shower.lua | 1 + data/scripts/runes/thunderstorm.lua | 1 + 10 files changed, 10 insertions(+), 7 deletions(-) diff --git a/data/scripts/runes/avalanche.lua b/data/scripts/runes/avalanche.lua index 6aefb1e1042..8837162695e 100644 --- a/data/scripts/runes/avalanche.lua +++ b/data/scripts/runes/avalanche.lua @@ -30,4 +30,5 @@ rune:level(30) rune:magicLevel(4) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() diff --git a/data/scripts/runes/energy_bomb.lua b/data/scripts/runes/energy_bomb.lua index 4396c02c0d9..b31ae0e2d7a 100644 --- a/data/scripts/runes/energy_bomb.lua +++ b/data/scripts/runes/energy_bomb.lua @@ -24,5 +24,5 @@ rune:level(37) rune:magicLevel(10) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) -rune:isBlocking(true) -- True = Solid / False = Creature +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() diff --git a/data/scripts/runes/energy_wall.lua b/data/scripts/runes/energy_wall.lua index aae0bf029e1..d2e89e94242 100644 --- a/data/scripts/runes/energy_wall.lua +++ b/data/scripts/runes/energy_wall.lua @@ -24,5 +24,5 @@ rune:level(41) rune:magicLevel(9) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) -rune:isBlocking(true) -- True = Solid / False = Creature +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() diff --git a/data/scripts/runes/fire_bomb.lua b/data/scripts/runes/fire_bomb.lua index 257e07c75c6..5a3efac6d14 100644 --- a/data/scripts/runes/fire_bomb.lua +++ b/data/scripts/runes/fire_bomb.lua @@ -24,5 +24,5 @@ rune:level(27) rune:magicLevel(5) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) -rune:isBlocking(true) -- True = Solid / False = Creature +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() diff --git a/data/scripts/runes/fire_wall.lua b/data/scripts/runes/fire_wall.lua index a9b7696c3c3..66a8da38b81 100644 --- a/data/scripts/runes/fire_wall.lua +++ b/data/scripts/runes/fire_wall.lua @@ -24,5 +24,5 @@ rune:level(33) rune:magicLevel(6) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) -rune:isBlocking(true) -- True = Solid / False = Creature +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() diff --git a/data/scripts/runes/great_fireball.lua b/data/scripts/runes/great_fireball.lua index ca0285986d8..39fbca15811 100644 --- a/data/scripts/runes/great_fireball.lua +++ b/data/scripts/runes/great_fireball.lua @@ -30,5 +30,5 @@ rune:level(30) rune:magicLevel(4) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) -rune:isBlocking(true) -- True = Solid / False = Creature +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() diff --git a/data/scripts/runes/poison_bomb.lua b/data/scripts/runes/poison_bomb.lua index 117ac2c67e5..e220e4dc9ec 100644 --- a/data/scripts/runes/poison_bomb.lua +++ b/data/scripts/runes/poison_bomb.lua @@ -24,5 +24,5 @@ rune:level(25) rune:magicLevel(4) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) -rune:isBlocking(true) -- True = Solid / False = Creature +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() diff --git a/data/scripts/runes/poison_wall.lua b/data/scripts/runes/poison_wall.lua index 1937b305880..64911f93357 100644 --- a/data/scripts/runes/poison_wall.lua +++ b/data/scripts/runes/poison_wall.lua @@ -24,5 +24,5 @@ rune:level(29) rune:magicLevel(5) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) -rune:isBlocking(true) -- True = Solid / False = Creature +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() diff --git a/data/scripts/runes/stone_shower.lua b/data/scripts/runes/stone_shower.lua index b3cfbd5421b..8be7e96b0cc 100644 --- a/data/scripts/runes/stone_shower.lua +++ b/data/scripts/runes/stone_shower.lua @@ -30,4 +30,5 @@ rune:level(28) rune:magicLevel(4) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() diff --git a/data/scripts/runes/thunderstorm.lua b/data/scripts/runes/thunderstorm.lua index 54ee6ed9c60..d26978d7547 100644 --- a/data/scripts/runes/thunderstorm.lua +++ b/data/scripts/runes/thunderstorm.lua @@ -30,4 +30,5 @@ rune:level(28) rune:magicLevel(4) rune:cooldown(2 * 1000) rune:groupCooldown(2 * 1000) +rune:isBlocking(false) -- True = Solid / False = Creature rune:register() From 9859dc09dda3baedbf8c005a49521fd2e6ef86a8 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 20 Mar 2024 21:51:40 -0300 Subject: [PATCH 6/7] fix: weapons missile for chain and equip hotkey for two-handed (#2476) --- src/creatures/combat/combat.cpp | 2 +- src/game/game.cpp | 38 ++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 532f4d48bb1..3ad2b8610f0 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -946,7 +946,7 @@ void Combat::setupChain(const std::shared_ptr &weapon) { } const auto &weaponType = weapon->getWeaponType(); - if (weaponType == WEAPON_NONE || weaponType == WEAPON_SHIELD || weaponType == WEAPON_AMMO || weaponType == WEAPON_DISTANCE) { + if (weaponType == WEAPON_NONE || weaponType == WEAPON_SHIELD || weaponType == WEAPON_AMMO || weaponType == WEAPON_DISTANCE || weaponType == WEAPON_MISSILE) { return; } diff --git a/src/game/game.cpp b/src/game/game.cpp index 53e887c9096..7adaf196dff 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -3153,28 +3153,40 @@ void Game::playerEquipItem(uint32_t playerId, uint16_t itemId, bool hasTier /* = auto slotItem = player->getInventoryItem(slot); auto equipItem = searchForItem(backpack, it.id, hasTier, tier); + ReturnValue ret = RETURNVALUE_NOERROR; if (slotItem && slotItem->getID() == it.id && (!it.stackable || slotItem->getItemCount() == slotItem->getStackSize() || !equipItem)) { - internalMoveItem(slotItem->getParent(), player, CONST_SLOT_WHEREEVER, slotItem, slotItem->getItemCount(), nullptr); + ret = internalMoveItem(slotItem->getParent(), player, CONST_SLOT_WHEREEVER, slotItem, slotItem->getItemCount(), nullptr); g_logger().debug("Item {} was unequipped", slotItem->getName()); } else if (equipItem) { + // Shield slot item + const auto &rightItem = player->getInventoryItem(CONST_SLOT_RIGHT); + // Check Ammo item if (it.weaponType == WEAPON_AMMO) { - auto quiver = player->getInventoryItem(CONST_SLOT_RIGHT); - if (quiver && quiver->isQuiver()) { - internalMoveItem(equipItem->getParent(), quiver->getContainer(), 0, equipItem, equipItem->getItemCount(), nullptr); - return; + if (rightItem && rightItem->isQuiver()) { + ret = internalMoveItem(equipItem->getParent(), rightItem->getContainer(), 0, equipItem, equipItem->getItemCount(), nullptr); + } + } else { + const int32_t &slotPosition = equipItem->getSlotPosition(); + // Checks if a two-handed item is being equipped in the left slot when the right slot is already occupied and move to backpack + if (slotPosition & SLOTP_LEFT && rightItem && (slotPosition & SLOTP_TWO_HAND)) { + ret = internalCollectManagedItems(player, rightItem, getObjectCategory(rightItem), false); } - } - if (slotItem) { - internalMoveItem(slotItem->getParent(), player, INDEX_WHEREEVER, slotItem, slotItem->getItemCount(), nullptr); - g_logger().debug("Item {} was moved back to player", slotItem->getName()); - } + if (slotItem) { + ret = internalMoveItem(slotItem->getParent(), player, INDEX_WHEREEVER, slotItem, slotItem->getItemCount(), nullptr); + g_logger().debug("Item {} was moved back to player", slotItem->getName()); + } - auto ret = internalMoveItem(equipItem->getParent(), player, slot, equipItem, equipItem->getItemCount(), nullptr); - if (ret == RETURNVALUE_NOERROR) { - g_logger().debug("Item {} was equipped", equipItem->getName()); + ret = internalMoveItem(equipItem->getParent(), player, slot, equipItem, equipItem->getItemCount(), nullptr); + if (ret == RETURNVALUE_NOERROR) { + g_logger().debug("Item {} was equipped", equipItem->getName()); + } } } + + if (ret != RETURNVALUE_NOERROR) { + player->sendCancelMessage(ret); + } } void Game::playerMove(uint32_t playerId, Direction direction) { From 198f79b7e135b5d60d6f93319f80802e48aad1ec Mon Sep 17 00:00:00 2001 From: Elson Costa Date: Thu, 21 Mar 2024 09:04:42 -0300 Subject: [PATCH 7/7] fix: removed error message 'monster with name not exist' in console (#2471) --- src/creatures/combat/combat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 3ad2b8610f0..cf98fcb6a7b 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -2131,7 +2131,7 @@ void Combat::applyExtensions(std::shared_ptr caster, std::shared_ptrgetSkillLevel(SKILL_CRITICAL_HIT_CHANCE); bonus = player->getSkillLevel(SKILL_CRITICAL_HIT_DAMAGE); - if (target) { + if (target && target->getMonster()) { uint16_t playerCharmRaceid = player->parseRacebyCharm(CHARM_LOW, false, 0); if (playerCharmRaceid != 0) { const auto mType = g_monsters().getMonsterType(target->getName());