#include "mod_shared_kill_credit.h" #include "Config.h" #include "Creature.h" #include "Group.h" #include "ObjectAccessor.h" #include "Player.h" #include "ScriptMgr.h" void SharedKillCredit::LoadConfig() { _enabled = sConfigMgr->GetOption("SharedKillCredit.Enable", true); } void SharedKillCredit::RecordDamage(Unit* attacker, Unit* victim) { if (!_enabled || !attacker || !victim || !victim->IsCreature()) return; Player* player = attacker->IsPlayer() ? attacker->ToPlayer() : attacker->GetCharmerOrOwnerPlayerOrPlayerItself(); if (!player) return; std::lock_guard lock(_mutex); _taggersByCreature[victim->GetGUID()].insert(player->GetGUID()); } void SharedKillCredit::RewardTaggers(Unit* victim) { if (!_enabled || !victim) return; Creature* creature = victim->ToCreature(); if (!creature) return; std::unordered_set taggers; { std::lock_guard lock(_mutex); auto it = _taggersByCreature.find(creature->GetGUID()); if (it == _taggersByCreature.end()) return; taggers = std::move(it->second); _taggersByCreature.erase(it); } // Players credited through the normal tap/group reward path (KillRewarder) // must not be credited again here, or their quest kill counters would be // double-incremented. ObjectGuid const recipient = creature->GetLootRecipientGUID(); ObjectGuid::LowType const recipientGroup = creature->GetLootRecipientGroupGUID(); for (ObjectGuid const& taggerGuid : taggers) { if (taggerGuid == recipient) continue; Player* tagger = ObjectAccessor::FindConnectedPlayer(taggerGuid); if (!tagger || !tagger->IsInWorld()) continue; if (recipientGroup && tagger->GetGroup() && tagger->GetGroup()->GetGUID().GetCounter() == recipientGroup) continue; // Give the same nearby-at-death eligibility that group members already // get for a shared kill, rather than rewarding a tagger who has long // since left the area. if (!tagger->IsAtGroupRewardDistance(creature)) continue; tagger->KilledMonster(creature->GetCreatureTemplate(), creature->GetGUID()); } } void SharedKillCredit::ForgetCreature(ObjectGuid const& creatureGuid) { std::lock_guard lock(_mutex); _taggersByCreature.erase(creatureGuid); } class SharedKillCredit_Unit : public UnitScript { public: SharedKillCredit_Unit() : UnitScript("SharedKillCredit_Unit", true, { UNITHOOK_ON_DAMAGE, UNITHOOK_ON_UNIT_DEATH }) { } void OnDamage(Unit* attacker, Unit* victim, uint32& /*damage*/) override { sSharedKillCredit->RecordDamage(attacker, victim); } void OnUnitDeath(Unit* unit, Unit* /*killer*/) override { sSharedKillCredit->RewardTaggers(unit); } }; class SharedKillCredit_AllCreature : public AllCreatureScript { public: SharedKillCredit_AllCreature() : AllCreatureScript("SharedKillCredit_AllCreature") { } void OnCreatureRemoveWorld(Creature* creature) override { sSharedKillCredit->ForgetCreature(creature->GetGUID()); } }; class SharedKillCredit_World : public WorldScript { public: SharedKillCredit_World() : WorldScript("SharedKillCredit_World") { } void OnBeforeConfigLoad(bool /*reload*/) override { sSharedKillCredit->LoadConfig(); } }; void AddSC_mod_shared_kill_credit() { new SharedKillCredit_Unit(); new SharedKillCredit_AllCreature(); new SharedKillCredit_World(); }