diff options
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) { |