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

(cherry picked from commit 2412886ef69d305df1bd6e6422ca3134c0ab1449)
This commit is contained in:
xinef1 authored and funjoker committed 2022-02-16 04:49:24 +01:00
1 parent f431459063
commit df9738aaa9
13 files changed
+119 -26

No files matched your search

@@ -0,0 +1,26 @@
-- To the Looter Go the Spoils (1166)
DELETE FROM `creature_loot_template` WHERE `entry`=1 AND `item`=18228;
INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `IsCurrency`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
(1, 18228, 0, 1, 0, 0, 1, 0, 1, 1, '');
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=1 AND `SourceGroup`=1 AND `SourceEntry` IN(18228);
INSERT INTO `conditions` VALUES (1, 1, 18228, 0, 0, 22, 0, 30, 0, 0, 0, 0, 0, '', 'Requires map Alterac Valley');
-- Add Player Loot for WG quests
DELETE FROM `creature_loot_template` WHERE `entry`=1 AND `item` IN(43314, 43322, 43323, 43324, 44808, 44809);
INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `IsCurrency`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
(1, 43314, 0, 100, 1, 0, 1, 0, 5, 5, ''),
(1, 43322, 0, 100, 1, 0, 1, 0, 5, 5, ''),
(1, 43323, 0, 100, 1, 0, 1, 0, 5, 5, ''),
(1, 43324, 0, 100, 1, 0, 1, 0, 5, 5, ''),
(1, 44808, 0, 100, 1, 0, 1, 0, 5, 5, ''),
(1, 44809, 0, 100, 1, 0, 1, 0, 5, 5, '');
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=1 AND `SourceGroup`=1 AND `SourceEntry` IN(43314, 43322, 43323, 43324, 44808, 44809);
INSERT INTO `conditions` VALUES (1, 1, 44808, 0, 0, 23, 0, 4585, 0, 0, 0, 0, 0, '', 'Requires Glacial Falls area'),
(1, 1, 43322, 0, 0, 23, 0, 4585, 0, 0, 0, 0, 0, '', 'Requires Glacial Falls area'),
(1, 1, 43314, 0, 0, 23, 0, 4584, 0, 0, 0, 0, 0, '', 'Requires Cauldron of Flames area'),
(1, 1, 43323, 0, 0, 23, 0, 4587, 0, 0, 0, 0, 0, '', 'Requires Forest of Shadows area'),
(1, 1, 43324, 0, 0, 23, 0, 4590, 0, 0, 0, 0, 0, '', 'Requires Steppe of Life area'),
(1, 1, 44809, 0, 0, 23, 0, 4590, 0, 0, 0, 0, 0, '', 'Requires Steppe of Life area');
@@ -952,8 +952,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
}
@@ -40,7 +40,6 @@ Corpse::Corpse(CorpseType type) : WorldObject(type != CORPSE_BONES), m_type(type
m_time = GameTime::GetGameTime();
lootForBody = false;
lootRecipient = nullptr;
}
-1
View File
@@ -74,7 +74,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;
@@ -267,7 +267,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_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
@@ -1222,7 +1222,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
@@ -1244,8 +1244,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);
}
+2 -4
View File
@@ -200,14 +200,13 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
void StartPickPocketRefillTimer();
void ResetPickPocketRefillTimer() { _pickpocketLootRestore = 0; }
bool CanGeneratePickPocketLoot() const;
void SetSkinner(ObjectGuid guid) { _skinner = guid; }
ObjectGuid GetSkinner() const { return _skinner; } // Returns the player who skinned this creature
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; }
@@ -392,7 +391,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;
+42 -12
View File
@@ -8243,7 +8243,8 @@ void Player::_ApplyAllLevelScaleItemMods(bool apply)
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 && GetZoneId() != BATTLEFIELD_TB_ZONEID)
return;
// If not released spirit, do it !
@@ -8360,8 +8361,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);
@@ -8477,14 +8479,24 @@ 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);
// For Tol Barad Quests
else if (GetZoneId() == BATTLEFIELD_TB_ZONEID)
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));
@@ -8542,6 +8554,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.
@@ -8569,14 +8597,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
@@ -8637,12 +8667,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
@@ -17856,7 +17886,7 @@ bool Player::isAllowedToLoot(Creature const* creature)
return false;
if (loot->loot_type == LOOT_SKINNING)
return creature->GetSkinner() == GetGUID();
return creature->GetLootRecipientGUID() == GetGUID();
Group* thisGroup = GetGroup();
if (!thisGroup)
+3 -2
View File
@@ -11836,12 +11836,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)
{
+1 -1
View File
@@ -105,7 +105,7 @@ void LootItem::AddAllowedLooter(Player const* player)
// --------- Loot ---------
//
Loot::Loot(uint32 _gold /*= 0*/) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_CORPSE), maxDuplicates(1), containerID(0)
Loot::Loot(uint32 _gold /*= 0*/) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_NONE), maxDuplicates(1), containerID(0)
{
}
+3
View File
@@ -822,6 +822,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);
@@ -3589,6 +3589,8 @@ enum CorpseDynFlags
CORPSE_DYNFLAG_LOOTABLE = 0x0001
};
#define PLAYER_CORPSE_LOOT_ENTRY 1
enum WeatherType
{
WEATHER_TYPE_FINE = 0,
+25
View File
@@ -7476,6 +7476,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, LINEOFSIGHT_ALL_CHECKS, 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, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
return false;
break;
}
default: // normal case
{
if (losPosition)
+1 -1
View File
@@ -4292,9 +4292,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 = 1;
if (targetLevel <= 10)