From d36b1ea131c1cf1d5dcebf19315d871457602851 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Sat, 28 Oct 2023 00:34:40 -0700 Subject: [PATCH] fix: bestiary double counting in party --- data/libs/concoctions_lib.lua | 40 ++--- data/scripts/creatureevents/bestiary_kill.lua | 35 ----- .../scripts/creatureevents/bosstiary_kill.lua | 33 ---- src/creatures/creature.cpp | 22 +-- src/creatures/monsters/monsters.hpp | 10 +- src/creatures/players/grouping/party.hpp | 10 +- src/creatures/players/player.cpp | 143 +++++++++++------- src/creatures/players/player.hpp | 14 ++ src/lua/functions/core/game/lua_enums.cpp | 25 +++ src/lua/functions/core/game/lua_enums.hpp | 1 + src/utils/utils_definitions.hpp | 23 +++ 11 files changed, 193 insertions(+), 163 deletions(-) delete mode 100644 data/scripts/creatureevents/bestiary_kill.lua delete mode 100644 data/scripts/creatureevents/bosstiary_kill.lua diff --git a/data/libs/concoctions_lib.lua b/data/libs/concoctions_lib.lua index 0d8a6e6574a..72547a8a1ab 100644 --- a/data/libs/concoctions_lib.lua +++ b/data/libs/concoctions_lib.lua @@ -12,26 +12,26 @@ ConcoctionTickType = { Concoction = {} Concoction.__index = Concoction Concoction.Ids = { - KooldownAid = 36723, - StaminaExtension = 36725, - StrikeEnhancement = 36724, - CharmUpgrade = 36726, - WealthDuplex = 36727, - BestiaryBetterment = 36728, - FireResilience = 36729, - IceResilience = 36730, - EarthResilience = 36731, - EnergyResilience = 36732, - HolyResilience = 36733, - DeathResilience = 36734, - PhysicalResilience = 36735, - FireAmplification = 36736, - IceAmplification = 36737, - EarthAmplification = 36738, - EnergyAmplification = 36739, - HolyAmplification = 36740, - DeathAmplification = 36741, - PhysicalAmplification = 36742, + KooldownAid = Concoction_KooldownAid, + StaminaExtension = Concoction_StaminaExtension, + StrikeEnhancement = Concoction_StrikeEnhancement, + CharmUpgrade = Concoction_CharmUpgrade, + WealthDuplex = Concoction_WealthDuplex, + BestiaryBetterment = Concoction_BestiaryBetterment, + FireResilience = Concoction_FireResilience, + IceResilience = Concoction_IceResilience, + EarthResilience = Concoction_EarthResilience, + EnergyResilience = Concoction_EnergyResilience, + HolyResilience = Concoction_HolyResilience, + DeathResilience = Concoction_DeathResilience, + PhysicalResilience = Concoction_PhysicalResilience, + FireAmplification = Concoction_FireAmplification, + IceAmplification = Concoction_IceAmplification, + EarthAmplification = Concoction_EarthAmplification, + EnergyAmplification = Concoction_EnergyAmplification, + HolyAmplification = Concoction_HolyAmplification, + DeathAmplification = Concoction_DeathAmplification, + PhysicalAmplification = Concoction_PhysicalAmplification, } function Concoction.find(identifier) diff --git a/data/scripts/creatureevents/bestiary_kill.lua b/data/scripts/creatureevents/bestiary_kill.lua deleted file mode 100644 index a238124eacf..00000000000 --- a/data/scripts/creatureevents/bestiary_kill.lua +++ /dev/null @@ -1,35 +0,0 @@ -local bestiaryOnKill = CreatureEvent("BestiaryOnKill") -function bestiaryOnKill.onKill(player, creature, lastHit) - if not player:isPlayer() or not creature:isMonster() or creature:hasBeenSummoned() or creature:isPlayer() then - return true - end - - local mType = MonsterType(creature:getName()) - if not mType then - logger.error("[bestiaryOnKill.onKill] monster with name {} have wrong MonsterType", creature:getName()) - return true - end - - if mType:Bestiaryrace() == 0 then - return true - end - - local bestiaryBetterment = Concoction.find(Concoction.Ids.BestiaryBetterment) - if not bestiaryBetterment then - logger.warn("[BestiaryOnKill] - Could not find BestiaryBetterment concoction.") - end - for cid, damage in pairs(creature:getDamageMap()) do - local participant = Player(cid) - if participant and participant:isPlayer() then - local bestiaryMultiplier = (configManager.getNumber(configKeys.BESTIARY_KILL_MULTIPLIER) or 1) - if bestiaryBetterment and bestiaryBetterment:active(participant) then - bestiaryMultiplier = bestiaryMultiplier * bestiaryBetterment.config.multiplier - end - participant:addBestiaryKill(creature:getName(), bestiaryMultiplier) - end - end - - return true -end - -bestiaryOnKill:register() diff --git a/data/scripts/creatureevents/bosstiary_kill.lua b/data/scripts/creatureevents/bosstiary_kill.lua deleted file mode 100644 index 2a1139cd339..00000000000 --- a/data/scripts/creatureevents/bosstiary_kill.lua +++ /dev/null @@ -1,33 +0,0 @@ -local bosstiaryOnKill = CreatureEvent("BosstiaryOnKill") -function bosstiaryOnKill.onKill(player, creature, lastHit) - if not player:isPlayer() or not creature:isMonster() or creature:hasBeenSummoned() or creature:isPlayer() then - return true - end - - local mType = MonsterType(creature:getName()) - if not mType then - logger.error("[bosstiaryOnKill.onKill] monster with name {} have wrong MonsterType", creature:getName()) - return true - end - - if mType:bossRace() == nil or mType:bossRace() == "" then - return true - end - - local bosstiaryMultiplier = (configManager.getNumber(configKeys.BOSSTIARY_KILL_MULTIPLIER) or 1) - local killBonus = (configManager.getNumber(configKeys.BOOSTED_BOSS_KILL_BONUS) or 3) - for cid, damage in pairs(creature:getDamageMap()) do - local participant = Player(cid) - if participant and participant:isPlayer() then - if creature:getName():lower() == (Game.getBoostedBoss()):lower() then - participant:addBosstiaryKill(creature:getName(), bosstiaryMultiplier * killBonus) - else - participant:addBosstiaryKill(creature:getName(), bosstiaryMultiplier) - end - end - end - - return true -end - -bosstiaryOnKill:register() diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 2f855c6ac15..980bab34155 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -625,14 +625,6 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt void Creature::onDeath() { bool lastHitUnjustified = false; bool mostDamageUnjustified = false; - std::shared_ptr lastHitCreature = g_game().getCreatureByID(lastHitCreatureId); - std::shared_ptr lastHitCreatureMaster; - if (lastHitCreature) { - lastHitUnjustified = lastHitCreature->onKilledCreature(static_self_cast(), true); - lastHitCreatureMaster = lastHitCreature->getMaster(); - } else { - lastHitCreatureMaster = nullptr; - } std::shared_ptr mostDamageCreature = nullptr; @@ -674,13 +666,15 @@ void Creature::onDeath() { it.first->onGainExperience(it.second, getCreature()); } + std::shared_ptr mostDamageCreatureMaster = nullptr; if (mostDamageCreature) { - if (mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) { - auto mostDamageCreatureMaster = mostDamageCreature->getMaster(); - if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) { - mostDamageUnjustified = mostDamageCreature->onKilledCreature(static_self_cast(), false); - } - } + mostDamageCreatureMaster = mostDamageCreature->getMaster(); + mostDamageUnjustified = mostDamageCreature->onKilledCreature(getCreature(), false); + } + + std::shared_ptr lastHitCreature = g_game().getCreatureByID(lastHitCreatureId); + if (lastHitCreature && lastHitCreature != mostDamageCreature && lastHitCreature != mostDamageCreatureMaster) { + lastHitUnjustified = lastHitCreature->onKilledCreature(getCreature(), true); } bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified); diff --git a/src/creatures/monsters/monsters.hpp b/src/creatures/monsters/monsters.hpp index fd911c661f9..b334fab5120 100644 --- a/src/creatures/monsters/monsters.hpp +++ b/src/creatures/monsters/monsters.hpp @@ -185,15 +185,19 @@ class MonsterType { } float getHealthMultiplier() const { - return info.bosstiaryClass.empty() ? g_configManager().getFloat(RATE_MONSTER_HEALTH) : g_configManager().getFloat(RATE_BOSS_HEALTH); + return isBoss() ? g_configManager().getFloat(RATE_MONSTER_HEALTH) : g_configManager().getFloat(RATE_BOSS_HEALTH); } float getAttackMultiplier() const { - return info.bosstiaryClass.empty() ? g_configManager().getFloat(RATE_MONSTER_ATTACK) : g_configManager().getFloat(RATE_BOSS_ATTACK); + return isBoss() ? g_configManager().getFloat(RATE_MONSTER_ATTACK) : g_configManager().getFloat(RATE_BOSS_ATTACK); } float getDefenseMultiplier() const { - return info.bosstiaryClass.empty() ? g_configManager().getFloat(RATE_MONSTER_DEFENSE) : g_configManager().getFloat(RATE_BOSS_DEFENSE); + return isBoss() ? g_configManager().getFloat(RATE_MONSTER_DEFENSE) : g_configManager().getFloat(RATE_BOSS_DEFENSE); + } + + bool isBoss() const { + return !info.bosstiaryClass.empty(); } void loadLoot(const std::shared_ptr monsterType, LootBlock lootblock); diff --git a/src/creatures/players/grouping/party.hpp b/src/creatures/players/grouping/party.hpp index e7bc2c2fc55..3b09dfb05e3 100644 --- a/src/creatures/players/grouping/party.hpp +++ b/src/creatures/players/grouping/party.hpp @@ -35,6 +35,14 @@ class Party : public SharedObject { std::shared_ptr getLeader() const { return m_leader.lock(); } + std::vector> getPlayers() const { + std::vector> players; + for (auto &member : memberList) { + players.push_back(member); + } + players.push_back(getLeader()); + return players; + } std::vector> getMembers() { return memberList; } @@ -68,7 +76,7 @@ class Party : public SharedObject { void shareExperience(uint64_t experience, std::shared_ptr target = nullptr); bool setSharedExperience(std::shared_ptr player, bool sharedExpActive, bool silent = false); bool isSharedExperienceActive() const { - return sharedExpActive; + return sharedExpEnabled && sharedExpActive; } bool isSharedExperienceEnabled() const { return sharedExpEnabled; diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 1f7f9f088b0..9a8d99449c7 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -4583,75 +4583,104 @@ void Player::onTargetCreatureGainHealth(std::shared_ptr target, int32_ } } -bool Player::onKilledCreature(std::shared_ptr target, bool lastHit /* = true*/) { +bool Player::onKilledPlayer(const std::shared_ptr &target, bool lastHit) { bool unjustified = false; - - if (hasFlag(PlayerFlags_t::NotGenerateLoot)) { + if (target->getZoneType() == ZONE_PVP) { target->setDropLoot(false); - } - - Creature::onKilledCreature(target, lastHit); - - if (auto targetPlayer = target->getPlayer()) { - if (targetPlayer && targetPlayer->getZoneType() == ZONE_PVP) { - targetPlayer->setDropLoot(false); - targetPlayer->setSkillLoss(false); - } else if (!hasFlag(PlayerFlags_t::NotGainInFight) && !isPartner(targetPlayer)) { - if (!Combat::isInPvpZone(getPlayer(), targetPlayer) && hasAttacked(targetPlayer) && !targetPlayer->hasAttacked(getPlayer()) && !isGuildMate(targetPlayer) && targetPlayer != getPlayer()) { - if (targetPlayer->hasKilled(getPlayer())) { - for (auto &kill : targetPlayer->unjustifiedKills) { - if (kill.target == getGUID() && kill.unavenged) { - kill.unavenged = false; - auto it = attackedSet.find(targetPlayer->guid); - attackedSet.erase(it); - break; - } + target->setSkillLoss(false); + } else if (!hasFlag(PlayerFlags_t::NotGainInFight) && !isPartner(target)) { + if (!Combat::isInPvpZone(getPlayer(), target) && hasAttacked(target) && !target->hasAttacked(getPlayer()) && !isGuildMate(target) && target != getPlayer()) { + if (target->hasKilled(getPlayer())) { + for (auto &kill : target->unjustifiedKills) { + if (kill.target == getGUID() && kill.unavenged) { + kill.unavenged = false; + auto it = attackedSet.find(target->guid); + attackedSet.erase(it); + break; } - } else if (targetPlayer->getSkull() == SKULL_NONE && !isInWar(targetPlayer)) { - unjustified = true; - addUnjustifiedDead(targetPlayer); } - - if (lastHit && hasCondition(CONDITION_INFIGHT)) { - pzLocked = true; - std::shared_ptr condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_INFIGHT, g_configManager().getNumber(WHITE_SKULL_TIME), 0); - addCondition(condition); - } - } - } - } else if (std::shared_ptr monster = target->getMonster()) { - // Access to the monster's map damage to check if the player attacked it - for (auto [playerId, damage] : monster->getDamageMap()) { - auto damagePlayer = g_game().getPlayerByID(playerId); - if (!damagePlayer) { - continue; + } else if (target->getSkull() == SKULL_NONE && !isInWar(target)) { + unjustified = true; + addUnjustifiedDead(target); } - // If the player is not in a party and sharing exp active and enabled - // And it's not the player killing the creature, then we ignore everything else - auto damageParty = damagePlayer->getParty(); - if (static_self_cast()->getID() != damagePlayer->getID() && (!damageParty || !damageParty->isSharedExperienceActive() || !damageParty->isSharedExperienceEnabled())) { - continue; + if (lastHit && hasCondition(CONDITION_INFIGHT)) { + pzLocked = true; + std::shared_ptr condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_INFIGHT, g_configManager().getNumber(WHITE_SKULL_TIME), 0); + addCondition(condition); } + } + } + return unjustified; +} - const auto &taskSlot = damagePlayer->getTaskHuntingWithCreature(monster->getRaceId()); - if (!taskSlot || monster->isSummon()) { - continue; - } +void Player::addHuntingTaskKill(const std::shared_ptr &mType) { + const auto &taskSlot = getTaskHuntingWithCreature(mType->info.raceid); + if (!taskSlot) { + return; + } - if (const auto &option = g_ioprey().getTaskRewardOption(taskSlot)) { - taskSlot->currentKills += 1; - if ((taskSlot->upgrade && taskSlot->currentKills >= option->secondKills) || (!taskSlot->upgrade && taskSlot->currentKills >= option->firstKills)) { - taskSlot->state = PreyTaskDataState_Completed; - std::string message = "You succesfully finished your hunting task. Your reward is ready to be claimed!"; - damagePlayer->sendTextMessage(MESSAGE_STATUS, message); - } - damagePlayer->reloadTaskSlot(taskSlot->id); - } + if (const auto &option = g_ioprey().getTaskRewardOption(taskSlot)) { + taskSlot->currentKills += 1; + if ((taskSlot->upgrade && taskSlot->currentKills >= option->secondKills) || (!taskSlot->upgrade && taskSlot->currentKills >= option->firstKills)) { + taskSlot->state = PreyTaskDataState_Completed; + std::string message = "You succesfully finished your hunting task. Your reward is ready to be claimed!"; + sendTextMessage(MESSAGE_STATUS, message); } + reloadTaskSlot(taskSlot->id); } +} - return unjustified; +void Player::addBestiaryKill(const std::shared_ptr &mType) { + if (mType->isBoss()) { + return; + } + uint32_t kills = g_configManager().getNumber(BESTIARY_KILL_MULTIPLIER); + if (isConcoctionActive(Concoction_t::BestiaryBetterment)) { + kills *= 2; + } + g_iobestiary().addBestiaryKill(getPlayer(), mType, kills); +} + +void Player::addBosstiaryKill(const std::shared_ptr &mType) { + if (!mType->isBoss()) { + return; + } + uint32_t kills = g_configManager().getNumber(BOSSTIARY_KILL_MULTIPLIER); + + g_ioBosstiary().addBosstiaryKill(getPlayer(), mType, kills); +} + +bool Player::onKilledMonster(const std::shared_ptr &monster, bool lastHit) { + if (lastHit || monster->isSummon()) { + return false; + } + auto party = getParty(); + auto participants = party && party->isSharedExperienceActive() ? party->getPlayers() : std::vector> { getPlayer() }; + auto mType = monster->getMonsterType(); + for (const auto &player : participants) { + player->addHuntingTaskKill(mType); + player->addBestiaryKill(mType); + player->addBosstiaryKill(mType); + } + + return false; +} + +bool Player::onKilledCreature(std::shared_ptr target, bool lastHit /* = true*/) { + if (hasFlag(PlayerFlags_t::NotGenerateLoot)) { + target->setDropLoot(false); + } + + Creature::onKilledCreature(target, lastHit); + + if (auto targetPlayer = target->getPlayer()) { + return onKilledPlayer(targetPlayer, lastHit); + } else if (auto targetMonster = target->getMonster()) { + return onKilledMonster(targetMonster, lastHit); + } + + return false; } void Player::gainExperience(uint64_t gainExp, std::shared_ptr target) { diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 791f696148c..13ca06a339c 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -2487,6 +2487,14 @@ class Player final : public Creature, public Cylinder, public Bankable { std::map getActiveConcoctions() const { return activeConcoctions; } + bool isConcoctionActive(Concoction_t concotion) const { + uint16_t itemId = static_cast(concotion); + if (!activeConcoctions.contains(itemId)) { + return false; + } + auto timeLeft = activeConcoctions.at(itemId); + return timeLeft > 0; + } bool checkAutoLoot() const { const bool autoLoot = g_configManager().getBoolean(AUTOLOOT) && getStorageValue(STORAGEVALUE_AUTO_LOOT) != 0; @@ -2589,6 +2597,12 @@ class Player final : public Creature, public Cylinder, public Bankable { void internalAddThing(std::shared_ptr thing) override; void internalAddThing(uint32_t index, std::shared_ptr thing) override; + void addHuntingTaskKill(const std::shared_ptr &mType); + void addBestiaryKill(const std::shared_ptr &mType); + void addBosstiaryKill(const std::shared_ptr &mType); + bool onKilledPlayer(const std::shared_ptr &target, bool lastHit); + bool onKilledMonster(const std::shared_ptr &target, bool lastHit); + phmap::flat_hash_set attackedSet; phmap::flat_hash_set VIPList; diff --git a/src/lua/functions/core/game/lua_enums.cpp b/src/lua/functions/core/game/lua_enums.cpp index fc1586f3363..f462aaae26a 100644 --- a/src/lua/functions/core/game/lua_enums.cpp +++ b/src/lua/functions/core/game/lua_enums.cpp @@ -108,6 +108,7 @@ void LuaEnums::init(lua_State* L) { initSoundEnums(L); initWheelEnums(L); initAttributeConditionSubIdEnums(L); + initConcoctionsEnum(L); } void LuaEnums::initOthersEnums(lua_State* L) { @@ -446,6 +447,30 @@ void LuaEnums::initAttributeConditionSubIdEnums(lua_State* L) { } } +void LuaEnums::initConcoctionsEnum(lua_State* L) { + std::string luaNamespace = "Concoction_"; + registerEnumNamespace(L, luaNamespace, Concoction_t::KooldownAid); + registerEnumNamespace(L, luaNamespace, Concoction_t::StaminaExtension); + registerEnumNamespace(L, luaNamespace, Concoction_t::StrikeEnhancement); + registerEnumNamespace(L, luaNamespace, Concoction_t::CharmUpgrade); + registerEnumNamespace(L, luaNamespace, Concoction_t::WealthDuplex); + registerEnumNamespace(L, luaNamespace, Concoction_t::BestiaryBetterment); + registerEnumNamespace(L, luaNamespace, Concoction_t::FireResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::IceResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::EarthResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::EnergyResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::HolyResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::DeathResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::PhysicalResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::FireAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::IceAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::EarthAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::EnergyAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::HolyAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::DeathAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::PhysicalAmplification); +} + void LuaEnums::initConstMeEnums(lua_State* L) { registerEnum(L, CONST_ME_NONE); registerEnum(L, CONST_ME_DRAWBLOOD); diff --git a/src/lua/functions/core/game/lua_enums.hpp b/src/lua/functions/core/game/lua_enums.hpp index 055741b3f24..448e09fb647 100644 --- a/src/lua/functions/core/game/lua_enums.hpp +++ b/src/lua/functions/core/game/lua_enums.hpp @@ -35,6 +35,7 @@ class LuaEnums final : LuaScriptInterface { static void initConditionIdEnums(lua_State* L); static void initConditionParamEnums(lua_State* L); static void initAttributeConditionSubIdEnums(lua_State* L); + static void initConcoctionsEnum(lua_State* L); static void initConstMeEnums(lua_State* L); static void initConstAniEnums(lua_State* L); static void initConstPropEnums(lua_State* L); diff --git a/src/utils/utils_definitions.hpp b/src/utils/utils_definitions.hpp index e84dcf58a64..25fce70f47a 100644 --- a/src/utils/utils_definitions.hpp +++ b/src/utils/utils_definitions.hpp @@ -762,3 +762,26 @@ enum class AttrSubId_t { BloodRageProtector, Sharpshooter, }; + +enum Concoction_t : uint16_t { + KooldownAid = 36723, + StaminaExtension = 36725, + StrikeEnhancement = 36724, + CharmUpgrade = 36726, + WealthDuplex = 36727, + BestiaryBetterment = 36728, + FireResilience = 36729, + IceResilience = 36730, + EarthResilience = 36731, + EnergyResilience = 36732, + HolyResilience = 36733, + DeathResilience = 36734, + PhysicalResilience = 36735, + FireAmplification = 36736, + IceAmplification = 36737, + EarthAmplification = 36738, + EnergyAmplification = 36739, + HolyAmplification = 36740, + DeathAmplification = 36741, + PhysicalAmplification = 36742, +};