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:
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user