Core/Loot: Initial support for personal loot in gameobjects (non-instanced content)

Port From (https://github.com/TrinityCore/TrinityCore/commit/641390dca2329041a6ef513c2c9f7b28d42d2762)
This commit is contained in:
hondacrx
2022-10-18 14:22:16 -04:00
parent 80009bfa8d
commit e78c71784c
6 changed files with 103 additions and 32 deletions
@@ -151,6 +151,8 @@ namespace Game.Chat
uint displayId = gameObjectInfo.displayId;
string name = gameObjectInfo.name;
uint lootId = gameObjectInfo.GetLootId();
if (type == GameObjectTypes.Chest && lootId == 0)
lootId = gameObjectInfo.Chest.chestPersonalLoot;
// If we have a real object, send some info about it
if (thisGO != null)
+76 -17
View File
@@ -482,6 +482,8 @@ namespace Game.Entities
m_lootState = LootState.Ready;
loot = null;
m_personalLoot.Clear();
m_unique_users.Clear();
m_usetimes = 0;
AddToObjectUpdateIfNeeded();
break;
default:
@@ -711,6 +713,8 @@ namespace Game.Entities
m_lootState = LootState.Ready;
loot = null;
m_personalLoot.Clear();
m_unique_users.Clear();
m_usetimes = 0;
AddToObjectUpdateIfNeeded();
}
break;
@@ -797,6 +801,8 @@ namespace Game.Entities
loot = null;
m_personalLoot.Clear();
m_unique_users.Clear();
m_usetimes = 0;
// Do not delete chests or goobers that are not consumed on loot, while still allowing them to despawn when they expire if summoned
bool isSummonedAndExpired = (GetOwner() != null || GetSpellId() != 0) && m_respawnTime == 0;
@@ -1346,7 +1352,10 @@ namespace Game.Entities
return false;
// scan GO chest with loot including quest items
if (target.GetQuestStatus(GetGoInfo().Chest.questID) == QuestStatus.Incomplete || LootStorage.Gameobject.HaveQuestLootForPlayer(GetGoInfo().GetLootId(), target))
if (target.GetQuestStatus(GetGoInfo().Chest.questID) == QuestStatus.Incomplete
|| LootStorage.Gameobject.HaveQuestLootForPlayer(GetGoInfo().Chest.chestLoot, target)
|| LootStorage.Gameobject.HaveQuestLootForPlayer(GetGoInfo().Chest.chestPersonalLoot, target)
|| LootStorage.Gameobject.HaveQuestLootForPlayer(GetGoInfo().Chest.chestPushLoot, target))
{
Battleground bg = target.GetBattleground();
if (bg)
@@ -1657,19 +1666,16 @@ namespace Game.Entities
return;
GameObjectTemplate info = GetGoInfo();
if (GetLootState() == LootState.Ready)
if (loot == null && info.GetLootId() != 0)
{
uint lootId = info.GetLootId();
if (lootId != 0)
if (info.GetLootId() != 0)
{
SetLootGenerationTime();
Group group = player.GetGroup();
bool groupRules = group != null && info.Chest.usegrouplootrules != 0;
loot = new Loot(GetMap(), GetGUID(), LootType.Chest, groupRules ? group : null);
loot.SetDungeonEncounterId(info.Chest.DungeonEncounter);
loot.FillLoot(lootId, LootStorage.Gameobject, player, !groupRules, false, GetLootMode(), GetMap().GetDifficultyLootItemContext());
loot.FillLoot(info.GetLootId(), LootStorage.Gameobject, player, !groupRules, false, GetLootMode(), GetMap().GetDifficultyLootItemContext());
if (GetLootMode() > 0)
{
@@ -1681,24 +1687,59 @@ namespace Game.Entities
/// @todo possible must be moved to loot release (in different from linked triggering)
if (info.Chest.triggeredEvent != 0)
GameEvents.Trigger(info.Chest.triggeredEvent, player, this);
// triggering linked GO
uint trapEntry = info.Chest.linkedTrap;
if (trapEntry != 0)
TriggeringLinkedGameObject(trapEntry, player);
}
else if (!m_personalLoot.ContainsKey(player.GetGUID()))
{
if (info.Chest.chestPersonalLoot != 0)
{
Log.outDebug(LogFilter.Spells, $"Chest ScriptStart id {info.Chest.triggeredEvent} for GO {GetSpawnId()}");
GameEvents.Trigger(info.Chest.triggeredEvent, user, this);
Loot personalLoot = new(GetMap(), GetGUID(), LootType.Chest, null);
m_personalLoot[player.GetGUID()] = personalLoot;
personalLoot.SetDungeonEncounterId(info.Chest.DungeonEncounter);
personalLoot.FillLoot(info.Chest.chestPersonalLoot, LootStorage.Gameobject, player, true, false, GetLootMode(), GetMap().GetDifficultyLootItemContext());
if (GetLootMode() > 0)
{
GameObjectTemplateAddon addon = GetTemplateAddon();
if (addon != null)
personalLoot.GenerateMoneyLoot(addon.Mingold, addon.Maxgold);
}
}
}
if (!m_unique_users.Contains(player.GetGUID()) && info.GetLootId() == 0)
{
if (info.Chest.chestPushLoot != 0)
{
Loot pushLoot = new(GetMap(), GetGUID(), LootType.Chest, null);
pushLoot.FillLoot(info.Chest.chestPushLoot, LootStorage.Gameobject, player, true, false, GetLootMode(), GetMap().GetDifficultyLootItemContext());
pushLoot.AutoStore(player, ItemConst.NullBag, ItemConst.NullSlot);
}
if (info.Chest.triggeredEvent != 0)
GameEvents.Trigger(info.Chest.triggeredEvent, player, this);
// triggering linked GO
uint trapEntry = info.Chest.linkedTrap;
if (trapEntry != 0)
TriggeringLinkedGameObject(trapEntry, player);
SetLootState(LootState.Activated, player);
AddUniqueUse(player);
}
else
loot = GetLootForPlayer(player);
if (GetLootState() != LootState.Activated)
SetLootState(LootState.Activated, player);
// Send loot
if (loot != null)
player.SendLoot(loot);
Loot playerLoot = GetLootForPlayer(player);
if (playerLoot != null)
player.SendLoot(playerLoot);
break;
}
case GameObjectTypes.Trap: //6
@@ -2743,6 +2784,18 @@ namespace Game.Entities
}
}
public bool IsFullyLooted()
{
if (loot != null && !loot.IsLooted())
return false;
foreach (var (_, loot) in m_personalLoot)
if (!loot.IsLooted())
return false;
return true;
}
public void SetGoState(GameObjectState state)
{
GameObjectState oldState = GetGoState();
@@ -2880,6 +2933,15 @@ namespace Game.Entities
public bool IsLootAllowedFor(Player player)
{
Loot loot = GetLootForPlayer(player);
if (loot != null) // check only if loot was already generated
{
if (loot.IsLooted()) // nothing to loot or everything looted.
return false;
if (!loot.HasAllowedLooter(GetGUID()) || (!loot.HasItemForAll() && !loot.HasItemFor(player))) // no loot in chest for this player
return false;
}
if (m_lootRecipient.IsEmpty() && m_lootRecipientGroup.IsEmpty())
return true;
@@ -3365,8 +3427,6 @@ namespace Game.Entities
void AddLootMode(LootModes lootMode) { m_LootMode |= lootMode; }
void RemoveLootMode(LootModes lootMode) { m_LootMode &= ~lootMode; }
void ResetLootMode() { m_LootMode = LootModes.Default; }
public void SetLootGenerationTime() { m_lootGenerationTime = (uint)GameTime.GetGameTime(); }
public uint GetLootGenerationTime() { return m_lootGenerationTime; }
public void AddToSkillupList(ObjectGuid PlayerGuid) { m_SkillupList.Add(PlayerGuid); }
public bool IsInSkillupList(ObjectGuid PlayerGuid)
@@ -3495,7 +3555,6 @@ namespace Game.Entities
ObjectGuid m_lootRecipient;
ObjectGuid m_lootRecipientGroup;
LootModes m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
uint m_lootGenerationTime;
long m_packedRotation;
Quaternion m_localRotation;
public Position StationaryPosition { get; set; }
+5 -5
View File
@@ -18,11 +18,11 @@
using Framework.Collections;
using Framework.Constants;
using Framework.Database;
using Framework.Dynamic;
using Framework.IO;
using Game.Conditions;
using Game.DataStorage;
using Game.Entities;
using Game.Loots;
using Game.Mails;
using Game.Maps;
using Game.Misc;
@@ -30,7 +30,6 @@ using Game.Movement;
using Game.Scripting;
using Game.Spells;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
@@ -4687,10 +4686,11 @@ namespace Game
case GameObjectTypes.Chest:
{
// scan GO chest with loot including quest items
uint lootId = pair.Value.GetLootId();
// find quest loot for GO
if (pair.Value.Chest.questID != 0 || Loots.LootStorage.Gameobject.HaveQuestLootFor(lootId))
if (pair.Value.Chest.questID != 0
|| LootStorage.Gameobject.HaveQuestLootFor(pair.Value.Chest.chestLoot)
|| LootStorage.Gameobject.HaveQuestLootFor(pair.Value.Chest.chestPersonalLoot)
|| LootStorage.Gameobject.HaveQuestLootFor(pair.Value.Chest.chestPushLoot))
break;
continue;
+1 -3
View File
@@ -296,10 +296,8 @@ namespace Game
else
go.SetLootState(LootState.Ready);
}
else
else if (go.IsFullyLooted())
go.SetLootState(LootState.JustDeactivated);
loot.Clear();
}
else
{
+1 -1
View File
@@ -694,7 +694,7 @@ namespace Game.Loots
}
}
public bool AutoStore(Player player, byte bag, byte slot, bool broadcast, bool createdByPlayer = false)
public bool AutoStore(Player player, byte bag, byte slot, bool broadcast = false, bool createdByPlayer = false)
{
bool allLooted = true;
for (uint i = 0; i < items.Count; ++i)
+18 -6
View File
@@ -165,17 +165,29 @@ namespace Game.Loots
List<uint> lootIdSet, lootIdSetUsed = new();
uint count = Gameobject.LoadAndCollectLootIds(out lootIdSet);
void checkLootId(uint lootId, uint gameObjectId)
{
if (!lootIdSet.Contains(lootId))
Gameobject.ReportNonExistingId(lootId, gameObjectId);
else
lootIdSetUsed.Add(lootId);
}
// remove real entries and check existence loot
var gotc = Global.ObjectMgr.GetGameObjectTemplates();
foreach (var go in gotc)
foreach (var (gameObjectId, gameObjectTemplate) in gotc)
{
uint lootid = go.Value.GetLootId();
uint lootid = gameObjectTemplate.GetLootId();
if (lootid != 0)
checkLootId(lootid, gameObjectId);
if (gameObjectTemplate.type == GameObjectTypes.Chest)
{
if (!lootIdSet.Contains(lootid))
Gameobject.ReportNonExistingId(lootid, go.Value.entry);
else
lootIdSetUsed.Add(lootid);
if (gameObjectTemplate.Chest.chestPersonalLoot != 0)
checkLootId(gameObjectTemplate.Chest.chestPersonalLoot, gameObjectId);
if (gameObjectTemplate.Chest.chestPushLoot != 0)
checkLootId(gameObjectTemplate.Chest.chestPushLoot, gameObjectId);
}
}