diff --git a/data/events/scripts/party.lua b/data/events/scripts/party.lua index b27965994b8..b94613c070a 100644 --- a/data/events/scripts/party.lua +++ b/data/events/scripts/party.lua @@ -66,25 +66,14 @@ function Party:onDisband() end function Party:onShareExperience(exp) - local sharedExperienceMultiplier = 1.20 --20% - local vocationsIds = {} + local uniqueVocationsCount = self:getUniqueVocationsCount() + local partySize = self:getMemberCount() + 1 - local vocationId = self:getLeader():getVocation():getBase():getId() - if vocationId ~= VOCATION_NONE then - table.insert(vocationsIds, vocationId) - end - - for _, member in ipairs(self:getMembers()) do - vocationId = member:getVocation():getBase():getId() - if not table.contains(vocationsIds, vocationId) and vocationId ~= VOCATION_NONE then - table.insert(vocationsIds, vocationId) - end - end - - local size = #vocationsIds - if size > 1 then - sharedExperienceMultiplier = 1.0 + ((size * (5 * (size - 1) + 10)) / 100) - end + -- Formula to calculate the % based on the vocations amount + local sharedExperienceMultiplier = ((0.1 * (uniqueVocationsCount ^ 2)) - (0.2 * uniqueVocationsCount) + 1.3) + -- Since the formula its non linear, we need to subtract 0.1 if all vocations are present, + -- because on all vocations the multiplier is 2.1 and it should be 2.0 + sharedExperienceMultiplier = partySize < 4 and sharedExperienceMultiplier or sharedExperienceMultiplier - 0.1 - return math.ceil((exp * sharedExperienceMultiplier) / (#self:getMembers() + 1)) + return math.ceil((exp * sharedExperienceMultiplier) / partySize) end diff --git a/src/creatures/players/grouping/party.cpp b/src/creatures/players/grouping/party.cpp index e63ca14b629..c04f8d57909 100644 --- a/src/creatures/players/grouping/party.cpp +++ b/src/creatures/players/grouping/party.cpp @@ -12,6 +12,7 @@ #include "config/configmanager.hpp" #include "creatures/creature.hpp" #include "creatures/players/player.hpp" +#include "creatures/players/vocations/vocation.hpp" #include "game/game.hpp" #include "game/movement/position.hpp" #include "lua/callbacks/event_callback.hpp" @@ -61,6 +62,25 @@ size_t Party::getInvitationCount() const { return inviteList.size(); } +uint8_t Party::getUniqueVocationsCount() const { + std::unordered_set uniqueVocations; + + for (const auto &player : getPlayers()) { + if (uniqueVocations.size() >= 4) { + break; + } + + const auto &vocation = player->getVocation(); + if (!vocation) { + continue; + } + + uniqueVocations.insert(vocation->getBaseId()); + } + + return uniqueVocations.size(); +} + void Party::disband() { if (!g_events().eventPartyOnDisband(getParty())) { return; @@ -504,9 +524,11 @@ void Party::shareExperience(uint64_t experience, const std::shared_ptr g_callbacks().executeCallback(EventCallback_t::partyOnShareExperience, &EventCallback::partyOnShareExperience, getParty(), std::ref(shareExperience)); for (const auto &member : getMembers()) { - member->onGainSharedExperience(shareExperience, target); + const auto memberStaminaBoost = static_cast(member->getStaminaXpBoost()) / 100; + member->onGainSharedExperience(shareExperience * memberStaminaBoost, target); } - leader->onGainSharedExperience(shareExperience, target); + const auto leaderStaminaBoost = static_cast(leader->getStaminaXpBoost()) / 100; + leader->onGainSharedExperience(shareExperience * leaderStaminaBoost, target); } bool Party::canUseSharedExperience(const std::shared_ptr &player) { diff --git a/src/creatures/players/grouping/party.hpp b/src/creatures/players/grouping/party.hpp index cef450c0c77..bc1ba77d135 100644 --- a/src/creatures/players/grouping/party.hpp +++ b/src/creatures/players/grouping/party.hpp @@ -40,6 +40,7 @@ class Party final : public SharedObject { std::vector> getInvitees(); size_t getMemberCount() const; size_t getInvitationCount() const; + uint8_t getUniqueVocationsCount() const; void disband(); bool invitePlayer(const std::shared_ptr &player); diff --git a/src/lua/functions/creatures/player/party_functions.cpp b/src/lua/functions/creatures/player/party_functions.cpp index 5c43593282a..a44e0129b94 100644 --- a/src/lua/functions/creatures/player/party_functions.cpp +++ b/src/lua/functions/creatures/player/party_functions.cpp @@ -24,6 +24,7 @@ void PartyFunctions::init(lua_State* L) { Lua::registerMethod(L, "Party", "getMemberCount", PartyFunctions::luaPartyGetMemberCount); Lua::registerMethod(L, "Party", "getInvitees", PartyFunctions::luaPartyGetInvitees); Lua::registerMethod(L, "Party", "getInviteeCount", PartyFunctions::luaPartyGetInviteeCount); + Lua::registerMethod(L, "Party", "getUniqueVocationsCount", PartyFunctions::luaPartyGetUniqueVocationsCount); Lua::registerMethod(L, "Party", "addInvite", PartyFunctions::luaPartyAddInvite); Lua::registerMethod(L, "Party", "removeInvite", PartyFunctions::luaPartyRemoveInvite); Lua::registerMethod(L, "Party", "addMember", PartyFunctions::luaPartyAddMember); @@ -162,6 +163,17 @@ int PartyFunctions::luaPartyGetInviteeCount(lua_State* L) { return 1; } +int PartyFunctions::luaPartyGetUniqueVocationsCount(lua_State* L) { + // party:getUniqueVocationsCount() + const auto &party = Lua::getUserdataShared(L, 1); + if (party) { + lua_pushnumber(L, party->getUniqueVocationsCount()); + } else { + lua_pushnil(L); + } + return 1; +} + int PartyFunctions::luaPartyAddInvite(lua_State* L) { // party:addInvite(player) const auto &player = Lua::getPlayer(L, 2); diff --git a/src/lua/functions/creatures/player/party_functions.hpp b/src/lua/functions/creatures/player/party_functions.hpp index 52801e349d6..92e629f71a1 100644 --- a/src/lua/functions/creatures/player/party_functions.hpp +++ b/src/lua/functions/creatures/player/party_functions.hpp @@ -22,6 +22,7 @@ class PartyFunctions { static int luaPartyGetMemberCount(lua_State* L); static int luaPartyGetInvitees(lua_State* L); static int luaPartyGetInviteeCount(lua_State* L); + static int luaPartyGetUniqueVocationsCount(lua_State* L); static int luaPartyAddInvite(lua_State* L); static int luaPartyRemoveInvite(lua_State* L); static int luaPartyAddMember(lua_State* L);