diff options
| author | xinef1 <w.szyszko2@gmail.com> | 2017-02-13 20:42:06 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2017-02-13 20:42:06 +0100 |
| commit | 2412886ef69d305df1bd6e6422ca3134c0ab1449 (patch) | |
| tree | 147a8b69982451adafba2b78da4b8ce3ea82a201 /src | |
| parent | 4536846d7d30508a046f394d1f561a2c3fdcf5f0 (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.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; |
