diff --git a/config.lua.dist b/config.lua.dist index bed040e0d6a..0507b652e29 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -212,6 +212,8 @@ wheelAtelierRevealGreaterCost = 6000000 familiarTime = 30 partyAutoShareExperience = true +-- partyShareRangeMultiplier: the range of the party share experience, default 3/2 (1.5) +partyShareRangeMultiplier = 1.5 partyShareLootBoosts = false partyShareLootBoostsDimishingFactor = 0.7 diff --git a/data-otservbr-global/lib/core/storages.lua b/data-otservbr-global/lib/core/storages.lua index 69f1d7f7948..6ce29967451 100644 --- a/data-otservbr-global/lib/core/storages.lua +++ b/data-otservbr-global/lib/core/storages.lua @@ -106,7 +106,6 @@ Storage = { -- unused ExerciseDummyExhaust = 30029, SamsOldBackpack = 30030, SamsOldBackpackDoor = 30031, - StrawberryCupcake = 30032, ChayenneReward = 30033, SwampDiggingTimeout = 30034, HydraEggQuest = 30035, @@ -125,8 +124,6 @@ Storage = { Navigator = 30048, DwarvenLegs = 30049, PrinceDrazzakTime = 30050, - LemonCupcake = 30052, - BlueberryCupcake = 30053, -- Reserved in Global.Storage.FamiliarSummonEvent10 = 30054 -- Reserved in Global.Storage.FamiliarSummonEvent60 = 30055 ChayenneKeyTime = 30056, diff --git a/data-otservbr-global/npc/asnarus.lua b/data-otservbr-global/npc/asnarus.lua index a733d90834b..3992d513e9b 100644 --- a/data-otservbr-global/npc/asnarus.lua +++ b/data-otservbr-global/npc/asnarus.lua @@ -56,7 +56,7 @@ npcConfig.shop = { { itemName = "animate dead rune", clientId = 3203, buy = 375 }, { itemName = "arrow", clientId = 3447, buy = 2 }, { itemName = "blue quiver", clientId = 35848, buy = 400 }, - { itemName = "bolt", clientId = 3483, buy = 4 }, + { itemName = "bolt", clientId = 3446, buy = 4 }, { itemName = "bow", clientId = 3350, buy = 400, sell = 100 }, { itemName = "bowl of terror sweat", clientId = 20204, sell = 500 }, { itemName = "broken visor", clientId = 20184, sell = 1900 }, diff --git a/data-otservbr-global/npc/hireling.lua b/data-otservbr-global/npc/hireling.lua index 145d846bd7e..aad7785079d 100644 --- a/data-otservbr-global/npc/hireling.lua +++ b/data-otservbr-global/npc/hireling.lua @@ -228,7 +228,7 @@ function createHirelingType(HirelingName) }, ["distance"] = { { itemName = "arrow", clientId = 3447, buy = 2 }, - { itemName = "bolt", clientId = 3483, buy = 4 }, + { itemName = "bolt", clientId = 3446, buy = 4 }, { itemName = "bow", clientId = 3350, buy = 400, sell = 100 }, { itemName = "crossbow", clientId = 3349, buy = 500, sell = 120 }, { itemName = "crystalline arrow", clientId = 15793, buy = 450 }, diff --git a/data-otservbr-global/scripts/actions/other/cup_cakes.lua b/data-otservbr-global/scripts/actions/other/cup_cakes.lua deleted file mode 100644 index a9d94dbaacd..00000000000 --- a/data-otservbr-global/scripts/actions/other/cup_cakes.lua +++ /dev/null @@ -1,51 +0,0 @@ -local data = { - [28484] = { - Type = "mana", - ExhaustStor = Storage.BlueberryCupcake, - timestamp = 10, - }, - [28485] = { - Type = "health", - ExhaustStor = Storage.StrawberryCupcake, - timestamp = 10, - }, - [28486] = { - Type = "skill", - ExhaustStor = Storage.LemonCupcake, - timestamp = 10, - }, -} - -local lemon = Condition(CONDITION_ATTRIBUTES) -lemon:setParameter(CONDITION_PARAM_TICKS, 60 * 60 * 1000) -lemon:setParameter(CONDITION_PARAM_SKILL_DISTANCE, 10) - -local cupCakes = Action() - -function cupCakes.onUse(player, item, fromPos, itemEx, toPos) - local foundItem = data[item.itemid] - if not foundItem then - return - end - if (player:getStorageValue(foundItem.ExhaustStor)) < os.time() then - if foundItem.Type == "mana" then - player:addMana(player:getMaxMana()) - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your mana has been refilled.") - elseif foundItem.Type == "health" then - player:addHealth(player:getMaxHealth()) - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your health has been refilled.") - elseif foundItem.Type == "skill" then - player:addCondition(lemon) - player:sendTextMessage(MESSAGE_FAILURE, "You feel more focused.") - end - player:say("Mmmm.", TALKTYPE_MONSTER_SAY) - item:remove(1) - player:setStorageValue(foundItem.ExhaustStor, os.time() + (foundItem.timestamp * 60)) - else - player:sendTextMessage(MESSAGE_FAILURE, "You need to wait before using it again.") - end - return true -end - -cupCakes:id(28484, 28485, 28486) -cupCakes:register() diff --git a/data/scripts/actions/items/blueberry_cupcake.lua b/data/scripts/actions/items/blueberry_cupcake.lua new file mode 100644 index 00000000000..f645e852101 --- /dev/null +++ b/data/scripts/actions/items/blueberry_cupcake.lua @@ -0,0 +1,18 @@ +local blueberryCupcake = Action() + +function blueberryCupcake.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if player:hasExhaustion("blueberry-cupcake-cooldown") then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to wait before using it again.") + return true + end + + player:addMana(player:getMaxMana()) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your mana has been refilled.") + player:say("Mmmm.", TALKTYPE_MONSTER_SAY) + player:setExhaustion("blueberry-cupcake-cooldown", 10 * 60) + item:remove(1) + return true +end + +blueberryCupcake:id(28484) +blueberryCupcake:register() diff --git a/data/scripts/actions/items/lemon_cupcake.lua b/data/scripts/actions/items/lemon_cupcake.lua new file mode 100644 index 00000000000..3cf085d8ad8 --- /dev/null +++ b/data/scripts/actions/items/lemon_cupcake.lua @@ -0,0 +1,24 @@ +local distanceCondition = Condition(CONDITION_ATTRIBUTES) +distanceCondition:setParameter(CONDITION_PARAM_BUFF_SPELL, 1) +distanceCondition:setParameter(CONDITION_PARAM_TICKS, 60 * 60 * 1000) +distanceCondition:setParameter(CONDITION_PARAM_SKILL_DISTANCE, 10) +distanceCondition:setParameter(CONDITION_PARAM_FORCEUPDATE, true) + +local lemonCupcake = Action() + +function lemonCupcake.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if player:hasExhaustion("lemon-cupcake-cooldown") then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to wait before using it again.") + return true + end + + player:addCondition(distanceCondition) + player:sendTextMessage(MESSAGE_FAILURE, "You feel more focused.") + player:say("Mmmm.", TALKTYPE_MONSTER_SAY) + player:setExhaustion("lemon-cupcake-cooldown", 10 * 60) + item:remove(1) + return true +end + +lemonCupcake:id(28486) +lemonCupcake:register() diff --git a/data/scripts/actions/items/potions.lua b/data/scripts/actions/items/potions.lua index 02e92349363..473796d79df 100644 --- a/data/scripts/actions/items/potions.lua +++ b/data/scripts/actions/items/potions.lua @@ -89,10 +89,13 @@ function flaskPotion.onUse(player, item, fromPosition, target, toPosition, isHot local deactivatedFlasks = player:kv():get("talkaction.potions.flask") or false if not deactivatedFlasks then local container = Container(item:getParent().uid) - local inbox = player:getSlotItem(CONST_SLOT_STORE_INBOX) - - if fromPosition.x == CONTAINER_POSITION and container ~= inbox and container:getEmptySlots() ~= 0 then - container:addItem(potion.flask, 1) + if container then + local storeInbox = player:getSlotItem(CONST_SLOT_STORE_INBOX) + if fromPosition.x == CONTAINER_POSITION and container ~= storeInbox and container:getEmptySlots() ~= 0 then + container:addItem(potion.flask, 1) + else + player:addItem(potion.flask, 1) + end else Game.createItem(potion.flask, 1, fromPosition) end diff --git a/data/scripts/actions/items/strawberry_cupcake.lua b/data/scripts/actions/items/strawberry_cupcake.lua new file mode 100644 index 00000000000..7ee7ec75764 --- /dev/null +++ b/data/scripts/actions/items/strawberry_cupcake.lua @@ -0,0 +1,18 @@ +local strawberryCupcake = Action() + +function strawberryCupcake.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if player:hasExhaustion("strawberry-cupcake-cooldown") then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You need to wait before using it again.") + return true + end + + player:addHealth(player:getMaxHealth()) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your health has been refilled.") + player:say("Mmmm.", TALKTYPE_MONSTER_SAY) + player:setExhaustion("strawberry-cupcake-cooldown", 10 * 60) + item:remove(1) + return true +end + +strawberryCupcake:id(28485) +strawberryCupcake:register() diff --git a/data/scripts/spells/conjuring/conjure_diamond_arrow.lua b/data/scripts/spells/conjuring/conjure_diamond_arrow.lua deleted file mode 100644 index 2ab4bbe0647..00000000000 --- a/data/scripts/spells/conjuring/conjure_diamond_arrow.lua +++ /dev/null @@ -1,21 +0,0 @@ -local spell = Spell("instant") - -function spell.onCastSpell(creature, variant) - return creature:conjureItem(0, 25757, 100, CONST_ME_MAGIC_BLUE) -end - -spell:group("support") -spell:id(192) -spell:name("Conjure Diamond Arrow") -spell:words("exevo gran con hur") -spell:cooldown(2 * 1000) -spell:groupCooldown(2 * 1000) -spell:level(150) -spell:mana(1000) -spell:soul(0) -spell:isPremium(true) -spell:isSelfTarget(true) -spell:isAggressive(false) -spell:vocation("paladin;true", "royal paladin;true") -spell:needLearn(false) -spell:register() diff --git a/data/scripts/spells/conjuring/conjure_spectral_bolt.lua b/data/scripts/spells/conjuring/conjure_spectral_bolt.lua deleted file mode 100644 index 336eb423139..00000000000 --- a/data/scripts/spells/conjuring/conjure_spectral_bolt.lua +++ /dev/null @@ -1,21 +0,0 @@ -local spell = Spell("instant") - -function spell.onCastSpell(creature, variant) - return creature:conjureItem(0, 35902, 100, CONST_ME_MAGIC_BLUE) -end - -spell:group("support") -spell:id(193) -spell:name("Conjure Spectral Bolt") -spell:words("exevo gran con vis") -spell:cooldown(2 * 1000) -spell:groupCooldown(2 * 1000) -spell:level(150) -spell:mana(1000) -spell:soul(0) -spell:isPremium(true) -spell:isSelfTarget(true) -spell:isAggressive(false) -spell:vocation("paladin;true", "royal paladin;true") -spell:needLearn(false) -spell:register() diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp index 07e5093b632..4abf29c04cb 100644 --- a/src/config/config_enums.hpp +++ b/src/config/config_enums.hpp @@ -179,6 +179,7 @@ enum ConfigKey_t : uint16_t { OWNER_NAME, PARALLELISM, PARTY_AUTO_SHARE_EXPERIENCE, + PARTY_SHARE_RANGE_MULTIPLIER, PARTY_LIST_MAX_DISTANCE, PARTY_SHARE_LOOT_BOOSTS_DIMINISHING_FACTOR, PARTY_SHARE_LOOT_BOOSTS, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index c375d7c3d8d..8d4ba7a77da 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -318,6 +318,7 @@ bool ConfigManager::load() { loadIntConfig(L, STAMINA_PZ_GAIN, "staminaPzGain", 1); loadIntConfig(L, STAMINA_TRAINER_DELAY, "staminaTrainerDelay", 5); loadIntConfig(L, STAMINA_TRAINER_GAIN, "staminaTrainerGain", 1); + loadFloatConfig(L, PARTY_SHARE_RANGE_MULTIPLIER, "partyShareRangeMultiplier", 1.5f); loadIntConfig(L, START_STREAK_LEVEL, "startStreakLevel", 0); loadIntConfig(L, STATUSQUERY_TIMEOUT, "statusTimeout", 5000); loadIntConfig(L, STORE_COIN_PACKET, "coinPacketSize", 25); diff --git a/src/creatures/players/grouping/party.cpp b/src/creatures/players/grouping/party.cpp index 880fc77594f..c7d6fd48363 100644 --- a/src/creatures/players/grouping/party.cpp +++ b/src/creatures/players/grouping/party.cpp @@ -491,6 +491,10 @@ SharedExpStatus_t Party::getMemberSharedExperienceStatus(std::shared_ptr return SHAREDEXP_OK; } +float Party::shareRangeMultiplier() const { + return g_configManager().getFloat(PARTY_SHARE_RANGE_MULTIPLIER, __FUNCTION__); +} + uint32_t Party::getHighestLevel() { auto leader = getLeader(); if (!leader) { @@ -507,7 +511,7 @@ uint32_t Party::getHighestLevel() { } uint32_t Party::getMinLevel() { - return static_cast(std::ceil((static_cast(getHighestLevel()) * 2) / 3)); + return static_cast(std::ceil(static_cast(getHighestLevel()) / shareRangeMultiplier())); } uint32_t Party::getLowestLevel() { @@ -525,7 +529,7 @@ uint32_t Party::getLowestLevel() { } uint32_t Party::getMaxLevel() { - return static_cast(std::floor((static_cast(getLowestLevel()) * 3) / 2)); + return static_cast(std::floor(static_cast(getLowestLevel()) * shareRangeMultiplier())); } bool Party::isPlayerActive(std::shared_ptr player) { @@ -533,7 +537,6 @@ bool Party::isPlayerActive(std::shared_ptr player) { if (it == ticksMap.end()) { return false; } - uint64_t timeDiff = OTSYS_TIME() - it->second; return timeDiff <= 2 * 60 * 1000; } diff --git a/src/creatures/players/grouping/party.hpp b/src/creatures/players/grouping/party.hpp index a356d1a032b..5da0f4e0647 100644 --- a/src/creatures/players/grouping/party.hpp +++ b/src/creatures/players/grouping/party.hpp @@ -133,6 +133,7 @@ class Party : public SharedObject { uint32_t getLowestLevel(); uint32_t getMinLevel(); uint32_t getMaxLevel(); + float shareRangeMultiplier() const; std::map ticksMap; diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 592db179071..855b48a782b 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -657,6 +657,11 @@ class Player final : public Creature, public Cylinder, public Bankable { return loginPosition; } const Position &getTemplePosition() const { + if (!town) { + static auto emptyPosition = Position(); + return emptyPosition; + } + return town->getTemplePosition(); } std::shared_ptr getTown() const { diff --git a/src/game/bank/bank.cpp b/src/game/bank/bank.cpp index 94f3cb3ae1e..4430cf11ed9 100644 --- a/src/game/bank/bank.cpp +++ b/src/game/bank/bank.cpp @@ -102,10 +102,12 @@ bool Bank::transferTo(const std::shared_ptr destination, uint64_t amount) if (destinationPlayer != nullptr) { auto name = asLowerCaseString(destinationPlayer->getName()); replaceString(name, " ", ""); + if (deniedNames.contains(name)) { g_logger().warn("Bank::transferTo: denied name: {}", name); return false; } + if (destinationPlayer->getTown()->getID() < g_configManager().getNumber(MIN_TOWN_ID_TO_BANK_TRANSFER, __FUNCTION__)) { g_logger().warn("Bank::transferTo: denied town: {}", destinationPlayer->getTown()->getID()); return false;