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.cpp16
-rw-r--r--src/server/game/Entities/Creature/Creature.h8
-rw-r--r--src/server/game/Entities/Player/Player.cpp51
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp5
-rw-r--r--src/server/game/Loot/LootMgr.cpp3
-rw-r--r--src/server/game/Loot/LootMgr.h2
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h2
-rw-r--r--src/server/game/Spells/Spell.cpp25
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
12 files changed, 94 insertions, 29 deletions
diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
index 9b5f832e294..9959f53a0fe 100644
--- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
+++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp
@@ -949,8 +949,13 @@ void BattlefieldWG::HandleKill(Player* killer, Unit* victim)
return;
if (victim->GetTypeId() == TYPEID_PLAYER)
+ {
HandlePromotion(killer, victim);
+ // Allow to Skin non-released corpse
+ victim->SetFlag(UNIT_FIELD_FLAGS, 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 990bd4e36a3..faac452bac0 100644
--- a/src/server/game/Entities/Corpse/Corpse.cpp
+++ b/src/server/game/Entities/Corpse/Corpse.cpp
@@ -36,8 +36,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 c7768e2f920..533a520a515 100644
--- a/src/server/game/Entities/Corpse/Corpse.h
+++ b/src/server/game/Entities/Corpse/Corpse.h
@@ -75,7 +75,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 8f60b41615d..ddfcfe30093 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -180,7 +180,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(),
m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0),
-m_lootRecipient(), m_lootRecipientGroup(0), _skinner(), _pickpocketLootRestore(0), m_corpseRemoveTime(0), m_respawnTime(0),
+m_lootRecipient(), m_lootRecipientGroup(0), _pickpocketLootRestore(0), m_corpseRemoveTime(0), m_respawnTime(0),
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE),
m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_cannotReachTarget(false), m_cannotReachTimer(0), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
@@ -1058,7 +1058,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
@@ -1080,8 +1080,13 @@ void Creature::SetLootRecipient(Unit* unit)
return;
m_lootRecipient = player->GetGUID();
- if (Group* group = player->GetGroup())
- m_lootRecipientGroup = group->GetLowGUID();
+ if (withGroup)
+ {
+ if (Group* group = player->GetGroup())
+ m_lootRecipientGroup = group->GetLowGUID();
+ }
+ else
+ m_lootRecipientGroup = ObjectGuid::Empty;
SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED);
}
@@ -1796,6 +1801,7 @@ void Creature::Respawn(bool force)
m_respawnTime = 0;
ResetPickPocketRefillTimer();
loot.clear();
+
if (m_originalEntry != GetEntry())
UpdateEntry(m_originalEntry);
@@ -3053,7 +3059,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 4e7a83c33d7..cc797966c46 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -555,15 +555,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; }
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; }
@@ -720,7 +719,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
ObjectGuid m_lootRecipient;
uint32 m_lootRecipientGroup;
- ObjectGuid _skinner;
/// Timers
time_t _pickpocketLootRestore;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 9e969887ba6..29fd756bc58 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -8297,7 +8297,8 @@ bool Player::CheckAmmoCompatibility(const ItemTemplate* ammo_proto) const
Called by remove insignia spell effect */
void Player::RemovedInsignia(Player* looterPlr)
{
- if (!GetBattlegroundId())
+ // If player is not in battleground and not in wintergrasp
+ if (!GetBattlegroundId() && GetZoneId() != AREA_WINTERGRASP)
return;
// If not released spirit, do it !
@@ -8385,8 +8386,9 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
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);
@@ -8499,14 +8501,21 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
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));
@@ -8563,6 +8572,22 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
}
else
{
+ // exploit fix
+ if (!creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE))
+ {
+ SendLootError(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(guid, LOOT_ERROR_DIDNT_KILL);
+ return;
+ }
+
if (loot->loot_type == LOOT_NONE)
{
// for creature, loot is filled when creature is killed.
@@ -8590,14 +8615,16 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
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
@@ -8658,12 +8685,12 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
// add 'this' player as one of the players that are looting 'loot'
loot->AddLooter(GetGUID());
+
+ if (loot_type == LOOT_CORPSE && !guid.IsItem())
+ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING);
}
else
SendLootError(GetLootGUID(), LOOT_ERROR_DIDNT_KILL);
-
- if (loot_type == LOOT_CORPSE && !guid.IsItem())
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING);
}
void Player::SendLootError(ObjectGuid guid, LootError error) const
@@ -17696,7 +17723,7 @@ bool Player::isAllowedToLoot(const Creature* creature)
return false;
if (loot->loot_type == LOOT_SKINNING)
- return creature->GetSkinner() == GetGUID();
+ return creature->GetLootRecipientGUID() == GetGUID();
Group* thisGroup = GetGroup();
if (!thisGroup)
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 1a55f14cfb5..f9e8f85cc86 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -11783,12 +11783,13 @@ 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/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index 9d56d8decb3..a301426f556 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -1545,6 +1545,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/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index cb66025b21a..3e902a86a84 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -325,7 +325,7 @@ struct TC_GAME_API Loot
// Only set for inventory items that can be right-click looted
uint32 containerID;
- Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_CORPSE), maxDuplicates(1), containerID(0) { }
+ Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_NONE), maxDuplicates(1), containerID(0) { }
~Loot() { clear(); }
// For deleting items at loot removal since there is no backward interface to the Item()
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index d192c76c623..9c0d09edaed 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -2993,6 +2993,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 29940ca1b06..ff418153773 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -6832,6 +6832,31 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo
// all ok by some way or another, skip normal check
break;
+ case SPELL_EFFECT_SKIN_PLAYER_CORPSE:
+ {
+ if (!m_targets.GetCorpseTargetGUID())
+ {
+ if (target->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2) && target->HasFlag(UNIT_FIELD_FLAGS, 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->HasFlag(CORPSE_FIELD_FLAGS, CORPSE_FLAG_LOOTABLE))
+ return false;
+
+ if (!corpse->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2))
+ return false;
+
+ break;
+ }
default: // normal case
{
if (losPosition)
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index c4592477529..fb740906ea8 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -4646,9 +4646,9 @@ void Spell::EffectSkinning(SpellEffIndex /*effIndex*/)
uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill();
- m_caster->ToPlayer()->SendLoot(creature->GetGUID(), LOOT_SKINNING);
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+ m_caster->ToPlayer()->SendLoot(creature->GetGUID(), LOOT_SKINNING);
int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;