diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 86 | ||||
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 4 | ||||
| -rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 6 | ||||
| -rw-r--r-- | src/server/game/Handlers/LootHandler.cpp | 4 | ||||
| -rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 24 | ||||
| -rw-r--r-- | src/server/scripts/Commands/cs_gobject.cpp | 2 |
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) |
