mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-21 23:38:54 -04:00
Core/Loot: Skinning improvements
* Set skinnable flag only after all loot was taken * Creatures are skinnable only once - after skinning, the player only has to loot the creature again if he did not take all skinning loot
This commit is contained in:
@@ -142,8 +142,8 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
}
|
||||
|
||||
Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(),
|
||||
lootForPickPocketed(false), _pickpocketLootRestore(0), lootForBody(false), lootForSkinned(false), _skinner(0), m_groupLootTimer(0), lootingGroupLowGUID(0),
|
||||
m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0),
|
||||
_pickpocketLootRestore(0), m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0),
|
||||
m_lootRecipient(0), m_lootRecipientGroup(0), _skinner(0), m_corpseRemoveTime(0), m_respawnTime(0),
|
||||
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE),
|
||||
m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
|
||||
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
|
||||
@@ -550,9 +550,9 @@ void Creature::Update(uint32 diff)
|
||||
time_t now = time(NULL);
|
||||
|
||||
// Check if we should refill the pickpocketing loot
|
||||
if (lootForPickPocketed && _pickpocketLootRestore && _pickpocketLootRestore <= now)
|
||||
if (loot.loot_type == LOOT_PICKPOCKETING && _pickpocketLootRestore && _pickpocketLootRestore <= now)
|
||||
{
|
||||
lootForPickPocketed = false;
|
||||
loot.clear();
|
||||
_pickpocketLootRestore = 0;
|
||||
}
|
||||
|
||||
@@ -1472,11 +1472,6 @@ void Creature::setDeathState(DeathState s)
|
||||
|
||||
setActive(false);
|
||||
|
||||
if (!IsPet() && GetCreatureTemplate()->SkinLootId)
|
||||
if (LootTemplates_Skinning.HaveLootFor(GetCreatureTemplate()->SkinLootId))
|
||||
if (hasLootRecipient())
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
|
||||
|
||||
if (HasSearchedAssistance())
|
||||
{
|
||||
SetNoSearchAssistance(false);
|
||||
@@ -1537,9 +1532,7 @@ void Creature::Respawn(bool force)
|
||||
GetName().c_str(), GetGUIDLow(), GetGUID(), GetEntry());
|
||||
m_respawnTime = 0;
|
||||
_pickpocketLootRestore = 0;
|
||||
lootForPickPocketed = false;
|
||||
lootForBody = false;
|
||||
lootForSkinned = false;
|
||||
loot.clear();
|
||||
if (m_originalEntry != GetEntry())
|
||||
UpdateEntry(m_originalEntry);
|
||||
|
||||
@@ -2278,23 +2271,23 @@ void Creature::GetRespawnPosition(float &x, float &y, float &z, float* ori, floa
|
||||
|
||||
void Creature::AllLootRemovedFromCorpse()
|
||||
{
|
||||
if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE))
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
if (m_corpseRemoveTime <= now)
|
||||
return;
|
||||
if (loot.loot_type != LOOT_SKINNING && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient())
|
||||
if (LootTemplates_Skinning.HaveLootFor(GetCreatureTemplate()->SkinLootId))
|
||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
|
||||
|
||||
float decayRate = sWorld->getRate(RATE_CORPSE_DECAY_LOOTED);
|
||||
CreatureTemplate const* cinfo = GetCreatureTemplate();
|
||||
time_t now = time(NULL);
|
||||
if (m_corpseRemoveTime <= now)
|
||||
return;
|
||||
|
||||
// corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
|
||||
if (cinfo && cinfo->SkinLootId)
|
||||
m_corpseRemoveTime = time(NULL);
|
||||
else
|
||||
m_corpseRemoveTime = now + m_corpseDelay * decayRate;
|
||||
float decayRate = sWorld->getRate(RATE_CORPSE_DECAY_LOOTED);
|
||||
|
||||
m_respawnTime = m_corpseRemoveTime + m_respawnTime;
|
||||
}
|
||||
// corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
|
||||
if (loot.loot_type == LOOT_SKINNING)
|
||||
m_corpseRemoveTime = time(NULL);
|
||||
else
|
||||
m_corpseRemoveTime = now + m_corpseDelay * decayRate;
|
||||
|
||||
m_respawnTime = m_corpseRemoveTime + m_respawnTime;
|
||||
}
|
||||
|
||||
uint8 Creature::getLevelForTarget(WorldObject const* target) const
|
||||
|
||||
@@ -551,9 +551,6 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
|
||||
virtual void DeleteFromDB(); // overriden in Pet
|
||||
|
||||
Loot loot;
|
||||
bool lootForPickPocketed;
|
||||
bool lootForBody;
|
||||
bool lootForSkinned;
|
||||
void StartPickPocketRefillTimer();
|
||||
void ResetPickPocketRefillTimer() { _pickpocketLootRestore = 0; }
|
||||
void SetSkinner(uint64 guid) { _skinner = guid; }
|
||||
|
||||
@@ -8969,9 +8969,8 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
|
||||
|
||||
if (loot_type == LOOT_PICKPOCKETING)
|
||||
{
|
||||
if (!creature->lootForPickPocketed)
|
||||
if (loot->loot_type != LOOT_PICKPOCKETING)
|
||||
{
|
||||
creature->lootForPickPocketed = true;
|
||||
creature->StartPickPocketRefillTimer();
|
||||
loot->clear();
|
||||
|
||||
@@ -8992,12 +8991,9 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
|
||||
if (!recipient)
|
||||
return;
|
||||
|
||||
if (!creature->lootForBody)
|
||||
if (loot->loot_type == LOOT_NONE)
|
||||
{
|
||||
creature->lootForBody = true;
|
||||
|
||||
// for creature, loot is filled when creature is killed.
|
||||
|
||||
if (Group* group = recipient->GetGroup())
|
||||
{
|
||||
switch (group->GetLootMethod())
|
||||
@@ -9018,15 +9014,17 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
|
||||
}
|
||||
}
|
||||
|
||||
// possible only if creature->lootForBody && loot->empty() at spell cast check
|
||||
if (loot_type == LOOT_SKINNING)
|
||||
// if loot is already skinning loot then don't do anything else
|
||||
if (loot->loot_type == LOOT_SKINNING)
|
||||
{
|
||||
if (!creature->lootForSkinned)
|
||||
{
|
||||
creature->lootForSkinned = true;
|
||||
loot->clear();
|
||||
loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true);
|
||||
}
|
||||
loot_type = LOOT_SKINNING;
|
||||
permission = creature->GetSkinner() == 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 group rights only for loot_type != LOOT_SKINNING
|
||||
@@ -17835,6 +17833,9 @@ bool Player::isAllowedToLoot(const Creature* creature)
|
||||
if (loot->isLooted()) // nothing to loot or everything looted.
|
||||
return false;
|
||||
|
||||
if (loot->loot_type == LOOT_SKINNING)
|
||||
return creature->GetSkinner() == GetGUID();
|
||||
|
||||
Group* thisGroup = GetGroup();
|
||||
if (!thisGroup)
|
||||
return this == creature->GetLootRecipient();
|
||||
|
||||
@@ -15271,11 +15271,8 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
|
||||
if (creature)
|
||||
{
|
||||
Loot* loot = &creature->loot;
|
||||
if (creature->lootForPickPocketed)
|
||||
{
|
||||
if (creature->loot.loot_type == LOOT_PICKPOCKETING)
|
||||
creature->ResetPickPocketRefillTimer();
|
||||
creature->lootForPickPocketed = false;
|
||||
}
|
||||
|
||||
loot->clear();
|
||||
if (uint32 lootid = creature->GetCreatureTemplate()->lootid)
|
||||
@@ -15394,9 +15391,12 @@ void Unit::Kill(Unit* victim, bool durabilityLoss)
|
||||
if (!creature->IsPet())
|
||||
{
|
||||
creature->DeleteThreatList();
|
||||
CreatureTemplate const* cInfo = creature->GetCreatureTemplate();
|
||||
if (cInfo && (cInfo->lootid || cInfo->maxgold > 0))
|
||||
|
||||
// must be after setDeathState which resets dynamic flags
|
||||
if (!creature->loot.empty())
|
||||
creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
|
||||
else
|
||||
creature->AllLootRemovedFromCorpse();
|
||||
}
|
||||
|
||||
// Call KilledUnit for creatures, this needs to be called after the lootable flag is set
|
||||
|
||||
@@ -81,7 +81,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
|
||||
{
|
||||
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
|
||||
|
||||
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed);
|
||||
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
|
||||
|
||||
if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
|
||||
{
|
||||
@@ -148,7 +148,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
|
||||
case HIGHGUID_VEHICLE:
|
||||
{
|
||||
Creature* creature = player->GetMap()->GetCreature(guid);
|
||||
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed);
|
||||
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
|
||||
if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE))
|
||||
{
|
||||
loot = &creature->loot;
|
||||
@@ -348,7 +348,7 @@ void WorldSession::DoLootRelease(uint64 lguid)
|
||||
{
|
||||
Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
|
||||
|
||||
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed);
|
||||
bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
|
||||
if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
|
||||
return;
|
||||
|
||||
@@ -356,9 +356,6 @@ void WorldSession::DoLootRelease(uint64 lguid)
|
||||
if (loot->isLooted())
|
||||
{
|
||||
creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
|
||||
|
||||
if (loot->loot_type == LOOT_SKINNING)
|
||||
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
|
||||
|
||||
// skip pickpocketing loot for speed, skinning timer reduction is no-op in fact
|
||||
if (!creature->IsAlive())
|
||||
|
||||
@@ -76,6 +76,8 @@ enum PermissionTypes
|
||||
|
||||
enum LootType
|
||||
{
|
||||
LOOT_NONE = 0,
|
||||
|
||||
LOOT_CORPSE = 1,
|
||||
LOOT_PICKPOCKETING = 2,
|
||||
LOOT_FISHING = 3,
|
||||
@@ -341,6 +343,7 @@ struct Loot
|
||||
gold = 0;
|
||||
unlootedCount = 0;
|
||||
roundRobinPlayer = 0;
|
||||
loot_type = LOOT_NONE;
|
||||
i_LootValidatorRefManager.clearReferences();
|
||||
}
|
||||
|
||||
|
||||
@@ -5058,13 +5058,11 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
return SPELL_FAILED_TARGET_UNSKINNABLE;
|
||||
|
||||
Creature* creature = m_targets.GetUnitTarget()->ToCreature();
|
||||
if (creature->GetCreatureType() != CREATURE_TYPE_CRITTER && creature->loot.loot_type != LOOT_SKINNING && !creature->loot.isLooted())
|
||||
if (creature->GetCreatureType() != CREATURE_TYPE_CRITTER && !creature->loot.isLooted())
|
||||
return SPELL_FAILED_TARGET_NOT_LOOTED;
|
||||
|
||||
uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill();
|
||||
|
||||
bool alreadySkinned = creature->loot.loot_type == LOOT_SKINNING && creature->GetSkinner() == m_caster->GetGUID();
|
||||
|
||||
int32 skillValue = m_caster->ToPlayer()->GetSkillValue(skill);
|
||||
int32 TargetLevel = m_targets.GetUnitTarget()->getLevel();
|
||||
int32 ReqValue = (skillValue < 100 ? (TargetLevel-10) * 10 : TargetLevel * 5);
|
||||
@@ -5074,7 +5072,7 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
// chance for fail at orange skinning attempt
|
||||
if ((m_selfContainer && (*m_selfContainer) == this) &&
|
||||
skillValue < sWorld->GetConfigMaxSkillValue() &&
|
||||
(ReqValue < 0 ? 0 : ReqValue) > irand(skillValue - 25, skillValue + 37) && !alreadySkinned)
|
||||
(ReqValue < 0 ? 0 : ReqValue) > irand(skillValue - 25, skillValue + 37))
|
||||
return SPELL_FAILED_TRY_AGAIN;
|
||||
|
||||
break;
|
||||
|
||||
@@ -4710,28 +4710,16 @@ void Spell::EffectSkinning(SpellEffIndex /*effIndex*/)
|
||||
|
||||
uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill();
|
||||
|
||||
bool awardPoints = true;
|
||||
|
||||
// Check if a skinning loot table was already generated for this creature
|
||||
if (creature->loot.loot_type == LOOT_SKINNING)
|
||||
{
|
||||
if (creature->GetSkinner() != m_caster->GetGUID())
|
||||
return;
|
||||
|
||||
awardPoints = false; // Do not grant skill points for this loot, they were already granted the first time.
|
||||
}
|
||||
else
|
||||
creature->SetSkinner(m_caster->GetGUID());
|
||||
|
||||
m_caster->ToPlayer()->SendLoot(creature->GetGUID(), LOOT_SKINNING);
|
||||
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
|
||||
creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
|
||||
|
||||
int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
|
||||
|
||||
int32 skillValue = m_caster->ToPlayer()->GetPureSkillValue(skill);
|
||||
|
||||
// Double chances for elites
|
||||
if (awardPoints)
|
||||
m_caster->ToPlayer()->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1);
|
||||
m_caster->ToPlayer()->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1);
|
||||
}
|
||||
|
||||
void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
|
||||
|
||||
Reference in New Issue
Block a user