aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Battlefield/Zones/BattlefieldWG.cpp5
-rw-r--r--src/server/game/Entities/Corpse/Corpse.cpp3
-rw-r--r--src/server/game/Entities/Corpse/Corpse.h1
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp14
-rw-r--r--src/server/game/Entities/Creature/Creature.h8
-rw-r--r--src/server/game/Entities/Object/Object.cpp15
-rw-r--r--src/server/game/Entities/Object/Object.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp51
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp4
-rw-r--r--src/server/game/Loot/Loot.cpp2
-rw-r--r--src/server/game/Loot/LootMgr.cpp3
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h2
-rw-r--r--src/server/game/Spells/Spell.cpp53
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
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)
{