diff options
author | Shauren <none@none> | 2010-09-11 21:28:55 +0200 |
---|---|---|
committer | Shauren <none@none> | 2010-09-11 21:28:55 +0200 |
commit | d714d0eb20767ec6acbe48aafcbb008aafd35a0e (patch) | |
tree | 2213adfa26c29ee526febbe0aa473289e78bfdf2 | |
parent | 1de7e5bed179a2c1bcaf7cdb68fb377c39afd51a (diff) |
Core/Loot: Reverted revision 44a1f284dd3e
Core/Loot: Implemented automatic currency distribution in better way, applying all conditions and updating achievements
Closes issue #3912.
--HG--
branch : trunk
extra : rebase_source : 35c2a59d213793ee29dfd0fc1acb7c15b375b049
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 68 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 1 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 111 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.h | 10 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Handlers/LootHandler.cpp | 76 |
5 files changed, 115 insertions, 151 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index fc9c83a395b..34719457084 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -22723,6 +22723,74 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons } } +void Player::StoreLootItem(uint8 lootSlot, Loot* loot) +{ + QuestItem *qitem = NULL; + QuestItem *ffaitem = NULL; + QuestItem *conditem = NULL; + + LootItem *item = loot->LootItemInSlot(lootSlot, this, &qitem, &ffaitem, &conditem); + + if (!item) + { + SendEquipError(EQUIP_ERR_ALREADY_LOOTED, NULL, NULL); + return; + } + + // questitems use the blocked field for other purposes + if (!qitem && item->is_blocked) + { + SendLootRelease(GetLootGUID()); + return; + } + + ItemPosCountVec dest; + uint8 msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count); + if (msg == EQUIP_ERR_OK) + { + Item * newitem = StoreNewItem(dest, item->itemid, true, item->randomPropertyId); + + if (qitem) + { + qitem->is_looted = true; + //freeforall is 1 if everyone's supposed to get the quest item. + if (item->freeforall || loot->GetPlayerQuestItems().size() == 1) + SendNotifyLootItemRemoved(lootSlot); + else + loot->NotifyQuestItemRemoved(qitem->index); + } + else + { + if (ffaitem) + { + //freeforall case, notify only one player of the removal + ffaitem->is_looted = true; + SendNotifyLootItemRemoved(lootSlot); + } + else + { + //not freeforall, notify everyone + if (conditem) + conditem->is_looted = true; + loot->NotifyItemRemoved(lootSlot); + } + } + + //if only one person is supposed to loot the item, then set it to looted + if (!item->freeforall) + item->is_looted = true; + + --loot->unlootedCount; + + SendNewItem(newitem, uint32(item->count), false, false, true); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); + } + else + SendEquipError(msg, NULL, NULL, item->itemid); +} + uint32 Player::CalculateTalentsPoints() const { uint32 base_talent = getLevel() < 10 ? 0 : getLevel()-9; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 30f93b2be4c..c1b8d75dcb8 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1194,6 +1194,7 @@ class Player : public Unit, public GridObject<Player> bool StoreNewItemInBestSlots(uint32 item_id, uint32 item_count); void AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, bool broadcast = false); void AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast = false) { AutoStoreLoot(NULL_BAG,NULL_SLOT,loot_id,store,broadcast); } + void StoreLootItem(uint8 lootSlot, Loot* loot); uint8 _CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL) const; uint8 _CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item *pItem = NULL, bool swap = false, uint32* no_space_count = NULL) const; diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 5a6d173487b..85f0cd869ee 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -37,18 +37,18 @@ static Rates const qualityToRate[MAX_ITEM_QUALITY] = { RATE_DROP_ITEM_ARTIFACT, // ITEM_QUALITY_ARTIFACT }; -LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true, true); -LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true, false); -LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true, false); -LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true, true); -LootStore LootTemplates_Item("item_loot_template", "item entry", true, false); -LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false, false); -LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true, false); -LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true, false); -LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true, false); -LootStore LootTemplates_Reference("reference_loot_template", "reference id", false, false); -LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true, false); -LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false, false); +LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true); +LootStore LootTemplates_Disenchant("disenchant_loot_template", "item disenchant id", true); +LootStore LootTemplates_Fishing("fishing_loot_template", "area id", true); +LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true); +LootStore LootTemplates_Item("item_loot_template", "item entry", true); +LootStore LootTemplates_Mail("mail_loot_template", "mail template id", false); +LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true); +LootStore LootTemplates_Pickpocketing("pickpocketing_loot_template", "creature pickpocket lootid", true); +LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true); +LootStore LootTemplates_Reference("reference_loot_template", "reference id", false); +LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true); +LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false); class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed) { @@ -57,8 +57,7 @@ class LootTemplate::LootGroup // A set of loot def bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry bool HasQuestDropForPlayer(Player const * player) const; // The same for active quests of the player - void Process(Loot& loot, Player* lootOwner, uint16 lootMode, bool autoProcessCurrency) const; - // Rolls an item from the group (if any) and adds the item to the loot + void Process(Loot& loot, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot float RawTotalChance() const; // Overall chance for the group (without equal chanced items) float TotalChance() const; // Overall chance for the group @@ -429,7 +428,7 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo items.reserve(MAX_NR_LOOT_ITEMS); quest_items.reserve(MAX_NR_QUEST_ITEMS); - tab->Process(*this, store, lootOwner, store.IsRatesAllowed(), lootMode); // Processing is done there, callback via Loot::AddItem() + tab->Process(*this, store, store.IsRatesAllowed(), lootMode); // Processing is done there, callback via Loot::AddItem() // Setting access rights for group loot case Group * pGroup = lootOwner->GetGroup(); @@ -470,6 +469,22 @@ void Loot::FillNotNormalLootFor(Player* pl) qmapitr = PlayerNonQuestNonFFAConditionalItems.find(plguid); if (qmapitr == PlayerNonQuestNonFFAConditionalItems.end()) FillNonQuestNonFFAConditionalLoot(pl); + + // Process currency items + uint32 max_slot = GetMaxSlotInLootFor(pl); + uint32 itemId = 0; + uint32 itemsSize = uint32(items.size()); + for (uint32 i = 0; i < max_slot; ++i) + { + if (i < items.size()) + itemId = items[i].itemid; + else + itemId = quest_items[i-itemsSize].itemid; + + if (ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemId)) + if (proto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) + pl->StoreLootItem(i, this); + } } QuestItemList* Loot::FillFFALoot(Player* player) @@ -992,7 +1007,7 @@ void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/) } // Rolls an item from the group (if any takes its chance) and adds the item to the loot -void LootTemplate::LootGroup::Process(Loot& loot, Player* lootOwner, uint16 lootMode, bool autoProcessCurrency) const +void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const { // build up list of possible drops LootStoreItemList EqualPossibleDrops = EqualChanced; @@ -1048,16 +1063,8 @@ void LootTemplate::LootGroup::Process(Loot& loot, Player* lootOwner, uint16 loot bool duplicate = false; if (ItemPrototype const *_proto = sItemStorage.LookupEntry<ItemPrototype>(item->itemid)) { - LootItemList::const_iterator _item = loot.items.begin(); - if (autoProcessCurrency) - if (LootTemplate::ProcessCurrency(lootOwner, itr, _proto)) - { - duplicate = true; // don't add to loot - _item = loot.items.end(); // skip next loop - } - uint8 _item_counter = 0; - for (; _item != loot.items.end(); ++_item) + for (LootItemList::const_iterator _item = loot.items.begin(); _item != loot.items.end(); ++_item) if (_item->itemid == item->itemid) // search through the items that have already dropped { ++_item_counter; @@ -1175,15 +1182,14 @@ void LootTemplate::CopyConditions(ConditionList conditions) } // Rolls for every item in the template and adds the rolled items the the loot -void LootTemplate::Process(Loot& loot, LootStore const& store, Player* lootOwner, bool rate, uint16 lootMode, uint8 groupId) const +void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint16 lootMode, uint8 groupId) const { - bool autoProcessCurrency = store.IsCurrencyAutoDistributed(); if (groupId) // Group reference uses own processing of the group { if (groupId > Groups.size()) return; // Error message already printed at loading stage - Groups[groupId-1].Process(loot, lootOwner, lootMode, autoProcessCurrency); + Groups[groupId-1].Process(loot, lootMode); return; } @@ -1198,10 +1204,6 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, Player* lootOwner if (ItemPrototype const *_proto = sItemStorage.LookupEntry<ItemPrototype>(i->itemid)) { - if (autoProcessCurrency) - if (ProcessCurrency(lootOwner, i, _proto)) - continue; // don't add to loot - uint8 _item_counter = 0; LootItemList::const_iterator _item = loot.items.begin(); for (; _item != loot.items.end(); ++_item) @@ -1225,7 +1227,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, Player* lootOwner continue; // Error message already printed at loading stage for (uint32 loop = 0; loop < i->maxcount; ++loop) // Ref multiplicator - Referenced->Process(loot, store, lootOwner, rate, lootMode, i->group); + Referenced->Process(loot, store, rate, lootMode, i->group); } else // Plain entries (not a reference, not grouped) loot.AddItem(*i); // Chance is already checked, just add @@ -1233,48 +1235,7 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, Player* lootOwner // Now processing groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - i->Process(loot, lootOwner, lootMode, autoProcessCurrency); -} - -bool LootTemplate::ProcessCurrency(Player* lootOwner, const LootStoreItemList::const_iterator& lootItem, ItemPrototype const* pProto) -{ - uint32 itemId = lootItem->itemid; - if (pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) // Tokens appear in currency of player and remove from drop - { - uint32 count = urand(lootItem->mincountOrRef, lootItem->maxcount); - if (Group* pGroup = lootOwner->GetGroup()) - { - for (GroupReference* itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - if (Player* pGroupGuy = itr->getSource()) - { - if (!pGroupGuy->IsAtGroupRewardDistance(lootOwner)) - continue; - - ItemPosCountVec dest; - uint8 msg = pGroupGuy->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count); - if (msg == EQUIP_ERR_OK) - { - Item* pItem = pGroupGuy->StoreNewItem(dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); - pGroupGuy->SendNewItem(pItem, count, true, false); - } - } - } - } - else - { - ItemPosCountVec dest; - uint8 msg = lootOwner->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count); - if (msg == EQUIP_ERR_OK) - { - Item* pItem = lootOwner->StoreNewItem(dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); - lootOwner->SendNewItem(pItem, count, true, false); - } - } - return true; - } - - return false; + i->Process(loot, lootMode); } // True if template includes at least 1 quest drop entry diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 9618c16fdfe..f057c19ce41 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -26,7 +26,6 @@ #include "RefManager.h" #include "SharedDefines.h" #include "ConditionMgr.h" -#include "ItemPrototype.h" #include <map> #include <vector> @@ -173,8 +172,8 @@ typedef std::set<uint32> LootIdSet; class LootStore { public: - explicit LootStore(char const* name, char const* entryName, bool ratesAllowed, bool autoDistributeCurrency) - : m_name(name), m_entryName(entryName), m_ratesAllowed(ratesAllowed), m_autoDistributeCurrency(autoDistributeCurrency) {} + explicit LootStore(char const* name, char const* entryName, bool ratesAllowed) + : m_name(name), m_entryName(entryName), m_ratesAllowed(ratesAllowed) {} virtual ~LootStore() { Clear(); } @@ -196,7 +195,6 @@ class LootStore char const* GetName() const { return m_name; } char const* GetEntryName() const { return m_entryName; } bool IsRatesAllowed() const { return m_ratesAllowed; } - bool IsCurrencyAutoDistributed() const { return m_autoDistributeCurrency; } protected: void LoadLootTable(); void Clear(); @@ -205,7 +203,6 @@ class LootStore char const* m_name; char const* m_entryName; bool m_ratesAllowed; - bool m_autoDistributeCurrency; }; class LootTemplate @@ -217,8 +214,7 @@ class LootTemplate // Adds an entry to the group (at loading stage) void AddEntry(LootStoreItem& item); // Rolls for every item in the template and adds the rolled items the the loot - void Process(Loot& loot, LootStore const& store, Player* lootOwner, bool rate, uint16 lootMode, uint8 groupId = 0) const; - static bool ProcessCurrency(Player* lootOwner, const LootStoreItemList::const_iterator& lootItem, ItemPrototype const* pProto); + void Process(Loot& loot, LootStore const& store, bool rate, uint16 lootMode, uint8 groupId = 0) const; void CopyConditions(ConditionList conditions); // True if template includes at least 1 quest drop entry diff --git a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp b/src/server/game/Server/Protocol/Handlers/LootHandler.cpp index 524c05be372..b2345dfab4f 100644 --- a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/LootHandler.cpp @@ -35,10 +35,10 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) { sLog.outDebug("WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); - Player *player = GetPlayer(); - uint64 lguid = player->GetLootGUID(); - Loot *loot; - uint8 lootSlot; + Player* player = GetPlayer(); + uint64 lguid = player->GetLootGUID(); + Loot* loot = NULL; + uint8 lootSlot = 0; recv_data >> lootSlot; @@ -75,6 +75,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) player->SendLootRelease(lguid); return; } + loot = &bones->loot; } else @@ -92,70 +93,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) loot = &pCreature->loot; } - QuestItem *qitem = NULL; - QuestItem *ffaitem = NULL; - QuestItem *conditem = NULL; - - LootItem *item = loot->LootItemInSlot(lootSlot,player,&qitem,&ffaitem,&conditem); - - if (!item) - { - player->SendEquipError(EQUIP_ERR_ALREADY_LOOTED, NULL, NULL); - return; - } - - // questitems use the blocked field for other purposes - if (!qitem && item->is_blocked) - { - player->SendLootRelease(lguid); - return; - } - - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count); - if (msg == EQUIP_ERR_OK) - { - Item * newitem = player->StoreNewItem(dest, item->itemid, true, item->randomPropertyId); - - if (qitem) - { - qitem->is_looted = true; - //freeforall is 1 if everyone's supposed to get the quest item. - if (item->freeforall || loot->GetPlayerQuestItems().size() == 1) - player->SendNotifyLootItemRemoved(lootSlot); - else - loot->NotifyQuestItemRemoved(qitem->index); - } - else - { - if (ffaitem) - { - //freeforall case, notify only one player of the removal - ffaitem->is_looted=true; - player->SendNotifyLootItemRemoved(lootSlot); - } - else - { - //not freeforall, notify everyone - if (conditem) - conditem->is_looted=true; - loot->NotifyItemRemoved(lootSlot); - } - } - - //if only one person is supposed to loot the item, then set it to looted - if (!item->freeforall) - item->is_looted = true; - - --loot->unlootedCount; - - player->SendNewItem(newitem, uint32(item->count), false, false, true); - player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); - player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count); - player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); - } - else - player->SendEquipError(msg, NULL, NULL, item->itemid); + player->StoreLootItem(lootSlot, loot); } void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recv_data*/) @@ -516,7 +454,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) if (slotid > pLoot->items.size()) { - sLog.outDebug("AutoLootItem: Player %s might be using a hack! (slot %d, size %lu)",GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); + sLog.outDebug("MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)",GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); return; } |