diff options
-rw-r--r-- | sql/updates/world/2012_07_05_00_world_item_template.sql | 1 | ||||
-rwxr-xr-x | src/server/game/Entities/Item/ItemPrototype.h | 1 | ||||
-rwxr-xr-x | src/server/game/Groups/Group.cpp | 118 | ||||
-rwxr-xr-x | src/server/game/Handlers/LootHandler.cpp | 6 | ||||
-rwxr-xr-x | src/server/game/Loot/LootMgr.cpp | 67 | ||||
-rwxr-xr-x | src/server/game/Loot/LootMgr.h | 3 |
6 files changed, 173 insertions, 23 deletions
diff --git a/sql/updates/world/2012_07_05_00_world_item_template.sql b/sql/updates/world/2012_07_05_00_world_item_template.sql new file mode 100644 index 00000000000..be6dc1979c1 --- /dev/null +++ b/sql/updates/world/2012_07_05_00_world_item_template.sql @@ -0,0 +1 @@ +UPDATE `item_template` SET `flagsCustom` = `flagsCustom` | 3 WHERE `entry` IN (50226,50231,50274); diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h index 5dbf1cad5bb..17a9e82db7d 100755 --- a/src/server/game/Entities/Item/ItemPrototype.h +++ b/src/server/game/Entities/Item/ItemPrototype.h @@ -196,6 +196,7 @@ enum ItemFlagsCustom { ITEM_FLAGS_CU_DURATION_REAL_TIME = 0x0001, // Item duration will tick even if player is offline ITEM_FLAGS_CU_IGNORE_QUEST_STATUS = 0x0002, // No quest status will be checked when this item drops + ITEM_FLAGS_CU_FOLLOW_LOOT_RULES = 0x0003, // Item will always follow group/master/need before greed looting rules }; enum BAG_FAMILY_MASK diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 3a6390cd83a..26faa7e6ae8 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -949,6 +949,64 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) else i->is_underthreshold = true; } + + for (i = loot->quest_items.begin(); i != loot->quest_items.end(); ++i, ++itemSlot) + { + if (!i->follow_loot_rules) + continue; + + item = sObjectMgr->GetItemTemplate(i->itemid); + if (!item) + { + //sLog->outDebug("Group::GroupLoot: missing item prototype for item with id: %d", i->itemid); + continue; + } + + uint64 newitemGUID = MAKE_NEW_GUID(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), 0, HIGHGUID_ITEM); + Roll* r = new Roll(newitemGUID, *i); + + //a vector is filled with only near party members + for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* member = itr->getSource(); + if (!member || !member->GetSession()) + continue; + + if (i->AllowedForPlayer(member)) + { + if (member->IsWithinDistInMap(pLootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) + { + r->totalPlayersRolling++; + r->playerVote[member->GetGUID()] = NOT_EMITED_YET; + } + } + } + + if (r->totalPlayersRolling > 0) + { + r->setLoot(loot); + r->itemSlot = itemSlot; + + loot->quest_items[itemSlot - loot->items.size()].is_blocked = true; + + SendLootStartRoll(60000, pLootedObject->GetMapId(), *r); + + RollId.push_back(r); + + if (Creature* creature = pLootedObject->ToCreature()) + { + creature->m_groupLootTimer = 60000; + creature->lootingGroupLowGUID = GetLowGUID(); + } + else if (GameObject* go = pLootedObject->ToGameObject()) + { + go->m_groupLootTimer = 60000; + go->lootingGroupLowGUID = GetLowGUID(); + } + } + else + delete r; + } } void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) @@ -1033,6 +1091,66 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) else i->is_underthreshold = true; } + + for (std::vector<LootItem>::iterator i = loot->quest_items.begin(); i != loot->quest_items.end(); ++i, ++itemSlot) + { + if (!i->follow_loot_rules) + continue; + + item = sObjectMgr->GetItemTemplate(i->itemid); + uint64 newitemGUID = MAKE_NEW_GUID(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), 0, HIGHGUID_ITEM); + Roll* r = new Roll(newitemGUID, *i); + + for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* playerToRoll = itr->getSource(); + if (!playerToRoll || !playerToRoll->GetSession()) + continue; + + bool allowedForPlayer = i->AllowedForPlayer(playerToRoll); + if (allowedForPlayer && playerToRoll->IsWithinDistInMap(lootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) + { + r->totalPlayersRolling++; + r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; + } + } + + if (r->totalPlayersRolling > 0) + { + r->setLoot(loot); + r->itemSlot = itemSlot; + + loot->quest_items[itemSlot - loot->items.size()].is_blocked = true; + + //Broadcast Pass and Send Rollstart + for (Roll::PlayerVote::const_iterator itr = r->playerVote.begin(); itr != r->playerVote.end(); ++itr) + { + Player* p = ObjectAccessor::FindPlayer(itr->first); + if (!p || !p->GetSession()) + continue; + + if (itr->second == PASS) + SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r); + else + SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, p->CanRollForItemInLFG(item, lootedObject) == EQUIP_ERR_OK, *r); + } + + RollId.push_back(r); + + if (Creature* creature = lootedObject->ToCreature()) + { + creature->m_groupLootTimer = 60000; + creature->lootingGroupLowGUID = GetLowGUID(); + } + else if (GameObject* go = lootedObject->ToGameObject()) + { + go->m_groupLootTimer = 60000; + go->lootingGroupLowGUID = GetLowGUID(); + } + } + else + delete r; + } } void Group::MasterLoot(Loot* /*loot*/, WorldObject* pLootedObject) diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 339c7a44d9f..72e0b63f5b6 100755 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -472,16 +472,18 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) if (!loot) return; - if (slotid > loot->items.size()) + if (slotid > loot->items.size() + loot->quest_items.size()) { sLog->outDebug(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName(), slotid, (unsigned long)loot->items.size()); return; } - LootItem& item = loot->items[slotid]; + LootItem& item = slotid > loot->items.size() ? loot->quest_items[slotid - loot->items.size()] : loot->items[slotid]; ItemPosCountVec dest; InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); + if (item.follow_loot_rules && !item.AllowedForPlayer(target)) + msg = EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; if (msg != EQUIP_ERR_OK) { target->SendEquipError(msg, NULL, NULL, item.itemid); diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index b4433906674..8d80c145026 100755 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -322,6 +322,7 @@ LootItem::LootItem(LootStoreItem const& li) ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid); freeforall = proto && (proto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT); + follow_loot_rules = proto && (proto->FlagsCu & ITEM_FLAGS_CU_FOLLOW_LOOT_RULES); needs_quest = li.needs_quest; @@ -358,12 +359,7 @@ bool LootItem::AllowedForPlayer(Player const* player) const // check quest requirements if (!(pProto->FlagsCu & ITEM_FLAGS_CU_IGNORE_QUEST_STATUS) && ((needs_quest || (pProto->StartQuest && player->GetQuestStatus(pProto->StartQuest) != QUEST_STATUS_NONE)) && !player->HasQuestForItem(itemid))) - if (Group const* group = player->GetGroup()) - { - if (pProto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT || ((pProto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT) == 0 && (group->GetLootMethod() != MASTER_LOOT || group->GetLooterGuid() != player->GetGUID()))) - return false; - } - else return false; + return false; return true; } @@ -517,18 +513,20 @@ QuestItemList* Loot::FillQuestLoot(Player* player) for (uint8 i = 0; i < quest_items.size(); ++i) { LootItem &item = quest_items[i]; - if (!item.is_looted && item.AllowedForPlayer(player)) + + if ((!item.is_looted && item.AllowedForPlayer(player)) || (item.follow_loot_rules && player->GetGroup() && player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetLooterGuid() == player->GetGUID())) { ql->push_back(QuestItem(i)); - // questitems get blocked when they first appear in a + // quest items get blocked when they first appear in a // player's quest vector // // increase once if one looter only, looter-times if free for all - if (item.freeforall || !item.is_blocked) + if (item.freeforall && !item.is_blocked) + { ++unlootedCount; - - item.is_blocked = true; + item.is_blocked = true; + } if (items.size() + ql->size() == MAX_NR_LOOT_ITEMS) break; @@ -551,7 +549,7 @@ QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player, bool pres for (uint8 i = 0; i < items.size(); ++i) { LootItem &item = items[i]; - if (!item.is_looted && !item.freeforall && item.AllowedForPlayer(player)) + if (!item.is_looted && !item.freeforall && (item.AllowedForPlayer(player)) || (item.follow_loot_rules && player->GetGroup() && player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGroup()->GetLooterGuid() == player->GetGUID())) { if (presentAtLooting) item.AddAllowedLooter(player); @@ -907,8 +905,24 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) { b << uint8(l.items.size() + (qi - q_list->begin())); b << item; - if (!item.freeforall) - b << uint8(partySlotType); + if (item.follow_loot_rules) + { + switch (lv.permission) + { + case MASTER_PERMISSION: + b << uint8(LOOT_SLOT_TYPE_MASTER); + break; + case GROUP_PERMISSION: + if (!item.is_blocked) + b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT); + else + b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING); + break; + default: + b << uint8(slotType); + break; + } + } else b << uint8(slotType); ++itemsShown; @@ -928,10 +942,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) { b << uint8(fi->index); b << item; - if (!item.freeforall) - b << uint8(partySlotType); - else - b << uint8(slotType); + b << uint8(slotType); ++itemsShown; } } @@ -949,8 +960,24 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) { b << uint8(ci->index); b << item; - if (!item.freeforall) - b << uint8(partySlotType); + if (item.follow_loot_rules) + { + switch (lv.permission) + { + case MASTER_PERMISSION: + b << uint8(LOOT_SLOT_TYPE_MASTER); + break; + case GROUP_PERMISSION: + if (!item.is_blocked) + b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT); + else + b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING); + break; + default: + b << uint8(slotType); + break; + } + } else b << uint8(slotType); ++itemsShown; diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 4a6becc7eff..1af5bd1ea62 100755 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -140,6 +140,7 @@ struct LootItem bool is_underthreshold : 1; bool is_counted : 1; bool needs_quest : 1; // quest drop + bool follow_loot_rules : 1; // Constructor, copies most fields from LootStoreItem, generates random count and random suffixes/properties // Should be called for non-reference LootStoreItem entries only (mincountOrRef > 0) @@ -280,6 +281,7 @@ struct Loot QuestItemMap const& GetPlayerNonQuestNonFFAConditionalItems() const { return PlayerNonQuestNonFFAConditionalItems; } std::vector<LootItem> items; + std::vector<LootItem> quest_items; uint32 gold; uint8 unlootedCount; uint64 roundRobinPlayer; // GUID of the player having the Round-Robin ownership for the loot. If 0, round robin owner has released. @@ -344,7 +346,6 @@ struct Loot QuestItemList* FillQuestLoot(Player* player); QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting); - std::vector<LootItem> quest_items; std::set<uint64> PlayersLooting; QuestItemMap PlayerQuestItems; QuestItemMap PlayerFFAItems; |