Core/Loot: Implemented personal loot and tag sharing for non-boss loot

Port From (https://github.com/TrinityCore/TrinityCore/commit/133334a902b705dae6f7e92bb1009b84cf1c51d2)
This commit is contained in:
hondacrx
2022-10-18 16:07:00 -04:00
parent e78c71784c
commit 9b62b83984
23 changed files with 298 additions and 340 deletions
+50 -40
View File
@@ -21,14 +21,14 @@ using Game.Groups;
using Game.Maps;
using Game.Scenarios;
using System.Collections.Generic;
using System.Linq;
namespace Game.Entities
{
public class KillRewarder
{
Player _killer;
Player[] _killers;
Unit _victim;
Group _group;
float _groupRate;
Player _maxNotGrayMember;
uint _count;
@@ -39,11 +39,10 @@ namespace Game.Entities
bool _isBattleground;
bool _isPvP;
public KillRewarder(Player killer, Unit victim, bool isBattleground)
public KillRewarder(Player[] killers, Unit victim, bool isBattleground)
{
_killer = killer;
_killers = killers;
_victim = victim;
_group = killer.GetGroup();
_groupRate = 1.0f;
_maxNotGrayMember = null;
_count = 0;
@@ -60,27 +59,37 @@ namespace Game.Entities
// or if its owned by player and its not a vehicle
else if (victim.GetCharmerOrOwnerGUID().IsPlayer())
_isPvP = !victim.IsVehicle();
_InitGroupData();
}
public void Reward()
{
// 3. Reward killer (and group, if necessary).
if (_group)
// 3.1. If killer is in group, reward group.
_RewardGroup();
else
SortedSet<Group> processedGroups = new();
foreach (Player killer in _killers)
{
// 3.2. Reward single killer (not group case).
// 3.2.1. Initialize initial XP amount based on killer's level.
_InitXP(_killer);
// To avoid unnecessary calculations and calls,
// proceed only if XP is not ZERO or player is not on Battleground
// (Battlegroundrewards only XP, that's why).
if (!_isBattleground || _xp != 0)
// 3.2.2. Reward killer.
_RewardPlayer(_killer, false);
_InitGroupData(killer);
// 3. Reward killer (and group, if necessary).
Group group = killer.GetGroup();
if (group != null)
{
if (!processedGroups.Add(group))
continue;
// 3.1. If killer is in group, reward group.
_RewardGroup(group, killer);
}
else
{
// 3.2. Reward single killer (not group case).
// 3.2.1. Initialize initial XP amount based on killer's level.
_InitXP(killer, killer);
// To avoid unnecessary calculations and calls,
// proceed only if XP is not ZERO or player is not on battleground
// (battleground rewards only XP, that's why).
if (!_isBattleground || _xp != 0)
// 3.2.2. Reward killer.
_RewardPlayer(killer, false);
}
}
// 5. Credit instance encounter.
@@ -99,25 +108,26 @@ namespace Game.Entities
uint guildId = victim.GetMap().GetOwnerGuildId();
var guild = Global.GuildMgr.GetGuildById(guildId);
if (guild != null)
guild.UpdateCriteria(CriteriaType.KillCreature, victim.GetEntry(), 1, 0, victim, _killer);
guild.UpdateCriteria(CriteriaType.KillCreature, victim.GetEntry(), 1, 0, victim, _killers.First());
Scenario scenario = victim.GetScenario();
if (scenario != null)
scenario.UpdateCriteria(CriteriaType.KillCreature, victim.GetEntry(), 1, 0, victim, _killer);
scenario.UpdateCriteria(CriteriaType.KillCreature, victim.GetEntry(), 1, 0, victim, _killers.First());
}
}
void _InitGroupData()
void _InitGroupData(Player killer)
{
if (_group)
Group group = killer.GetGroup();
if (group != null)
{
// 2. In case when player is in group, initialize variables necessary for group calculations:
for (GroupReference refe = _group.GetFirstMember(); refe != null; refe = refe.Next())
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.Next())
{
Player member = refe.GetSource();
if (member)
if (member != null)
{
if (_killer == member || (member.IsAtGroupRewardDistance(_victim) && member.IsAlive()))
if (killer == member || (member.IsAtGroupRewardDistance(_victim) && member.IsAlive()))
{
uint lvl = member.GetLevel();
// 2.1. _count - number of alive group members within reward distance;
@@ -143,14 +153,14 @@ namespace Game.Entities
_count = 1;
}
void _InitXP(Player player)
void _InitXP(Player player, Player killer)
{
// Get initial value of XP for kill.
// XP is given:
// * on Battlegrounds;
// * otherwise, not in PvP;
// * not if killer is on vehicle.
if (_isBattleground || (!_isPvP && _killer.GetVehicle() == null))
if (_isBattleground || (!_isPvP && killer.GetVehicle() == null))
_xp = Formulas.XPGain(player, _victim, _isBattleground);
}
@@ -164,7 +174,7 @@ namespace Game.Entities
void _RewardXP(Player player, float rate)
{
uint xp = _xp;
if (_group)
if (player.GetGroup() != null)
{
// 4.2.1. If player is in group, adjust XP:
// * set to 0 if player's level is more than maximum level of not gray member;
@@ -188,7 +198,7 @@ namespace Game.Entities
Pet pet = player.GetPet();
if (pet)
// 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
pet.GivePetXP(_group ? xp / 2 : xp);
pet.GivePetXP(player.GetGroup() != null ? xp / 2 : xp);
}
}
@@ -202,7 +212,7 @@ namespace Game.Entities
void _RewardKillCredit(Player player)
{
// 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse).
if (!_group || player.IsAlive() || player.GetCorpse() == null)
if (player.GetGroup() == null || player.IsAlive() || player.GetCorpse() == null)
{
Creature target = _victim.ToCreature();
if (target != null)
@@ -228,7 +238,7 @@ namespace Game.Entities
// Give reputation and kill credit only in PvE.
if (!_isPvP || _isBattleground)
{
float rate = _group ? _groupRate * player.GetLevel() / _sumLevel : 1.0f;
float rate = player.GetGroup() != null ? _groupRate * player.GetLevel() / _sumLevel : 1.0f;
if (_xp != 0)
// 4.2. Give XP.
_RewardXP(player, rate);
@@ -241,34 +251,34 @@ namespace Game.Entities
}
}
void _RewardGroup()
void _RewardGroup(Group group, Player killer)
{
if (_maxLevel != 0)
{
if (_maxNotGrayMember != null)
// 3.1.1. Initialize initial XP amount based on maximum level of group member,
// for whom victim is not gray.
_InitXP(_maxNotGrayMember);
_InitXP(_maxNotGrayMember, killer);
// To avoid unnecessary calculations and calls,
// proceed only if XP is not ZERO or player is not on Battleground
// (Battlegroundrewards only XP, that's why).
if (!_isBattleground || _xp != 0)
{
bool isDungeon = !_isPvP && CliDB.MapStorage.LookupByKey(_killer.GetMapId()).IsDungeon();
bool isDungeon = !_isPvP && CliDB.MapStorage.LookupByKey(killer.GetMapId()).IsDungeon();
if (!_isBattleground)
{
// 3.1.2. Alter group rate if group is in raid (not for Battlegrounds).
bool isRaid = !_isPvP && CliDB.MapStorage.LookupByKey(_killer.GetMapId()).IsRaid() && _group.IsRaidGroup();
bool isRaid = !_isPvP && CliDB.MapStorage.LookupByKey(killer.GetMapId()).IsRaid() && group.IsRaidGroup();
_groupRate = Formulas.XPInGroupRate(_count, isRaid);
}
// 3.1.3. Reward each group member (even dead or corpse) within reward distance.
for (GroupReference refe = _group.GetFirstMember(); refe != null; refe = refe.Next())
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.Next())
{
Player member = refe.GetSource();
if (member)
{
// Killer may not be at reward distance, check directly
if (_killer == member || member.IsAtGroupRewardDistance(_victim))
if (killer == member || member.IsAtGroupRewardDistance(_victim))
_RewardPlayer(member, isDungeon);
}
}
@@ -44,11 +44,6 @@ namespace Game.Entities
}
}
public void RewardPlayerAndGroupAtKill(Unit victim, bool isBattleground)
{
new KillRewarder(this, victim, isBattleground).Reward();
}
public void RewardPlayerAndGroupAtEvent(uint creature_id, WorldObject pRewardSource)
{
if (pRewardSource == null)
+1 -10
View File
@@ -3126,7 +3126,7 @@ namespace Game.Entities
public bool IsAllowedToLoot(Creature creature)
{
if (!creature.IsDead() || !creature.IsDamageEnoughForLootingAndReward())
if (!creature.IsDead())
return false;
if (HasPendingBind())
@@ -3139,15 +3139,6 @@ namespace Game.Entities
if (!loot.HasAllowedLooter(GetGUID()) || (!loot.HasItemForAll() && !loot.HasItemFor(this))) // no loot in creature for this player
return false;
if (loot.loot_type == LootType.Skinning)
return creature.GetLootRecipientGUID() == GetGUID();
Group thisGroup = GetGroup();
if (!thisGroup)
return this == creature.GetLootRecipient();
else if (thisGroup != creature.GetLootRecipientGroup())
return false;
switch (loot.GetLootMethod())
{
case LootMethod.PersonalLoot:// @todo implement personal loot (http://wow.gamepedia.com/Loot#Personal_Loot)