aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp86
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h4
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp6
-rw-r--r--src/server/game/Handlers/LootHandler.cpp4
-rw-r--r--src/server/game/Loot/LootMgr.cpp24
-rw-r--r--src/server/scripts/Commands/cs_gobject.cpp2
6 files changed, 93 insertions, 33 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 36ef1a42d9e..ed2dc526fba 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -521,8 +521,6 @@ GameObject::GameObject() : WorldObject(false), MapObject(),
m_spawnId = UI64LIT(0);
- m_lootGenerationTime = 0;
-
ResetLootMode(); // restore default loot mode
m_stationaryPosition.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
}
@@ -958,6 +956,8 @@ void GameObject::Update(uint32 diff)
m_lootState = GO_READY;
m_loot = nullptr;
m_personalLoot.clear();
+ m_unique_users.clear();
+ m_usetimes = 0;
AddToObjectUpdateIfNeeded();
break;
default:
@@ -1188,6 +1188,8 @@ void GameObject::Update(uint32 diff)
m_lootState = GO_READY;
m_loot = nullptr;
m_personalLoot.clear();
+ m_unique_users.clear();
+ m_usetimes = 0;
AddToObjectUpdateIfNeeded();
}
break;
@@ -1263,6 +1265,8 @@ void GameObject::Update(uint32 diff)
m_loot = nullptr;
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() || GetSpellId()) && m_respawnTime == 0;
@@ -1873,7 +1877,10 @@ bool GameObject::ActivateToQuest(Player const* target) const
return false;
// scan GO chest with loot including quest items
- if (target->GetQuestStatus(GetGOInfo()->chest.questID) == QUEST_STATUS_INCOMPLETE || LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->GetLootId(), target))
+ if (target->GetQuestStatus(GetGOInfo()->chest.questID) == QUEST_STATUS_INCOMPLETE
+ || LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->chest.chestLoot, target)
+ || LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->chest.chestPersonalLoot, target)
+ || LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->chest.chestPushLoot, target))
{
if (Battleground const* bg = target->GetBattleground())
return bg->CanActivateGO(GetEntry(), bg->GetPlayerTeam(target->GetGUID()));
@@ -2182,45 +2189,71 @@ void GameObject::Use(Unit* user)
return;
GameObjectTemplate const* info = GetGOInfo();
- Loot* loot = nullptr;
- if (getLootState() == GO_READY)
+ if (!m_loot && info->GetLootId())
{
- if (uint32 lootId = info->GetLootId())
+ if (info->GetLootId())
{
- SetLootGenerationTime();
-
Group const* group = player->GetGroup();
bool groupRules = group && info->chest.usegrouplootrules;
- loot = new Loot(GetMap(), GetGUID(), LOOT_CHEST, groupRules ? group : nullptr);
+ Loot* loot = new Loot(GetMap(), GetGUID(), LOOT_CHEST, groupRules ? group : nullptr);
m_loot.reset(loot);
loot->SetDungeonEncounterId(info->chest.DungeonEncounter);
- loot->FillLoot(lootId, LootTemplates_Gameobject, player, !groupRules, false, GetLootMode(), GetMap()->GetDifficultyLootItemContext());
+ loot->FillLoot(info->GetLootId(), LootTemplates_Gameobject, player, !groupRules, false, GetLootMode(), GetMap()->GetDifficultyLootItemContext());
if (GetLootMode() > 0)
if (GameObjectTemplateAddon const* addon = GetTemplateAddon())
loot->generateMoneyLoot(addon->Mingold, addon->Maxgold);
}
- /// @todo possible must be moved to loot release (in different from linked triggering)
if (info->chest.triggeredEvent)
+ GameEvents::Trigger(info->chest.triggeredEvent, player, this);
+
+ // triggering linked GO
+ if (uint32 trapEntry = info->chest.linkedTrap)
+ TriggeringLinkedGameObject(trapEntry, player);
+ }
+ else if (!m_personalLoot.count(player->GetGUID()))
+ {
+ if (info->chest.chestPersonalLoot)
+ {
+ Loot* loot = new Loot(GetMap(), GetGUID(), LOOT_CHEST, nullptr);
+ m_personalLoot[player->GetGUID()].reset(loot);
+
+ loot->SetDungeonEncounterId(info->chest.DungeonEncounter);
+ loot->FillLoot(info->chest.chestPersonalLoot, LootTemplates_Gameobject, player, true, false, GetLootMode(), GetMap()->GetDifficultyLootItemContext());
+
+ if (GetLootMode() > 0)
+ if (GameObjectTemplateAddon const* addon = GetTemplateAddon())
+ loot->generateMoneyLoot(addon->Mingold, addon->Maxgold);
+ }
+ }
+
+ if (!m_unique_users.count(player->GetGUID()) && !info->GetLootId())
+ {
+ if (info->chest.chestPushLoot)
{
- TC_LOG_DEBUG("spells", "Chest ScriptStart id %u for GO " UI64FMTD, info->chest.triggeredEvent, GetSpawnId());
- GameEvents::Trigger(info->chest.triggeredEvent, user, this);
+ Loot pushLoot(GetMap(), GetGUID(), LOOT_CHEST, nullptr);
+ pushLoot.FillLoot(info->chest.chestPushLoot, LootTemplates_Gameobject, player, true, false, GetLootMode(), GetMap()->GetDifficultyLootItemContext());
+ pushLoot.AutoStore(player, NULL_BAG, NULL_SLOT);
}
+ if (info->chest.triggeredEvent)
+ GameEvents::Trigger(info->chest.triggeredEvent, player, this);
+
// triggering linked GO
if (uint32 trapEntry = info->chest.linkedTrap)
TriggeringLinkedGameObject(trapEntry, player);
- SetLootState(GO_ACTIVATED, player);
+ AddUniqueUse(player);
}
- else
- loot = GetLootForPlayer(player);
+
+ if (getLootState() != GO_ACTIVATED)
+ SetLootState(GO_ACTIVATED, player);
// Send loot
- if (loot)
+ if (Loot* loot = GetLootForPlayer(player))
player->SendLoot(*loot);
break;
}
@@ -3145,9 +3178,16 @@ void GameObject::SetLootState(LootState state, Unit* unit)
}
}
-void GameObject::SetLootGenerationTime()
+bool GameObject::IsFullyLooted() const
{
- m_lootGenerationTime = GameTime::GetGameTime();
+ if (m_loot && !m_loot->isLooted())
+ return false;
+
+ for (auto const& [_, loot] : m_personalLoot)
+ if (!loot->isLooted())
+ return false;
+
+ return true;
}
void GameObject::SetGoState(GOState state)
@@ -3284,6 +3324,14 @@ void GameObject::SetLootRecipient(Unit* unit, Group* group)
bool GameObject::IsLootAllowedFor(Player const* player) const
{
+ if (Loot const* loot = GetLootForPlayer(player)) // 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 && !m_lootRecipientGroup)
return true;
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 886b28b4cdb..55d86f1e5f8 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -261,8 +261,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
void AddLootMode(uint16 lootMode) { m_LootMode |= lootMode; }
void RemoveLootMode(uint16 lootMode) { m_LootMode &= ~lootMode; }
void ResetLootMode() { m_LootMode = LOOT_MODE_DEFAULT; }
- void SetLootGenerationTime();
- uint32 GetLootGenerationTime() const { return m_lootGenerationTime; }
+ bool IsFullyLooted() const;
void AddToSkillupList(ObjectGuid const& PlayerGuidLow) { m_SkillupList.insert(PlayerGuidLow); }
bool IsInSkillupList(ObjectGuid const& playerGuid) const
@@ -431,7 +430,6 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
ObjectGuid m_lootRecipient;
ObjectGuid m_lootRecipientGroup;
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
- uint32 m_lootGenerationTime;
ObjectGuid m_linkedTrap;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 881a0f87b88..ecb36b25938 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -8872,9 +8872,11 @@ void ObjectMgr::LoadGameObjectForQuests()
case GAMEOBJECT_TYPE_CHEST:
{
// scan GO chest with loot including quest items
- uint32 lootId = gameObjectTemplatePair.second.GetLootId();
// find quest loot for GO
- if (gameObjectTemplatePair.second.chest.questID || LootTemplates_Gameobject.HaveQuestLootFor(lootId))
+ if (gameObjectTemplatePair.second.chest.questID
+ || LootTemplates_Gameobject.HaveQuestLootFor(gameObjectTemplatePair.second.chest.chestLoot)
+ || LootTemplates_Gameobject.HaveQuestLootFor(gameObjectTemplatePair.second.chest.chestPersonalLoot)
+ || LootTemplates_Gameobject.HaveQuestLootFor(gameObjectTemplatePair.second.chest.chestPushLoot))
break;
continue;
}
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index ed1ed76be36..8fe3ecff2b5 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -295,10 +295,8 @@ void WorldSession::DoLootRelease(Loot* loot)
else
go->SetLootState(GO_READY);
}
- else
+ else if (go->IsFullyLooted())
go->SetLootState(GO_JUST_DEACTIVATED);
-
- loot->clear();
}
else
{
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index 506b26b59ef..9e04a32edd4 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -880,16 +880,28 @@ void LoadLootTemplates_Gameobject()
LootIdSet lootIdSet, lootIdSetUsed;
uint32 count = LootTemplates_Gameobject.LoadAndCollectLootIds(lootIdSet);
+ auto checkLootId = [&](uint32 lootId, uint32 gameObjectId)
+ {
+ if (!lootIdSet.count(lootId))
+ LootTemplates_Gameobject.ReportNonExistingId(lootId, "Gameobject", gameObjectId);
+ else
+ lootIdSetUsed.insert(lootId);
+ };
+
// remove real entries and check existence loot
GameObjectTemplateContainer const& gotc = sObjectMgr->GetGameObjectTemplates();
- for (auto const& gameObjectTemplatePair : gotc)
+ for (auto const& [gameObjectId, gameObjectTemplate] : gotc)
{
- if (uint32 lootid = gameObjectTemplatePair.second.GetLootId())
+ if (uint32 lootid = gameObjectTemplate.GetLootId())
+ checkLootId(lootid, gameObjectId);
+
+ if (gameObjectTemplate.type == GAMEOBJECT_TYPE_CHEST)
{
- if (!lootIdSet.count(lootid))
- LootTemplates_Gameobject.ReportNonExistingId(lootid, "Gameobject", gameObjectTemplatePair.first);
- else
- lootIdSetUsed.insert(lootid);
+ if (gameObjectTemplate.chest.chestPersonalLoot)
+ checkLootId(gameObjectTemplate.chest.chestPersonalLoot, gameObjectId);
+
+ if (gameObjectTemplate.chest.chestPushLoot)
+ checkLootId(gameObjectTemplate.chest.chestPushLoot, gameObjectId);
}
}
diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp
index 027c72e1c23..4a20f423892 100644
--- a/src/server/scripts/Commands/cs_gobject.cpp
+++ b/src/server/scripts/Commands/cs_gobject.cpp
@@ -528,6 +528,8 @@ public:
displayId = gameObjectInfo->displayId;
name = gameObjectInfo->name;
lootId = gameObjectInfo->GetLootId();
+ if (type == GAMEOBJECT_TYPE_CHEST && !lootId)
+ lootId = gameObjectInfo->chest.chestPersonalLoot;
// If we have a real object, send some info about it
if (thisGO)