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>2017-02-13 20:42:06 +0100
commit2412886ef69d305df1bd6e6422ca3134c0ab1449 (patch)
tree147a8b69982451adafba2b78da4b8ce3ea82a201 /src
parent4536846d7d30508a046f394d1f561a2c3fdcf5f0 (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
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;