aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxinef1 <w.szyszko2@gmail.com>2017-02-13 20:42:06 +0100
committerShauren <shauren.trinity@gmail.com>2019-07-21 21:06:54 +0200
commit89f728cd5b6ae3041fdae3c853ac4b0ac5f0a848 (patch)
tree10a4c1d3322df49c0e2d1f87cae1c7bf801d38e2 /src
parentc860522ecf358b20afb3b3266de0555606a77888 (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.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)
{