diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/Battlefield/Zones/BattlefieldWG.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/Corpse/Corpse.cpp | 3 | ||||
| -rw-r--r-- | src/server/game/Entities/Corpse/Corpse.h | 1 | ||||
| -rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 16 | ||||
| -rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 8 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 51 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 3 | ||||
| -rw-r--r-- | src/server/game/Loot/LootMgr.h | 2 | ||||
| -rw-r--r-- | src/server/game/Miscellaneous/SharedDefines.h | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 25 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 2 |
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; |
