From 17650183411a9e9eb45f06fc437113b5eef68b04 Mon Sep 17 00:00:00 2001 From: valdzera <146901121+valdzera@users.noreply.github.com> Date: Tue, 19 Nov 2024 17:22:26 -0300 Subject: [PATCH 1/8] feat: specific meal purchase option for hireling (#3105) This update introduces a new feature for the hireling NPC, allowing players to choose specific meals for 90,000 gold, aligning with the latest global updates. The NPC now prompts players with options for a "specific" or "surprise" meal, guiding them through the selection process. If "specific" is chosen, players are presented with a list of available dishes. --- data-otservbr-global/npc/hireling.lua | 68 +++++++++++++++++++-------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/data-otservbr-global/npc/hireling.lua b/data-otservbr-global/npc/hireling.lua index ce5c6737e02..bfc9000ca0f 100644 --- a/data-otservbr-global/npc/hireling.lua +++ b/data-otservbr-global/npc/hireling.lua @@ -420,11 +420,13 @@ function createHirelingType(HirelingName) local TOPIC_FOOD = { SKILL_CHOOSE = 1301, + SKILL_SURPRISE = 1302, } local GREETINGS = { BANK = "Alright! What can I do for you and your bank business, |PLAYERNAME|?", - FOOD = "Hmm, yes! A variety of fine food awaits! However, a small expense of 15000 gold is expected to make these delicious masterpieces happen. Shall I?", + FOOD = [[Hmm, yes! A variety of fine food awaits! However, a small expense of 15000 gold is expected to make these delicious masterpieces happen. + For 90000 gold I will also serve you a specific dish. Just tell me what it shall be: a {specific} meal or a little {surprise}.]], STASH = "Of course, here is your stash! Well-maintained and neatly sorted for your convenience!", } @@ -513,7 +515,7 @@ function createHirelingType(HirelingName) return message end - local function deliverFood(npc, creature, food_id) + local function deliverFood(npc, creature, food_id, cost) local playerId = creature:getId() local player = Player(creature) local itType = ItemType(food_id) @@ -523,8 +525,8 @@ function createHirelingType(HirelingName) npcHandler:say("Sorry, but you don't have enough capacity.", npc, creature) elseif not inbox or #inboxItems >= inbox:getMaxCapacity() then player:getPosition():sendMagicEffect(CONST_ME_POFF) - npcHandler:say("Sorry, you don't have enough room on your inbox", npc, creature) - elseif not player:removeMoneyBank(15000) then + npcHandler:say("Sorry, you don't have enough room on your inbox.", npc, creature) + elseif not player:removeMoneyBank(cost) then npcHandler:say("Sorry, you don't have enough money.", npc, creature) else local message = getDeliveredMessageByFoodId(food_id) @@ -534,38 +536,66 @@ function createHirelingType(HirelingName) npcHandler:setTopic(playerId, TOPIC.SERVICES) end - local function cookFood(npc, creature) + local function cookFood(npc, creature, specificRequest) local playerId = creature:getId() - local random = math.random(6) - if random == 6 then - -- ask for preferred skill + if specificRequest then + npcHandler:say("Very well. You may choose one of the following: {chilli con carniphila}, {svargrond salmon filet}, {carrion casserole}, {consecrated beef}, {roasted wyvern wings}, {carrot pie}, {tropical marinated tiger}, or {delicatessen salad}.", npc, creature) npcHandler:setTopic(playerId, TOPIC_FOOD.SKILL_CHOOSE) - npcHandler:say("Yay! I have the ingredients to make a skill boost dish. Would you rather like to boost your {magic}, {melee}, {shielding} or {distance} skill?", npc, creature) - else -- deliver the random generated index - deliverFood(npc, creature, HIRELING_FOODS_IDS[random]) + else + npcHandler:say("Alright, let me astonish you. Shall I?", npc, creature) + deliverFood(npc, creature, HIRELING_FOODS_IDS[math.random(#HIRELING_FOODS_IDS)], 15000) end end local function handleFoodActions(npc, creature, message) local playerId = creature:getId() + if npcHandler:getTopic(playerId) == TOPIC.FOOD then - if MsgContains(message, "yes") then - cookFood(npc, creature) + if MsgContains(message, "specific") then + npcHandler:setTopic(playerId, TOPIC_FOOD.SPECIFIC) + npcHandler:say("Which specific meal would you like? Choices are: {chilli con carniphila}, {svargrond salmon filet}, {carrion casserole}, {consecrated beef}, {roasted wyvern wings}, {carrot pie}, {tropical marinated tiger}, or {delicatessen salad}.", npc, creature) + elseif MsgContains(message, "surprise") then + local random = math.random(6) + if random == 6 then + npcHandler:setTopic(playerId, TOPIC_FOOD.SKILL_CHOOSE) + npcHandler:say("Yay! I have the ingredients to make a skill boost dish. Would you rather like to boost your {magic}, {melee}, {shielding}, or {distance} skill?", npc, creature) + else + deliverFood(npc, creature, HIRELING_FOODS_IDS[random], 15000) + end + elseif MsgContains(message, "yes") then + deliverFood(npc, creature, HIRELING_FOODS_IDS[math.random(#HIRELING_FOODS_IDS)], 15000) elseif MsgContains(message, "no") then npcHandler:setTopic(playerId, TOPIC.SERVICES) npcHandler:say("Alright then, ask me for other {services}, if you want.", npc, creature) end elseif npcHandler:getTopic(playerId) == TOPIC_FOOD.SKILL_CHOOSE then if MsgContains(message, "magic") then - deliverFood(npc, creature, HIRELING_FOODS_BOOST.MAGIC) + deliverFood(npc, creature, HIRELING_FOODS_BOOST.MAGIC, 15000) elseif MsgContains(message, "melee") then - deliverFood(npc, creature, HIRELING_FOODS_BOOST.MELEE) + deliverFood(npc, creature, HIRELING_FOODS_BOOST.MELEE, 15000) elseif MsgContains(message, "shielding") then - deliverFood(npc, creature, HIRELING_FOODS_BOOST.SHIELDING) + deliverFood(npc, creature, HIRELING_FOODS_BOOST.SHIELDING, 15000) elseif MsgContains(message, "distance") then - deliverFood(npc, creature, HIRELING_FOODS_BOOST.DISTANCE) + deliverFood(npc, creature, HIRELING_FOODS_BOOST.DISTANCE, 15000) + else + npcHandler:say("Sorry, but you must choose a valid skill class. Would you like to boost your {magic}, {melee}, {shielding}, or {distance} skill?", npc, creature) + end + elseif npcHandler:getTopic(playerId) == TOPIC_FOOD.SPECIFIC then + local specificFoodOptions = { + ["chilli con carniphila"] = 29412, + ["svargrond salmon filet"] = 29413, + ["carrion casserole"] = 29414, + ["consecrated beef"] = 29415, + ["roasted wyvern wings"] = 29408, + ["carrot pie"] = 29409, + ["tropical marinated tiger"] = 29410, + ["delicatessen salad"] = 29411, + } + + if specificFoodOptions[message:lower()] then + deliverFood(npc, creature, specificFoodOptions[message:lower()], 90000) else - npcHandler:say("Sorry, but you must choose a valid skill class. Would you like to boost your {magic}, {melee}, {shielding} or {distance} skill?", npc, creature) + npcHandler:say("I'm sorry, but that's not a valid food option. Please choose from: {chilli con carniphila}, {svargrond salmon filet}, {carrion casserole}, {consecrated beef}, {roasted wyvern wings}, {carrot pie}, {tropical marinated tiger}, or {delicatessen salad}.", npc, creature) end end end @@ -656,7 +686,7 @@ function createHirelingType(HirelingName) end elseif npcHandler:getTopic(playerId) == TOPIC.BANK then enableBankSystem[playerId] = true - elseif npcHandler:getTopic(playerId) == TOPIC.FOOD or npcHandler:getTopic(playerId) == TOPIC_FOOD.SKILL_CHOOSE then + elseif npcHandler:getTopic(playerId) == TOPIC.FOOD or npcHandler:getTopic(playerId) == TOPIC_FOOD.SKILL_CHOOSE or npcHandler:getTopic(playerId) == TOPIC_FOOD.SPECIFIC then handleFoodActions(npc, creature, message) elseif npcHandler:getTopic(playerId) == TOPIC.GOODS then -- Ensures players cannot access other shop categories From 729387bc8b8a6171de32d936a6442cb285c9da42 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 20 Nov 2024 00:31:07 -0300 Subject: [PATCH 2/8] fix: lua getNumber overflow with "MoveEvent::EquipItem" function (#3136) Fixed overflow with "MoveEvent::EquipItem" and added imbuement shrine to canary temple --- data-canary/scripts/actions/objects/imbuement_shrine.lua | 2 ++ data/events/scripts/player.lua | 3 ++- src/lua/functions/lua_functions_loader.hpp | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/data-canary/scripts/actions/objects/imbuement_shrine.lua b/data-canary/scripts/actions/objects/imbuement_shrine.lua index 71e3776f2f0..11d75150cf8 100644 --- a/data-canary/scripts/actions/objects/imbuement_shrine.lua +++ b/data-canary/scripts/actions/objects/imbuement_shrine.lua @@ -13,5 +13,7 @@ function imbuement.onUse(player, item, fromPosition, target, toPosition, isHotke return true end +imbuement:position({ x = 1943, y = 1340, z = 7 }, 25061) + imbuement:id(25060, 25061, 25103, 25104, 25202, 25174, 25175, 25182, 25183) imbuement:register() diff --git a/data/events/scripts/player.lua b/data/events/scripts/player.lua index 78653733b58..c526553132d 100644 --- a/data/events/scripts/player.lua +++ b/data/events/scripts/player.lua @@ -315,7 +315,8 @@ function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder, end -- Reward System - if toPosition.x == CONTAINER_POSITION then + local containerThing = tile and tile:getItemByType(ITEM_TYPE_CONTAINER) + if containerThing and toPosition.x == CONTAINER_POSITION then local containerId = toPosition.y - 64 local container = self:getContainerById(containerId) if not container then diff --git a/src/lua/functions/lua_functions_loader.hpp b/src/lua/functions/lua_functions_loader.hpp index fffc7e5b355..68cfeb45c51 100644 --- a/src/lua/functions/lua_functions_loader.hpp +++ b/src/lua/functions/lua_functions_loader.hpp @@ -63,7 +63,7 @@ class Lua { static void setCreatureMetatable(lua_State* L, int32_t index, const std::shared_ptr &creature); template - static T getNumber(lua_State* L, int32_t arg) { + static T getNumber(lua_State* L, int32_t arg, std::source_location location = std::source_location::current()) { auto number = lua_tonumber(L, arg); if constexpr (std::is_enum_v) { @@ -73,7 +73,7 @@ class Lua { if constexpr (std::is_integral_v) { if constexpr (std::is_unsigned_v) { if (number < 0) { - g_logger().debug("[{}] overflow, setting to default unsigned value (0)", __FUNCTION__); + g_logger().debug("[{}] overflow, setting to default unsigned value (0), called line: {}:{}, in {}", __FUNCTION__, location.line(), location.column(), location.function_name()); return T(0); } } From 854f60c30dd72eb4a512bceaf83470e764969545 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 20 Nov 2024 11:05:22 -0300 Subject: [PATCH 3/8] fix: remove duplicate "update impact tracker" for elemental damage (#3137) It's already send here: https://github.com/opentibiabr/canary/blob/729387bc8b8a6171de32d936a6442cb285c9da42/src/game/game.cpp#L7375 --- src/game/game.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index cde008d4f65..2484702d758 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -7428,10 +7428,6 @@ bool Game::combatChangeHealth(const std::shared_ptr &attacker, const s target->drainHealth(attacker, realDamage); if (realDamage > 0 && targetMonster) { - if (attackerPlayer && attackerPlayer->getPlayer()) { - attackerPlayer->updateImpactTracker(damage.secondary.type, damage.secondary.value); - } - if (targetMonster->israndomStepping()) { targetMonster->setIgnoreFieldDamage(true); } From efbac6c806284aa3f3f7d448fbe6ada5acee2937 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 20 Nov 2024 12:54:20 -0300 Subject: [PATCH 4/8] fix: quiver replacement logic and shield-weapon equip handling (#3138) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Added logic to replace an existing quiver when equipping a new one, ensuring proper unequip and feedback to the player. • Refactored shield equip logic to properly handle scenarios where a two-handed weapon is equipped in the left slot, preventing unnecessary unequips. • Improved equip flow to ensure consistent behavior for different weapon and item types, avoiding conflicts between equipped items. --- src/game/game.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/game/game.cpp b/src/game/game.cpp index 2484702d758..068ecad4a50 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -3409,18 +3409,22 @@ void Game::playerEquipItem(uint32_t playerId, uint16_t itemId, bool hasTier /* = const auto &slotItem = player->getInventoryItem(slot); const 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)) { 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) { if (rightItem && rightItem->isQuiver()) { ret = internalMoveItem(equipItem->getParent(), rightItem->getContainer(), 0, equipItem, equipItem->getItemCount(), nullptr); } } else { + const auto &leftItem = player->getInventoryItem(CONST_SLOT_LEFT); + 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 ( @@ -3429,10 +3433,35 @@ void Game::playerEquipItem(uint32_t playerId, uint16_t itemId, bool hasTier /* = && rightItem && !(it.weaponType == WEAPON_DISTANCE) && !rightItem->isQuiver() + && (!leftItem || leftItem->getWeaponType() != WEAPON_DISTANCE) ) { ret = internalCollectManagedItems(player, rightItem, getObjectCategory(rightItem), false); } + // Check if trying to equip a quiver while another quiver is already equipped in the right slot + if (slot == CONST_SLOT_RIGHT && rightItem && rightItem->isQuiver() && it.isQuiver()) { + // Replace the existing quiver with the new one + ret = internalMoveItem(rightItem->getParent(), player, INDEX_WHEREEVER, rightItem, rightItem->getItemCount(), nullptr); + if (ret == RETURNVALUE_NOERROR) { + g_logger().debug("Quiver {} was unequipped to equip new quiver", rightItem->getName()); + } else { + player->sendCancelMessage(ret); + return; + } + } else { + // Check if trying to equip a shield while a two-handed weapon is equipped in the left slot + if (slot == CONST_SLOT_RIGHT && leftItem && leftItem->getSlotPosition() & SLOTP_TWO_HAND) { + // Unequip the two-handed weapon from the left slot + ret = internalMoveItem(leftItem->getParent(), player, INDEX_WHEREEVER, leftItem, leftItem->getItemCount(), nullptr); + if (ret == RETURNVALUE_NOERROR) { + g_logger().debug("Two-handed weapon {} was unequipped to equip shield", leftItem->getName()); + } else { + player->sendCancelMessage(ret); + return; + } + } + } + if (slotItem) { ret = internalMoveItem(slotItem->getParent(), player, INDEX_WHEREEVER, slotItem, slotItem->getItemCount(), nullptr); g_logger().debug("Item {} was moved back to player", slotItem->getName()); From ed8abb6b714bf9ae7cbd0293ce744dfeb88e73c6 Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 21 Nov 2024 15:17:27 -0300 Subject: [PATCH 5/8] fix: initialize totalCost correctly and refactor blessing purchase logic (#3142) This fixes the initialization of the `totalCost` variable and refactors the blessing purchase logic. Improvements include replacing string concatenation with `string.format` for more efficient formatting, as well as adjustments for better code clarity and readability. The code is now more organized, and the calculation error has been fixed. --- data/libs/systems/blessing.lua | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/data/libs/systems/blessing.lua b/data/libs/systems/blessing.lua index fee0e6fe8e8..f5403fbb07b 100644 --- a/data/libs/systems/blessing.lua +++ b/data/libs/systems/blessing.lua @@ -258,8 +258,9 @@ Blessings.BuyAllBlesses = function(player) local hasToF = Blessings.Config.HasToF and player:hasBlessing(1) or true local missingBless = player:getBlessings(nil, donthavefilter) local missingBlessAmt = #missingBless + (hasToF and 0 or 1) - local totalCost - for i, bless in ipairs(missingBless) do + local totalCost = 0 + + for _, bless in ipairs(missingBless) do totalCost = totalCost + Blessings.getBlessingCost(player:getLevel(), true, bless.id >= 7) end @@ -274,19 +275,19 @@ Blessings.BuyAllBlesses = function(player) end if player:removeMoneyBank(totalCost) then - metrics.addCounter("balance_decrease", remainsPrice, { + metrics.addCounter("balance_decrease", totalCost, { player = player:getName(), context = "blessings", }) - for i, v in ipairs(missingBless) do - player:addBlessing(v.id, 1) + for _, bless in ipairs(missingBless) do + player:addBlessing(bless.id, 1) end - player:sendCancelMessage("You received the remaining " .. missingBlessAmt .. " blesses for a total of " .. totalCost .. " gold.") + player:sendCancelMessage(string.format("You received the remaining %d blesses for a total of %d gold.", missingBlessAmt, totalCost)) player:getPosition():sendMagicEffect(CONST_ME_HOLYAREA) else - player:sendCancelMessage("You don't have enough money. You need " .. totalCost .. " to buy all blesses.", cid) + player:sendCancelMessage(string.format("You don't have enough money. You need %d to buy all blesses.", totalCost)) player:getPosition():sendMagicEffect(CONST_ME_POFF) end From 6253d64f70b5109c4895479a42734a3f7b2f8d10 Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 21 Nov 2024 16:05:39 -0300 Subject: [PATCH 6/8] fix: prevent teleportation (#3143) This fixes an issue where the player was teleported even when a Lua script was blocking the action. --- src/game/movement/teleport.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/game/movement/teleport.cpp b/src/game/movement/teleport.cpp index 368bcf6e476..d11552220a3 100644 --- a/src/game/movement/teleport.cpp +++ b/src/game/movement/teleport.cpp @@ -80,29 +80,27 @@ void Teleport::addThing(int32_t, const std::shared_ptr &thing) { // Prevent infinity loop if (checkInfinityLoop(destTile)) { const Position &pos = getPosition(); - g_logger().warn("[Teleport:addThing] - " - "Infinity loop teleport at position: {}", - pos.toString()); + g_logger().warn("[Teleport:addThing] - Infinity loop teleport at position: {}", pos.toString()); return; } const MagicEffectClasses effect = Item::items[id].magicEffect; - if (const std::shared_ptr &creature = thing->getCreature()) { + if (const auto &creature = thing->getCreature()) { Position origPos = creature->getPosition(); g_game().internalCreatureTurn(creature, origPos.x > destPos.x ? DIRECTION_WEST : DIRECTION_EAST); - g_dispatcher().addWalkEvent([=] { - g_game().map.moveCreature(creature, destTile); - if (effect != CONST_ME_NONE) { - g_game().addMagicEffect(origPos, effect); - g_game().addMagicEffect(destTile->getPosition(), effect); - } - }); + g_game().map.moveCreature(creature, destTile); + + if (effect != CONST_ME_NONE) { + g_game().addMagicEffect(origPos, effect); + g_game().addMagicEffect(destTile->getPosition(), effect); + } } else if (const auto &item = thing->getItem()) { if (effect != CONST_ME_NONE) { g_game().addMagicEffect(destTile->getPosition(), effect); g_game().addMagicEffect(item->getPosition(), effect); } + g_game().internalMoveItem(getTile(), destTile, INDEX_WHEREEVER, item, item->getItemCount(), nullptr); } } From db2611b1f2a97caeaf96ff722fc2dc059d4f7d06 Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 21 Nov 2024 16:12:29 -0300 Subject: [PATCH 7/8] fix: item usage mechanics to obtain Phantasmal Jade (#3112) This fixes the item usage mechanics for obtaining the Phantasmal Jade mount. It ensures that the correct number of items are used, and the mount is granted when all requirements are met. Additionally, it automates the registration of item IDs to simplify the code and reduce redundancy. Close #3100 --- .../soul_war/action-reward_soul_war.lua | 32 ------------- .../items/usable_phantasmal_jade_items.lua | 45 +++++++++++++++++++ 2 files changed, 45 insertions(+), 32 deletions(-) create mode 100644 data/scripts/actions/items/usable_phantasmal_jade_items.lua diff --git a/data-otservbr-global/scripts/quests/soul_war/action-reward_soul_war.lua b/data-otservbr-global/scripts/quests/soul_war/action-reward_soul_war.lua index fae3fc59794..652a74af84b 100644 --- a/data-otservbr-global/scripts/quests/soul_war/action-reward_soul_war.lua +++ b/data-otservbr-global/scripts/quests/soul_war/action-reward_soul_war.lua @@ -26,35 +26,3 @@ end rewardSoulWar:position({ x = 33620, y = 31400, z = 10 }) rewardSoulWar:register() - -local phantasmalJadeMount = Action() - -function phantasmalJadeMount.onUse(player, item, fromPosition, target, toPosition, isHotkey) - local soulWarQuest = player:soulWarQuestKV() - if soulWarQuest:get("panthasmal-jade-mount") then - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You already have Phantasmal Jade mount!") - return true - end - - if table.contains({ 34072, 34073, 34074 }, item.itemid) then - if player:getItemCount(34072) >= 4 and player:getItemCount(34073) == 1 and player:getItemCount(34074) == 1 then - player:removeItem(34072, 4) - player:removeItem(34073, 1) - player:removeItem(34074, 1) - player:addMount(167) - player:addAchievement("You got Horse Power") - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Congratulations! You won Phantasmal Jade mount.") - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Congratulations! You won You got Horse Power achievement.") - player:getPosition():sendMagicEffect(CONST_ME_HOLYDAMAGE) - soulWarQuest:set("panthasmal-jade-mount", true) - else - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You don't have the necessary items!") - player:getPosition():sendMagicEffect(CONST_ME_POFF) - end - end - - return true -end - -phantasmalJadeMount:id(34072, 34073, 34074) -phantasmalJadeMount:register() diff --git a/data/scripts/actions/items/usable_phantasmal_jade_items.lua b/data/scripts/actions/items/usable_phantasmal_jade_items.lua new file mode 100644 index 00000000000..8075125df25 --- /dev/null +++ b/data/scripts/actions/items/usable_phantasmal_jade_items.lua @@ -0,0 +1,45 @@ +local config = { + requiredItems = { + [34072] = { key = "spectral-horseshoes", count = 4 }, + [34073] = { key = "spectral-saddle", count = 1 }, + [34074] = { key = "spectral-horse-tac", count = 1 }, + }, + + mountId = 167, +} + +local usablePhantasmalJadeItems = Action() + +function usablePhantasmalJadeItems.onUse(player, item, fromPosition, target, toPosition, isHotkey) + local itemInfo = config.requiredItems[item:getId()] + if not itemInfo then + return true + end + + if player:hasMount(config.mountId) then + return true + end + + local currentCount = (player:kv():get(itemInfo.key) or 0) + 1 + player:kv():set(itemInfo.key, currentCount) + player:getPosition():sendMagicEffect(CONST_ME_HOLYDAMAGE) + item:remove(1) + + for _, info in pairs(config.requiredItems) do + if (player:kv():get(info.key) or 0) < info.count then + return true + end + end + + player:addMount(config.mountId) + player:addAchievement("Natural Born Cowboy") + player:addAchievement("You got Horse Power") + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Phantasmal jade is now yours!") + return true +end + +for itemId, _ in pairs(config.requiredItems) do + usablePhantasmalJadeItems:id(itemId) +end + +usablePhantasmalJadeItems:register() From 34b6fa8e08ee0bb397fe7583b985ea4455e5e345 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Fri, 22 Nov 2024 11:53:38 -0300 Subject: [PATCH 8/8] fix: boss lever check god access (#3141) Check god access instead of normal, to ensure that tutors also count towards the cooldown --- data/libs/functions/boss_lever.lua | 2 +- src/utils/pugicast.hpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/data/libs/functions/boss_lever.lua b/data/libs/functions/boss_lever.lua index 40bc8e0b4b0..ae8a89d0e54 100644 --- a/data/libs/functions/boss_lever.lua +++ b/data/libs/functions/boss_lever.lua @@ -177,7 +177,7 @@ function BossLever:onUse(player) return true end - local isAccountNormal = creature:getAccountType() == ACCOUNT_TYPE_NORMAL + local isAccountNormal = creature:getAccountType() < ACCOUNT_TYPE_GAMEMASTER if isAccountNormal and creature:getLevel() < self.requiredLevel then local message = "All players need to be level " .. self.requiredLevel .. " or higher." creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, message) diff --git a/src/utils/pugicast.hpp b/src/utils/pugicast.hpp index b59e95d37ab..91043596605 100644 --- a/src/utils/pugicast.hpp +++ b/src/utils/pugicast.hpp @@ -38,14 +38,12 @@ namespace pugi { // If the string could not be parsed as the specified type if (errorCode == std::errc::invalid_argument) { // Throw an exception indicating that the argument is invalid - logError(fmt::format("Invalid argument {}", str)); - throw std::invalid_argument("Invalid argument: " + std::string(str)); + logError(fmt::format("[{}] Invalid argument {}", __FUNCTION__, str)); } // If the parsed value is out of range for the specified type else if (errorCode == std::errc::result_out_of_range) { // Throw an exception indicating that the result is out of range - logError(fmt::format("Result out of range: {}", str)); - throw std::out_of_range("Result out of range: " + std::string(str)); + logError(fmt::format("[{}] Result out of range: {}", __FUNCTION__, str)); } // Return a default value if no exception is thrown