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
This commit is contained in:
Shauren
2010-09-11 21:28:55 +02:00
parent 1de7e5bed1
commit d714d0eb20
5 changed files with 115 additions and 151 deletions
@@ -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;
+1
View File
@@ -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;
+36 -75
View File
@@ -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
+3 -7
View File
@@ -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
@@ -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;
}