diff options
author | xinef1 <w.szyszko2@gmail.com> | 2017-02-13 20:42:06 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2019-07-21 21:06:54 +0200 |
commit | 89f728cd5b6ae3041fdae3c853ac4b0ac5f0a848 (patch) | |
tree | 10a4c1d3322df49c0e2d1f87cae1c7bf801d38e2 /src | |
parent | c860522ecf358b20afb3b3266de0555606a77888 (diff) |
Core/Misc: Fixed player corpse looting, added player corpse loot and some more (#19122)
* Fixed corpse looting in wintergrasp
Added corpse loot for wintergrasp quests and To the Looter Go the Spoils (1166) achievement
Don't generate money for loot if no loot mode is available
Simplified few things
(cherrypicked from 2412886ef69d305df1bd6e6422ca3134c0ab1449)
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Battlefield/Zones/BattlefieldWG.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Corpse/Corpse.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Corpse/Corpse.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 14 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 8 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 15 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 51 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Loot/Loot.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/SharedDefines.h | 2 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 53 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 2 |
14 files changed, 125 insertions, 39 deletions
diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp index 3d87b2aa66e..53dd265bf81 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp @@ -954,8 +954,13 @@ void BattlefieldWG::HandleKill(Player* killer, Unit* victim) return; if (victim->GetTypeId() == TYPEID_PLAYER) + { HandlePromotion(killer, victim); + // Allow to Skin non-released corpse + victim->AddUnitFlag(UNIT_FLAG_SKINNABLE); + } + /// @todoRecent PvP activity worldstate } diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 23052bd7ff6..a7838589dce 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -38,8 +38,7 @@ Corpse::Corpse(CorpseType type) : WorldObject(type != CORPSE_BONES), m_type(type m_time = time(NULL); - lootForBody = false; - lootRecipient = NULL; + lootRecipient = nullptr; } Corpse::~Corpse() { } diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h index 8abaeae48a3..2aec35372d3 100644 --- a/src/server/game/Entities/Corpse/Corpse.h +++ b/src/server/game/Entities/Corpse/Corpse.h @@ -98,7 +98,6 @@ class TC_GAME_API Corpse : public WorldObject, public GridObject<Corpse> Loot loot; // remove insignia ONLY at BG Player* lootRecipient; - bool lootForBody; bool IsExpired(time_t t) const; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index debf8f3b817..bdd49e25e71 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1101,7 +1101,7 @@ Group* Creature::GetLootRecipientGroup() const return sGroupMgr->GetGroupByGUID(m_lootRecipientGroup); } -void Creature::SetLootRecipient(Unit* unit) +void Creature::SetLootRecipient(Unit* unit, bool withGroup) { // set the player whose group should receive the right // to loot the creature after it dies @@ -1123,8 +1123,13 @@ void Creature::SetLootRecipient(Unit* unit) return; m_lootRecipient = player->GetGUID(); - if (Group* group = player->GetGroup()) - m_lootRecipientGroup = group->GetGUID(); + if (withGroup) + { + if (Group* group = player->GetGroup()) + m_lootRecipientGroup = group->GetGUID(); + } + else + m_lootRecipientGroup = ObjectGuid::Empty; AddDynamicFlag(UNIT_DYNFLAG_TAPPED); } @@ -1888,6 +1893,7 @@ void Creature::Respawn(bool force) m_respawnTime = 0; ResetPickPocketRefillTimer(); loot.clear(); + if (m_originalEntry != GetEntry()) UpdateEntry(m_originalEntry); else @@ -3080,7 +3086,7 @@ void Creature::ReleaseFocus(Spell const* focusSpell, bool withDelay) void Creature::StartPickPocketRefillTimer() { - _pickpocketLootRestore = time(NULL) + sWorld->getIntConfig(CONFIG_CREATURE_PICKPOCKET_REFILL); + _pickpocketLootRestore = time(nullptr) + sWorld->getIntConfig(CONFIG_CREATURE_PICKPOCKET_REFILL); } void Creature::SetTextRepeatId(uint8 textGroup, uint8 id) diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index c90081536c0..21a53dbc973 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -195,15 +195,14 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma Loot loot; void StartPickPocketRefillTimer(); void ResetPickPocketRefillTimer() { _pickpocketLootRestore = 0; } - bool CanGeneratePickPocketLoot() const { return _pickpocketLootRestore <= time(NULL); } - void SetSkinner(ObjectGuid guid) { _skinner = guid; } - ObjectGuid GetSkinner() const { return _skinner; } // Returns the player who skinned this creature + bool CanGeneratePickPocketLoot() const { return _pickpocketLootRestore <= time(nullptr); } + ObjectGuid GetLootRecipientGUID() const { return m_lootRecipient; } Player* GetLootRecipient() const; Group* GetLootRecipientGroup() const; bool hasLootRecipient() const { return !m_lootRecipient.IsEmpty() || !m_lootRecipientGroup.IsEmpty(); } bool isTappedBy(Player const* player) const; // return true if the creature is tapped by the player or a member of his party. - void SetLootRecipient (Unit* unit); + void SetLootRecipient (Unit* unit, bool withGroup = true); void AllLootRemovedFromCorpse(); uint16 GetLootMode() const { return m_LootMode; } @@ -356,7 +355,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma ObjectGuid m_lootRecipient; ObjectGuid m_lootRecipientGroup; - ObjectGuid _skinner; /// Timers time_t _pickpocketLootRestore; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index af4fd6e6ec5..b7894cef6b0 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -938,6 +938,21 @@ void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const GetMap()->GetZoneAndAreaId(GetPhaseShift(), zoneid, areaid, m_positionX, m_positionY, m_positionZ); } +bool WorldObject::IsInWorldPvpZone() const +{ + switch (GetZoneId()) + { + case 4197: // Wintergrasp + case 5095: // Tol Barad + case 6941: // Ashran + return true; + break; + default: + return false; + break; + } +} + InstanceScript* WorldObject::GetInstanceScript() { Map* map = GetMap(); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 00258002f17..84157b8f58b 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -402,6 +402,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation uint32 GetZoneId() const; uint32 GetAreaId() const; void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const; + bool IsInWorldPvpZone() const; InstanceScript* GetInstanceScript(); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 20cb86a37b3..d89c26a8cfd 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8274,7 +8274,8 @@ bool Player::HasLootWorldObjectGUID(ObjectGuid const& lootWorldObjectGuid) const Called by remove insignia spell effect */ void Player::RemovedInsignia(Player* looterPlr) { - if (!GetBattlegroundId()) + // If player is not in battleground and not in worldpvpzone + if (!GetBattlegroundId() && !IsInWorldPvpZone()) return; // If not released spirit, do it ! @@ -8369,8 +8370,9 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa group->UpdateLooterGuid(go); } - if (GameObjectTemplateAddon const* addon = go->GetTemplateAddon()) - loot->generateMoneyLoot(addon->mingold, addon->maxgold); + if (go->GetLootMode() > 0) + if (GameObjectTemplateAddon const* addon = go->GetTemplateAddon()) + loot->generateMoneyLoot(addon->mingold, addon->maxgold); if (loot_type == LOOT_FISHING) go->getFishLoot(loot, this); @@ -8477,14 +8479,21 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa loot = &bones->loot; - if (!bones->lootForBody) + if (loot->loot_type == LOOT_NONE) { - bones->lootForBody = true; uint32 pLevel = bones->loot.gold; bones->loot.clear(); + + // For AV Achievement if (Battleground* bg = GetBattleground()) + { if (bg->GetTypeID(true) == BATTLEGROUND_AV) - loot->FillLoot(1, LootTemplates_Creature, this, true); + loot->FillLoot(PLAYER_CORPSE_LOOT_ENTRY, LootTemplates_Creature, this, true); + } + // For wintergrasp Quests + else if (GetZoneId() == AREA_WINTERGRASP) + loot->FillLoot(PLAYER_CORPSE_LOOT_ENTRY, LootTemplates_Creature, this, true); + // It may need a better formula // Now it works like this: lvl10: ~6copper, lvl70: ~9silver bones->loot.gold = uint32(urand(50, 150) * 0.016f * std::pow(float(pLevel) / 5.76f, 2.5f) * sWorld->getRate(RATE_DROP_MONEY)); @@ -8541,6 +8550,22 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa } else { + // exploit fix + if (!creature->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE)) + { + SendLootError(loot->GetGUID(), guid, LOOT_ERROR_DIDNT_KILL); + return; + } + + // the player whose group may loot the corpse + Player* recipient = creature->GetLootRecipient(); + Group* recipientGroup = creature->GetLootRecipientGroup(); + if (!recipient && !recipientGroup) + { + SendLootError(loot->GetGUID(), guid, LOOT_ERROR_DIDNT_KILL); + return; + } + if (loot->loot_type == LOOT_NONE) { // for creature, loot is filled when creature is killed. @@ -8565,14 +8590,16 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa if (loot->loot_type == LOOT_SKINNING) { loot_type = LOOT_SKINNING; - permission = creature->GetSkinner() == GetGUID() ? OWNER_PERMISSION : NONE_PERMISSION; + permission = creature->GetLootRecipientGUID() == GetGUID() ? OWNER_PERMISSION : NONE_PERMISSION; } else if (loot_type == LOOT_SKINNING) { loot->clear(); loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true); - creature->SetSkinner(GetGUID()); permission = OWNER_PERMISSION; + + // Set new loot recipient + creature->SetLootRecipient(this, false); } // set group rights only for loot_type != LOOT_SKINNING else @@ -8649,12 +8676,12 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa // add 'this' player as one of the players that are looting 'loot' loot->AddLooter(GetGUID()); m_AELootView[loot->GetGUID()] = guid; + + if (loot_type == LOOT_CORPSE && !guid.IsItem()) + SetUnitFlags(UNIT_FLAG_LOOTING); } else SendLootError(loot->GetGUID(), guid, LOOT_ERROR_DIDNT_KILL); - - if (loot_type == LOOT_CORPSE && !guid.IsItem()) - AddUnitFlag(UNIT_FLAG_LOOTING); } void Player::SendLootError(ObjectGuid const& lootObj, ObjectGuid const& owner, LootError error) const @@ -18329,7 +18356,7 @@ bool Player::isAllowedToLoot(const Creature* creature) const return false; if (loot->loot_type == LOOT_SKINNING) - return creature->GetSkinner() == GetGUID(); + return creature->GetLootRecipientGUID() == GetGUID(); Group const* thisGroup = GetGroup(); if (!thisGroup) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index a454777ba77..f683730009f 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -11128,12 +11128,12 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) if (creature) { Loot* loot = &creature->loot; - loot->clear(); if (uint32 lootid = creature->GetCreatureTemplate()->lootid) loot->FillLoot(lootid, LootTemplates_Creature, looter, false, false, creature->GetLootMode()); - loot->generateMoneyLoot(creature->GetCreatureTemplate()->mingold, creature->GetCreatureTemplate()->maxgold); + if (creature->GetLootMode() > 0) + loot->generateMoneyLoot(creature->GetCreatureTemplate()->mingold, creature->GetCreatureTemplate()->maxgold); if (group) { diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp index c16178da814..7da466435f4 100644 --- a/src/server/game/Loot/Loot.cpp +++ b/src/server/game/Loot/Loot.cpp @@ -96,7 +96,7 @@ void LootItem::AddAllowedLooter(const Player* player) // --------- Loot --------- // -Loot::Loot(uint32 _gold /*= 0*/) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_CORPSE), maxDuplicates(1), _itemContext(0) +Loot::Loot(uint32 _gold /*= 0*/) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_NONE), maxDuplicates(1), _itemContext(0) { } diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 00687a0a4d5..ebc77718973 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -807,6 +807,9 @@ void LoadLootTemplates_Creature() for (LootIdSet::const_iterator itr = lootIdSetUsed.begin(); itr != lootIdSetUsed.end(); ++itr) lootIdSet.erase(*itr); + // 1 means loot for player corpse + lootIdSet.erase(PLAYER_CORPSE_LOOT_ENTRY); + // output error for any still listed (not referenced from appropriate table) ids LootTemplates_Creature.ReportUnusedIds(lootIdSet); diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 7dd25644c38..89f2abd8b1b 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -4705,6 +4705,8 @@ enum CorpseDynFlags CORPSE_DYNFLAG_LOOTABLE = 0x0001 }; +#define PLAYER_CORPSE_LOOT_ENTRY 1 + enum WeatherType { WEATHER_TYPE_FINE = 0, diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index f8049826773..b66570a58d8 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -6893,18 +6893,49 @@ bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const* effect, /// @todo shit below shouldn't be here, but it's temporary //Check targets for LOS visibility - if (losPosition) - return target->IsWithinLOS(losPosition->GetPositionX(), losPosition->GetPositionY(), losPosition->GetPositionZ(), VMAP::ModelIgnoreFlags::M2); - else + switch (effect->Effect) { - // Get GO cast coordinates if original caster -> GO - WorldObject* caster = NULL; - if (m_originalCasterGUID.IsGameObject()) - caster = m_caster->GetMap()->GetGameObject(m_originalCasterGUID); - if (!caster) - caster = m_caster; - if (target != m_caster && !target->IsWithinLOSInMap(caster, VMAP::ModelIgnoreFlags::M2)) - return false; + case SPELL_EFFECT_SKIN_PLAYER_CORPSE: + { + if (!m_targets.GetCorpseTargetGUID()) + { + if (target->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2) && target->HasUnitFlag(UNIT_FLAG_SKINNABLE)) + return true; + + return false; + } + + Corpse* corpse = ObjectAccessor::GetCorpse(*m_caster, m_targets.GetCorpseTargetGUID()); + if (!corpse) + return false; + + if (target->GetGUID() != corpse->GetOwnerGUID()) + return false; + + if (!corpse->HasDynamicFlag(CORPSE_DYNFLAG_LOOTABLE)) + return false; + + if (!corpse->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2)) + return false; + + break; + } + default: + { + if (losPosition) + return target->IsWithinLOS(losPosition->GetPositionX(), losPosition->GetPositionY(), losPosition->GetPositionZ(), VMAP::ModelIgnoreFlags::M2); + else + { + // Get GO cast coordinates if original caster -> GO + WorldObject* caster = NULL; + if (m_originalCasterGUID.IsGameObject()) + caster = m_caster->GetMap()->GetGameObject(m_originalCasterGUID); + if (!caster) + caster = m_caster; + if (target != m_caster && !target->IsWithinLOSInMap(caster, VMAP::ModelIgnoreFlags::M2)) + return false; + } + } } return true; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 937578b6ccd..d5d9f1cdd2b 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4168,9 +4168,9 @@ void Spell::EffectSkinning(SpellEffIndex /*effIndex*/) uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill(); - m_caster->ToPlayer()->SendLoot(creature->GetGUID(), LOOT_SKINNING); creature->RemoveUnitFlag(UNIT_FLAG_SKINNABLE); creature->AddDynamicFlag(UNIT_DYNFLAG_LOOTABLE); + m_caster->ToPlayer()->SendLoot(creature->GetGUID(), LOOT_SKINNING); if (skill == SKILL_SKINNING) { |