#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();
}