楼主: 微笑

[未归类主题(有空慢慢分)] 【一键范围拾取】-适合新AZ--补丁文件

[复制链接]
发表于 2021-7-5 22:05:14 | 显示全部楼层


---
modules/WackyCore/WackyCoreScripts.cpp           |  63 +++
src/server/game/Entities/GameObject/GameObject.h |   2 +
src/server/game/Entities/Object/Object.cpp       |  18 +
src/server/game/Entities/Object/Object.h         |   3 +
src/server/game/Entities/Player/Player.cpp       | 625 +++++++++++++++++++----
src/server/game/Entities/Player/Player.h         |   3 +-
src/server/game/Events/TF_coreload.cpp           |   5 +-
src/server/game/Globals/ObjectMgr.h              |   1 +
src/server/game/Grids/Notifiers/GridNotifiers.h  |  19 +
src/server/game/Handlers/LootHandler.cpp         | 385 ++++++++++----
src/server/game/Loot/LootItemStorage.cpp         |   4 +-
src/server/game/Loot/LootItemStorage.h           |   2 +-
src/server/game/Loot/LootMgr.h                   |   1 +
src/server/game/Server/WorldSession.h            |   7 +-
14 files changed, 937 insertions(+), 201 deletions(-)

diff --git a/modules/WackyCore/WackyCoreScripts.cpp b/modules/WackyCore/WackyCoreScripts.cpp
index bd938ee..3dc382c 100644
--- a/modules/WackyCore/WackyCoreScripts.cpp
+++ b/modules/WackyCore/WackyCoreScripts.cpp
@@ -53,9 +53,14 @@ public:
             { "alldemorph",   SEC_ADMINISTRATOR,      false,      &HandleDeMorphAllCommand,       "" },
             { "全体模式",   SEC_ADMINISTRATOR,      false,      &quantimoshi,       "" },
             { "中立模式",   SEC_ADMINISTRATOR,      false,      &zhonglimoshi,       "" },
+            //{ "_loot",                SEC_ADMINISTRATOR,                        false,                &HandleAOELootCommand,                                "" },
+            { "_loot",                SEC_CONSOLE,                        true,                &HandleAOELootCommand,                                "",  },
         };
         return JfCommandTable;
+
     }
+  
+

     static bool HandleKillAllCommand(ChatHandler * handler, const char * args)
     {
@@ -313,6 +318,62 @@ public:
                 handler->PSendSysMessage(sObjectMgr->get_TF_String(7), sObjectMgr->GetNameLinkColor(playerTarget).c_str(), count);
         }

+        return true;
+    }
+
+    static void AoeLoot(Player* player, float range)
+    {
+        if (!player->IsAlive())
+        {
+            ChatHandler(player->GetSession()).PSendSysMessage("你已经死亡");
+            return;
+        }
+
+        if (player->IsNonMeleeSpellCast(false))
+            player->InterruptNonMeleeSpells(false);
+
+        std::list<Creature*> list;
+        player->GetCreatureListInGrid(list, range);
+        if (!list.empty())
+        {
+            for (std::list<Creature*>::iterator itr = list.begin(); itr != list.end(); ++itr)
+            {
+                Creature* c = *itr;
+
+                if (c->IsAlive())
+                    continue;
+
+                uint64 guid = c->GetGUID();
+                Loot* loot = &c->loot;
+
+                WorldPacket p1(CMSG_LOOT);
+                p1 << guid;
+                player->GetSession()->HandleLootFarOpcode(p1, range);
+
+                for (size_t lootSlot = 0; lootSlot < loot->GetMaxSlotInLootFor(player); lootSlot++)
+                {
+                    WorldPacket p(CMSG_AUTOSTORE_LOOT_ITEM);
+                    p << lootSlot;
+                    player->GetSession()->HandleAutostoreLootItemFarOpcode(p, range);
+                }
+
+                WorldPacket p2(CMSG_LOOT_MONEY);
+                player->GetSession()->HandleLootMoneyFarOpcode(p2, range);
+
+                player->GetSession()->DoLootRelease(guid, range);
+            }
+        }
+    }
+
+    static bool HandleAOELootCommand(ChatHandler* handler, const char* args)
+    {
+        if (Player* player = handler->GetSession()->GetPlayer())
+            
+            AoeLoot(player, 1000.0f);
+        Player* player = handler->GetSession()->GetPlayer();
+        player->GetSession()->SendAreaTriggerMessage("你已开启范围拾取. 范围:1000码");
+           
+      
         return true;
     }
     static bool HandleVipInfo(ChatHandler* handler, char const* /*args*/)
@@ -427,6 +488,8 @@ public:
         return true;
     }
};
+
+
//////////////////////////////////////////////////////////////////////////////自定义命令

//////////////////////////////////////////////////////////////////////////////世界聊天
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index ca12d08..4a35e8b 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -862,6 +862,8 @@ public:

     Loot        loot;

+   unordered_map<uint32, uint32> LootExtraItems;
+
     Player* GetLootRecipient() const;
     Group* GetLootRecipientGroup() const;
     void SetLootRecipient(Unit* unit);
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 9faccd8..23b2d5c 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -2445,7 +2445,25 @@ void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>& creatureL

     cell.Visit(pair, visitor, *(this->GetMap()), *this, maxSearchRange);
}
+void WorldObject::GetCreatureListInGrid(std::list<Creature*>& creatureList, float fMaxSearchRange) const
+{
+    CellCoord pair(acore::ComputeCellCoord(this->GetPositionX(), this->GetPositionY()));
+    Cell cell(pair);
+    cell.SetNoCreate();
+
+    acore::AllCreaturesInRange check(this, fMaxSearchRange);
+    acore::CreatureListSearcher<acore::AllCreaturesInRange> searcher(this, creatureList, check);
+    TypeContainerVisitor<acore::CreatureListSearcher<acore::AllCreaturesInRange>, GridTypeMapContainer> visitor(searcher);

+    cell.Visit(pair, visitor, *(this->GetMap()), *this, fMaxSearchRange);
+}
+
+void WorldObject::GetPlayerListInGrid(std::list<Player*>& playerList, float maxSearchRange, bool reqAlive) const
+{
+    acore::AnyPlayerInObjectRangeCheck checker(this, maxSearchRange, reqAlive);
+    acore::PlayerListSearcher<acore::AnyPlayerInObjectRangeCheck> searcher(this, playerList, checker);
+    this->VisitNearbyWorldObject(maxSearchRange, searcher);
+}
/*
namespace acore
{
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index e368ad5..c199494 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -1003,6 +1003,9 @@ public:
     void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange) const;
     void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange) const;

+    void GetCreatureListInGrid(std::list<Creature*>& lList, float fMaxSearchRange) const;
+    void GetPlayerListInGrid(std::list<Player*>& playerList, float maxSearchRange, bool reqAlive = true) const;
+
     void DestroyForNearbyPlayers();
     virtual void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false);
     void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& player_set);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 12979c4..b4a237c 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -9149,7 +9149,8 @@ void Player::SendLootRelease(uint64 guid)
     SendDirectMessage(&data);
}

-void Player::SendLoot(uint64 guid, LootType loot_type)
+
+void Player::SendLoot(uint64 guid, LootType loot_type, float range)
{
     if (uint64 lguid = GetLootGUID())
         m_session->DoLootRelease(lguid);
@@ -9157,19 +9158,15 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
     Loot* loot = 0;
     PermissionTypes permission = ALL_PERMISSION;

-#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
-    sLog->outDebug(LOG_FILTER_LOOT, "Player::SendLoot");
-#endif
+    ;//sLog->outDebug(LOG_FILTER_LOOT, "Player::SendLoot");
     if (IS_GAMEOBJECT_GUID(guid))
     {
-#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
-        sLog->outDebug(LOG_FILTER_LOOT, "IS_GAMEOBJECT_GUID(guid)");
-#endif
+        ;//sLog->outDebug(LOG_FILTER_LOOT, "IS_GAMEOBJECT_GUID(guid)");
         GameObject* go = GetMap()->GetGameObject(guid);

         // not check distance for GO in case owned GO (fishing bobber case, for example)
         // And permit out of range GO with no owner in case fishing hole
-        if (!go || (loot_type != LOOT_FISHINGHOLE && ((loot_type != LOOT_FISHING && loot_type != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault()))
+        if (!go || (loot_type != LOOT_FISHINGHOLE && ((loot_type != LOOT_FISHING && loot_type != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, range)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault()))
         {
             go->ForceValuesUpdateAtIndex(GAMEOBJECT_BYTES_1);
             SendLootRelease(guid);
@@ -9180,7 +9177,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)

         // Xinef: loot was generated and respawntime has passed since then, allow to recreate loot
         // Xinef: to avoid bugs, this rule covers spawned gameobjects only
-        if (go->isSpawnedByDefault() && go->getLootState() == GO_ACTIVATED && !go->loot.isLooted() && go->GetLootGenerationTime() + go->GetRespawnDelay() < time(nullptr))
+        if (go->isSpawnedByDefault() && go->getLootState() == GO_ACTIVATED && !go->loot.isLooted() && go->GetLootGenerationTime() + go->GetRespawnDelay() < time(NULL))
             go->SetLootState(GO_READY);

         if (go->getLootState() == GO_READY)
@@ -9190,8 +9187,8 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
             //TODO: fix this big hack
             if ((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S))
                 if (Battleground* bg = GetBattleground())
-                    if (bg->GetBgTypeID(true) == BATTLEGROUND_AV)
-                        if (!bg->ToBattlegroundAV()->PlayerCanDoMineQuest(go->GetEntry(), GetBgTeamId()))
+                    if (bg->GetBgTypeID() == BATTLEGROUND_AV)
+                        if (!bg->ToBattlegroundAV()->PlayerCanDoMineQuest(go->GetEntry(), GetTeamId()))
                         {
                             go->ForceValuesUpdateAtIndex(GAMEOBJECT_BYTES_1);
                             SendLootRelease(guid);
@@ -9209,6 +9206,10 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
                 if (groupRules)
                     group->UpdateLooterGuid(go, true);

+                loot->LootExtraItems = go->LootExtraItems;
+
+
+
                 loot->FillLoot(lootid, LootTemplates_Gameobject, this, !groupRules, false, go->GetLootMode());
                 go->SetLootGenerationTime();

@@ -9216,8 +9217,6 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
                 if (groupRules && !go->loot.empty())
                     group->UpdateLooterGuid(go);
             }
-            if (GameObjectTemplateAddon const* addon = go->GetTemplateAddon())
-                loot->generateMoneyLoot(addon->mingold, addon->maxgold);

             if (loot_type == LOOT_FISHING)
                 go->getFishLoot(loot, this);
@@ -9230,18 +9229,18 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
                 {
                     switch (group->GetLootMethod())
                     {
-                        case GROUP_LOOT:
-                            // GroupLoot: rolls items over threshold. Items with quality < threshold, round robin
-                            group->GroupLoot(loot, go);
-                            break;
-                        case NEED_BEFORE_GREED:
-                            group->NeedBeforeGreed(loot, go);
-                            break;
-                        case MASTER_LOOT:
-                            group->MasterLoot(loot, go);
-                            break;
-                        default:
-                            break;
+                    case GROUP_LOOT:
+                        // GroupLoot: rolls items over threshold. Items with quality < threshold, round robin
+                        group->GroupLoot(loot, go);
+                        break;
+                    case NEED_BEFORE_GREED:
+                        group->NeedBeforeGreed(loot, go);
+                        break;
+                    case MASTER_LOOT:
+                        group->MasterLoot(loot, go);
+                        break;
+                    default:
+                        break;
                     }
                 }
             }
@@ -9255,23 +9254,25 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
             {
                 switch (group->GetLootMethod())
                 {
-                    case MASTER_LOOT:
-                        permission = group->GetMasterLooterGuid() == GetGUID() ? MASTER_PERMISSION : RESTRICTED_PERMISSION;
-                        break;
-                    case FREE_FOR_ALL:
-                        permission = ALL_PERMISSION;
-                        break;
-                    case ROUND_ROBIN:
-                        permission = ROUND_ROBIN_PERMISSION;
-                        break;
-                    default:
-                        permission = GROUP_PERMISSION;
-                        break;
+                case MASTER_LOOT:
+                    permission = group->GetMasterLooterGuid() == GetGUID() ? MASTER_PERMISSION : RESTRICTED_PERMISSION;
+                    break;
+                case FREE_FOR_ALL:
+                    permission = ALL_PERMISSION;
+                    break;
+                case ROUND_ROBIN:
+                    permission = ROUND_ROBIN_PERMISSION;
+                    break;
+                default:
+                    permission = GROUP_PERMISSION;
+                    break;
                 }
             }
             else
                 permission = ALL_PERMISSION;
         }
+
+        //sServerAnnounce->Announce(this, go->GetEntry(), 0);
     }
     else if (IS_ITEM_GUID(guid))
     {
@@ -9297,26 +9298,28 @@ void Player::SendLoot(uint64 guid, LootType loot_type)

             switch (loot_type)
             {
-                case LOOT_DISENCHANTING:
-                    loot->FillLoot(item->GetTemplate()->DisenchantID, LootTemplates_Disenchant, this, true);
-                    break;
-                case LOOT_PROSPECTING:
-                    loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this, true);
-                    break;
-                case LOOT_MILLING:
-                    loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this, true);
-                    break;
-                default:
-                    loot->generateMoneyLoot(item->GetTemplate()->MinMoneyLoot, item->GetTemplate()->MaxMoneyLoot);
-                    loot->FillLoot(item->GetEntry(), LootTemplates_Item, this, true, loot->gold != 0);
+            case LOOT_DISENCHANTING:
+                loot->FillLoot(item->GetTemplate()->DisenchantID, LootTemplates_Disenchant, this, true);
+                break;
+            case LOOT_PROSPECTING:
+                loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this, true);
+                break;
+            case LOOT_MILLING:
+                loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this, true);
+                break;
+            default:
+                loot->generateMoneyLoot(item->GetTemplate()->MinMoneyLoot, item->GetTemplate()->MaxMoneyLoot);
+                loot->FillLoot(item->GetEntry(), LootTemplates_Item, this, true, loot->gold != 0);

-                    // Xinef: Add to storage
-                    if (loot->gold > 0 || loot->unlootedCount > 0)
-                        sLootItemStorage->AddNewStoredLoot(loot, this);
+                // Xinef: Add to storage
+                if (loot->gold > 0 || loot->unlootedCount > 0)
+                    sLootItemStorage->AddNewStoredLoot(loot, this);

-                    break;
+                break;
             }
         }
+
+        //sServerAnnounce->Announce(this, item->GetEntry(), 1);
     }
     else if (IS_CORPSE_GUID(guid))                          // remove insignia
     {
@@ -9338,7 +9341,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
             // Xinef: For AV Achievement
             if (Battleground* bg = GetBattleground())
             {
-                if (bg->GetBgTypeID(true) == BATTLEGROUND_AV)
+                if (bg->GetBgTypeID() == BATTLEGROUND_AV)
                     loot->FillLoot(1, LootTemplates_Creature, this, true);
             }
             // Xinef: For wintergrasp Quests
@@ -9360,7 +9363,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
         Creature* creature = GetMap()->GetCreature(guid);

         // must be in range and creature must be alive for pickpocket and must be dead for another loot
-        if (!creature || creature->IsAlive() != (loot_type == LOOT_PICKPOCKETING) || !creature->IsWithinDistInMap(this, INTERACTION_DISTANCE))
+        if (!creature || creature->IsAlive() != (loot_type == LOOT_PICKPOCKETING) || !creature->IsWithinDistInMap(this, range))
         {
             SendLootRelease(guid);
             return;
@@ -9422,18 +9425,18 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
                 {
                     switch (recipientGroup->GetLootMethod())
                     {
-                        case GROUP_LOOT:
-                            // GroupLoot: rolls items over threshold. Items with quality < threshold, round robin
-                            recipientGroup->GroupLoot(loot, creature);
-                            break;
-                        case NEED_BEFORE_GREED:
-                            recipientGroup->NeedBeforeGreed(loot, creature);
-                            break;
-                        case MASTER_LOOT:
-                            recipientGroup->MasterLoot(loot, creature);
-                            break;
-                        default:
-                            break;
+                    case GROUP_LOOT:
+                        // GroupLoot: rolls items over threshold. Items with quality < threshold, round robin
+                        recipientGroup->GroupLoot(loot, creature);
+                        break;
+                    case NEED_BEFORE_GREED:
+                        recipientGroup->NeedBeforeGreed(loot, creature);
+                        break;
+                    case MASTER_LOOT:
+                        recipientGroup->MasterLoot(loot, creature);
+                        break;
+                    default:
+                        break;
                     }
                 }
             }
@@ -9450,12 +9453,6 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
                 loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true);
                 permission = OWNER_PERMISSION;

-                //Inform instance if creature is skinned.
-                if (InstanceScript* mapInstance = creature->GetInstanceScript())
-                {
-                    mapInstance->CreatureLooted(creature, LOOT_SKINNING);
-                }
-
                 // Xinef: Set new loot recipient
                 creature->SetLootRecipient(this, false);
             }
@@ -9468,18 +9465,18 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
                     {
                         switch (recipientGroup->GetLootMethod())
                         {
-                            case MASTER_LOOT:
-                                permission = recipientGroup->GetMasterLooterGuid() == GetGUID() ? MASTER_PERMISSION : RESTRICTED_PERMISSION;
-                                break;
-                            case FREE_FOR_ALL:
-                                permission = ALL_PERMISSION;
-                                break;
-                            case ROUND_ROBIN:
-                                permission = ROUND_ROBIN_PERMISSION;
-                                break;
-                            default:
-                                permission = GROUP_PERMISSION;
-                                break;
+                        case MASTER_LOOT:
+                            permission = recipientGroup->GetMasterLooterGuid() == GetGUID() ? MASTER_PERMISSION : RESTRICTED_PERMISSION;
+                            break;
+                        case FREE_FOR_ALL:
+                            permission = ALL_PERMISSION;
+                            break;
+                        case ROUND_ROBIN:
+                            permission = ROUND_ROBIN_PERMISSION;
+                            break;
+                        default:
+                            permission = GROUP_PERMISSION;
+                            break;
                         }
                     }
                     else
@@ -9490,23 +9487,20 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
                 else
                     permission = NONE_PERMISSION;
             }

         }
     }

     // LOOT_INSIGNIA and LOOT_FISHINGHOLE unsupported by client
     switch (loot_type)
     {
-        case LOOT_INSIGNIA:
-            loot_type = LOOT_SKINNING;
-            break;
-        case LOOT_FISHINGHOLE:
-            loot_type = LOOT_FISHING;
-            break;
-        case LOOT_FISHING_JUNK:
-            loot_type = LOOT_FISHING;
-            break;
-        default:
-            break;
+    case LOOT_INSIGNIA:    loot_type = LOOT_SKINNING; break;
+    case LOOT_FISHINGHOLE: loot_type = LOOT_FISHING; break;
+    case LOOT_FISHING_JUNK: loot_type = LOOT_FISHING; break;
+    default: break;
     }

     // need know merged fishing/corpse loot type for achievements
@@ -9516,7 +9510,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
     {
         SetLootGUID(guid);

        WorldPacket data(SMSG_LOOT_RESPONSE, (9 + 50));         // we guess size
      
         data << uint64(guid);
         data << uint8(loot_type);
         data << LootView(*loot, this, permission);
@@ -9528,6 +9522,9 @@ void Player::SendLoot(uint64 guid, LootType loot_type)

         if (loot_type == LOOT_CORPSE && !IS_ITEM_GUID(guid))
             SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING);

     }
     else
         SendLootError(guid, LOOT_ERROR_DIDNT_KILL);
@@ -14082,6 +14079,440 @@ void Player::SwapItem(uint16 src, uint16 dst)
     AutoUnequipOffhandIfNeed();
}

+void Player::SwapItem(uint8 srcslot)
+{
+    uint8 srcbag = INVENTORY_SLOT_BAG_0;
+    uint8 dstbag = 0;
+    uint8 dstslot = 0;
+
+    bool empty = false;
+
+    //?±3°ü
+    for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
+        if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+        {
+            dstbag = INVENTORY_SLOT_BAG_0;
+            dstslot = i;
+            empty = true;
+        }
+
+    if (!empty)
+    {
+        //????±3°ü
+        for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
+            if (Bag* pBag = GetBagByPos(i))
+                for (uint32 j = 0; j < pBag->GetBagSize(); j++)
+                    if (!GetItemByPos(i, j))
+                    {
+                        dstbag = i;
+                        dstslot = j;
+                        empty = true;
+                    }
+    }
+
+    uint16 src = srcbag << 8 | srcslot;
+    uint16 dst = dstbag << 8 | dstslot;
+
+    /*
+    //?А
+    for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
+        if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+        {
+            dstbag = INVENTORY_SLOT_BAG_0;
+            dstslot = i;
+        }
+
+    //?А±3°ü
+    for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
+        if (Bag* pBag = GetBagByPos(i))
+            for (uint32 j = 0; j < pBag->GetBagSize(); j++)
+                if (!GetItemByPos(i, j))
+                {
+                    dstbag = i;
+                    dstslot = j;
+                }
+
+                */
+
+
+    Item* pSrcItem = GetItemByPos(srcbag, srcslot);
+    Item* pDstItem = GetItemByPos(dstbag, dstslot);
+
+    if (!pSrcItem)
+        return;
+
+    if (!empty)
+    {
+        SQLTransaction trans = CharacterDatabase.BeginTransaction();
+        MailSender sender(MAIL_CREATURE, 34337 /* The Postmaster */);
+        MailDraft draft("Ξ·¨??μ?°±?", "?μ?3°ü????-oá??Β2??°±??μ???μē??£????2???钢?£");
+        MoveItemFromInventory(pSrcItem->GetBagSlot(), pSrcItem->GetSlot(), true);
+        pSrcItem->DeleteFromInventoryDB(trans);
+        if (pSrcItem->GetState() == ITEM_UNCHANGED)
+            pSrcItem->FSetState(ITEM_CHANGED);
+        pSrcItem->SetOwnerGUID(GetGUID());
+        pSrcItem->SaveToDB(trans);
+        draft.AddItem(pSrcItem);
+        draft.SendMailTo(trans, MailReceiver(this, this->GetGUIDLow()), sender);
+        CharacterDatabase.CommitTransaction(trans);
+        return;
+    }
+
+    if (!IsAlive())
+    {
+        SendEquipError(EQUIP_ERR_YOU_ARE_DEAD, pSrcItem, pDstItem);
+        return;
+    }
+
+    // SRC checks
+
+    if (GetLootGUID() == pSrcItem->GetGUID())                           // prevent swap looting item
+    {
+        //best error message found for attempting to swap while looting
+        SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, pSrcItem, NULL);
+        return;
+    }
+
+    // check unequip potability for equipped items and bank bags
+    if (IsEquipmentPos(src) || IsBagPos(src))
+    {
+        // bags can be swapped with empty bag slots, or with empty bag (items move possibility checked later)
+        InventoryResult msg = CanUnequipItem(src, !IsBagPos(src) || IsBagPos(dst) || (pDstItem && pDstItem->ToBag() && pDstItem->ToBag()->IsEmpty()));
+        if (msg != EQUIP_ERR_OK)
+        {
+            SendEquipError(msg, pSrcItem, pDstItem);
+            return;
+        }
+    }
+
+    // anti-wpe
+    if (pSrcItem->IsBag() && pSrcItem->IsNotEmptyBag() && !IsBagPos(dst))
+    {
+        SendEquipError(EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS, pSrcItem, pDstItem);
+        return;
+    }
+
+    // prevent put equipped/bank bag in self
+    if (IsBagPos(src) && srcslot == dstbag)
+    {
+        SendEquipError(EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem);
+        return;
+    }
+
+    // prevent equipping bag in the same slot from its inside
+    if (IsBagPos(dst) && srcbag == dstslot)
+    {
+        SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pSrcItem, pDstItem);
+        return;
+    }
+
+    // DST checks
+
+    if (pDstItem)
+    {
+        // Xinef: Removed next bullshit loot generated check
+        if (pDstItem->GetGUID() == GetLootGUID())                       // prevent swap looting item
+        {
+            //best error message found for attempting to swap while looting
+            SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, pDstItem, NULL);
+            return;
+        }
+
+        // check unequip potability for equipped items and bank bags
+        if (IsEquipmentPos(dst) || IsBagPos(dst))
+        {
+            // bags can be swapped with empty bag slots, or with empty bag (items move possibility checked later)
+            InventoryResult msg = CanUnequipItem(dst, !IsBagPos(dst) || IsBagPos(src) || (pSrcItem->ToBag() && pSrcItem->ToBag()->IsEmpty()));
+            if (msg != EQUIP_ERR_OK)
+            {
+                SendEquipError(msg, pSrcItem, pDstItem);
+                return;
+            }
+        }
+    }
+
+    // NOW this is or item move (swap with empty), or swap with another item (including bags in bag possitions)
+    // or swap empty bag with another empty or not empty bag (with items exchange)
+
+    // Move case
+    if (!pDstItem)
+    {
+        if (IsInventoryPos(dst))
+        {
+            ItemPosCountVec dest;
+            InventoryResult msg = CanStoreItem(dstbag, dstslot, dest, pSrcItem, false);
+            if (msg != EQUIP_ERR_OK)
+            {
+                SendEquipError(msg, pSrcItem, NULL);
+                return;
+            }
+
+            RemoveItem(srcbag, srcslot, true);
+            StoreItem(dest, pSrcItem, true);
+            UpdateTitansGrip();
+            if (IsBankPos(src))
+                ItemAddedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount());
+        }
+        else if (IsBankPos(dst))
+        {
+            ItemPosCountVec dest;
+            InventoryResult msg = CanBankItem(dstbag, dstslot, dest, pSrcItem, false);
+            if (msg != EQUIP_ERR_OK)
+            {
+                SendEquipError(msg, pSrcItem, NULL);
+                return;
+            }
+
+            RemoveItem(srcbag, srcslot, true);
+            BankItem(dest, pSrcItem, true);
+            UpdateTitansGrip();
+            ItemRemovedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount());
+        }
+        else if (IsEquipmentPos(dst))
+        {
+            uint16 dest;
+            InventoryResult msg = CanEquipItem(dstslot, dest, pSrcItem, false);
+            if (msg != EQUIP_ERR_OK)
+            {
+                SendEquipError(msg, pSrcItem, NULL);
+                return;
+            }
+
+            RemoveItem(srcbag, srcslot, true);
+            EquipItem(dest, pSrcItem, true);
+            AutoUnequipOffhandIfNeed();
+        }
+
+        return;
+    }
+
+    // attempt merge to / fill target item
+    if (!pSrcItem->IsBag() && !pDstItem->IsBag())
+    {
+        InventoryResult msg;
+        ItemPosCountVec sDest;
+        uint16 eDest = 0;
+        if (IsInventoryPos(dst))
+            msg = CanStoreItem(dstbag, dstslot, sDest, pSrcItem, false);
+        else if (IsBankPos(dst))
+            msg = CanBankItem(dstbag, dstslot, sDest, pSrcItem, false);
+        else if (IsEquipmentPos(dst))
+            msg = CanEquipItem(dstslot, eDest, pSrcItem, false);
+        else
+            return;
+
+        // can be merge/fill
+        if (msg == EQUIP_ERR_OK)
+        {
+            if (pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetTemplate()->GetMaxStackSize())
+            {
+                RemoveItem(srcbag, srcslot, true);
+
+                if (IsInventoryPos(dst))
+                    StoreItem(sDest, pSrcItem, true);
+                else if (IsBankPos(dst))
+                    BankItem(sDest, pSrcItem, true);
+                else if (IsEquipmentPos(dst))
+                {
+                    EquipItem(eDest, pSrcItem, true);
+                    AutoUnequipOffhandIfNeed();
+                }
+            }
+            else
+            {
+                pSrcItem->SetCount(pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetTemplate()->GetMaxStackSize());
+                pDstItem->SetCount(pSrcItem->GetTemplate()->GetMaxStackSize());
+                pSrcItem->SetState(ITEM_CHANGED, this);
+                pDstItem->SetState(ITEM_CHANGED, this);
+                if (IsInWorld())
+                {
+                    pSrcItem->SendUpdateToPlayer(this);
+                    pDstItem->SendUpdateToPlayer(this);
+                }
+            }
+            SendRefundInfo(pDstItem);
+            return;
+        }
+    }
+
+    // impossible merge/fill, do real swap
+    InventoryResult msg = EQUIP_ERR_OK;
+
+    // check src->dest move possibility
+    ItemPosCountVec sDest;
+    uint16 eDest = 0;
+    if (IsInventoryPos(dst))
+        msg = CanStoreItem(dstbag, dstslot, sDest, pSrcItem, true);
+    else if (IsBankPos(dst))
+        msg = CanBankItem(dstbag, dstslot, sDest, pSrcItem, true);
+    else if (IsEquipmentPos(dst))
+    {
+        msg = CanEquipItem(dstslot, eDest, pSrcItem, true);
+        if (msg == EQUIP_ERR_OK)
+            msg = CanUnequipItem(eDest, true);
+    }
+
+    if (msg != EQUIP_ERR_OK)
+    {
+        SendEquipError(msg, pSrcItem, pDstItem);
+        return;
+    }
+
+    // check dest->src move possibility
+    ItemPosCountVec sDest2;
+    uint16 eDest2 = 0;
+    if (IsInventoryPos(src))
+        msg = CanStoreItem(srcbag, srcslot, sDest2, pDstItem, true);
+    else if (IsBankPos(src))
+        msg = CanBankItem(srcbag, srcslot, sDest2, pDstItem, true);
+    else if (IsEquipmentPos(src))
+    {
+        msg = CanEquipItem(srcslot, eDest2, pDstItem, true);
+        if (msg == EQUIP_ERR_OK)
+            msg = CanUnequipItem(eDest2, true);
+    }
+
+    if (msg != EQUIP_ERR_OK)
+    {
+        SendEquipError(msg, pDstItem, pSrcItem);
+        return;
+    }
+
+    // Check bag swap with item exchange (one from empty in not bag possition (equipped (not possible in fact) or store)
+    if (Bag* srcBag = pSrcItem->ToBag())
+    {
+        if (Bag* dstBag = pDstItem->ToBag())
+        {
+            Bag* emptyBag = NULL;
+            Bag* fullBag = NULL;
+            if (srcBag->IsEmpty() && !IsBagPos(src))
+            {
+                emptyBag = srcBag;
+                fullBag = dstBag;
+            }
+            else if (dstBag->IsEmpty() && !IsBagPos(dst))
+            {
+                emptyBag = dstBag;
+                fullBag = srcBag;
+            }
+
+            // bag swap (with items exchange) case
+            if (emptyBag && fullBag)
+            {
+                ItemTemplate const* emptyProto = emptyBag->GetTemplate();
+
+                uint32 count = 0;
+
+                for (uint32 i = 0; i < fullBag->GetBagSize(); ++i)
+                {
+                    Item* bagItem = fullBag->GetItemByPos(i);
+                    if (!bagItem)
+                        continue;
+
+                    ItemTemplate const* bagItemProto = bagItem->GetTemplate();
+                    if (!bagItemProto || !ItemCanGoIntoBag(bagItemProto, emptyProto))
+                    {
+                        // one from items not go to empty target bag
+                        SendEquipError(EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem);
+                        return;
+                    }
+
+                    ++count;
+                }
+
+                if (count > emptyBag->GetBagSize())
+                {
+                    // too small targeted bag
+                    SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pSrcItem, pDstItem);
+                    return;
+                }
+
+                // Items swap
+                count = 0;                                      // will pos in new bag
+                for (uint32 i = 0; i < fullBag->GetBagSize(); ++i)
+                {
+                    Item* bagItem = fullBag->GetItemByPos(i);
+                    if (!bagItem)
+                        continue;
+
+                    fullBag->RemoveItem(i, true);
+                    emptyBag->StoreItem(count, bagItem, true);
+                    bagItem->SetState(ITEM_CHANGED, this);
+
+                    ++count;
+                }
+            }
+        }
+    }
+
+    // now do moves, remove...
+    RemoveItem(dstbag, dstslot, false, true);
+    RemoveItem(srcbag, srcslot, false, true);
+
+    // add to dest
+    if (IsInventoryPos(dst))
+        StoreItem(sDest, pSrcItem, true);
+    else if (IsBankPos(dst))
+        BankItem(sDest, pSrcItem, true);
+    else if (IsEquipmentPos(dst))
+        EquipItem(eDest, pSrcItem, true);
+
+    // add to src
+    if (IsInventoryPos(src))
+        StoreItem(sDest2, pDstItem, true);
+    else if (IsBankPos(src))
+        BankItem(sDest2, pDstItem, true);
+    else if (IsEquipmentPos(src))
+        EquipItem(eDest2, pDstItem, true);
+
+    // Xinef: Call this here after all needed items are equipped
+    RemoveItemDependentAurasAndCasts((Item*)NULL);
+
+    // if player is moving bags and is looting an item inside this bag
+    // release the loot
+    if (GetLootGUID())
+    {
+        bool released = false;
+        if (IsBagPos(src))
+        {
+            Bag* bag = pSrcItem->ToBag();
+            for (uint32 i = 0; i < bag->GetBagSize(); ++i)
+            {
+                if (Item* bagItem = bag->GetItemByPos(i))
+                {
+                    // Xinef: Removed next bullshit loot generated check
+                    if (bagItem->GetGUID() == GetLootGUID())
+                    {
+                        m_session->DoLootRelease(GetLootGUID());
+                        released = true;                    // so we don't need to look at dstBag
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (!released && IsBagPos(dst) && pDstItem)
+        {
+            Bag* bag = pDstItem->ToBag();
+            for (uint32 i = 0; i < bag->GetBagSize(); ++i)
+            {
+                if (Item* bagItem = bag->GetItemByPos(i))
+                {
+                    // Xinef: Removed next bullshit loot generated check
+                    if (bagItem->GetGUID() == GetLootGUID())
+                    {
+                        m_session->DoLootRelease(GetLootGUID());
+                        released = true;                    // not realy needed here
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    AutoUnequipOffhandIfNeed();
+}
+
void Player::AddItemToBuyBackSlot(Item* pItem)
{
     if (pItem)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 11578e4..37c62b2 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1526,6 +1526,7 @@ public:
     void DestroyZoneLimitedItem(bool update, uint32 new_zone);
     void SplitItem(uint16 src, uint16 dst, uint32 count);
     void SwapItem(uint16 src, uint16 dst);
+    void SwapItem(uint8 srcslot);
     void AddItemToBuyBackSlot(Item* pItem);
     Item* GetItemFromBuyBackSlot(uint32 slot);
     void RemoveItemFromBuyBackSlot(uint32 slot, bool del);
@@ -2400,7 +2401,7 @@ public:
     PlayerMenu* PlayerTalkClass;
     std::vector<ItemSetEffect*> ItemSetEff;

-    void SendLoot(uint64 guid, LootType loot_type);
+    void SendLoot(uint64 guid, LootType loot_type, float range = INTERACTION_DISTANCE);
     void SendLootError(uint64 guid, LootError error);
     void SendLootRelease(uint64 guid);
     void SendNotifyLootItemRemoved(uint8 lootSlot);
diff --git a/src/server/game/Events/TF_coreload.cpp b/src/server/game/Events/TF_coreload.cpp
index 23f8858..f2233fd 100644
--- a/src/server/game/Events/TF_coreload.cpp
+++ b/src/server/game/Events/TF_coreload.cpp
@@ -145,6 +145,7 @@

#define sObjectMgr ObjectMgr::instance()
#pragma execution_character_set("utf-8")
+
///////////////////////////////////////////////自定义系统频道
//系统频道新函数1 仅聊天窗口
void ObjectMgr::SendSerMessage(const char *format, ...)
@@ -276,6 +277,8 @@ void Player::SendHkAsMessage(const char *Text, ...)
         GetSession()->SendAreaTriggerMessage(str);
     }
}
+//共享
+
//发送特效聊天 聊天窗口 和 屏幕上方弹起跳动
void Player::SendSpecialMsg(const char *Text, ...)
{

index 6d85e99..6d0b2ac 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -1095,6 +1095,7 @@ public:

+    void Announce(Player* announcer, uint32 entry, uint8 flag);
     TF_ConfigMap m_tf_ConfigMap;
     TF_StrMap m_tf_StringMap;
     const uint32 Get_TF_Config(uint32 entry);
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 04b909b..91de445 100644
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -1321,6 +1321,8 @@ namespace acore
         float m_fRange;
     };

+
+
     class AllCreaturesOfEntryInRange
     {
     public:
@@ -1339,6 +1341,23 @@ namespace acore
         float m_fRange;
     };

+    class AllCreaturesInRange
+    {
+    public:
+        AllCreaturesInRange(const WorldObject* object, float maxRange) : m_pObject(object), m_fRange(maxRange) {}
+        bool operator() (Unit* unit)
+        {
+            if (m_pObject->IsWithinDist(unit, m_fRange, false))
+                return true;
+
+            return false;
+        }
+
+    private:
+        const WorldObject* m_pObject;
+        float m_fRange;
+    };
+
     class PlayerAtMinimumRangeAway
     {
     public:
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index d95ff12..71e2ae5 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -1,9 +1,3 @@
-/*
- * Copyright (C) 2016+     AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: https://github.com/azerothcore/a ... master/LICENSE-GPL2
- * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
- * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
- */
-
#include "Common.h"
#include "Log.h"
#include "Corpse.h"
@@ -19,20 +13,13 @@
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
-#include "ObjectMgr.h"
-
-#ifdef ELUNA
-#include "LuaEngine.h"
-#endif

void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
{
-#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
-    sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_LOOT_ITEM");
-#endif

     Player* player = GetPlayer();
     uint64 lguid = player->GetLootGUID();
-    Loot* loot = nullptr;
+    Loot* loot = NULL;
     uint8 lootSlot = 0;

     recvData >> lootSlot;
@@ -42,7 +29,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
         GameObject* go = player->GetMap()->GetGameObject(lguid);
         // xinef: cheating protection
         //if (player->GetGroup() && player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGUID() != player->GetGroup()->GetMasterLooterGuid())
           go = nullptr;


         // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
         if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE)))
@@ -99,68 +86,281 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)

void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
{
-#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
-    sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT_MONEY");
-#endif

     Player* player = GetPlayer();
     uint64 guid = player->GetLootGUID();
     if (!guid)
         return;

-    Loot* loot = nullptr;
+    Loot* loot = NULL;
     bool shareMoney = true;

     switch (GUID_HIPART(guid))
     {
-        case HIGHGUID_GAMEOBJECT:
-            {
-                GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid);
+    case HIGHGUID_GAMEOBJECT:
+    {
+        GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid);

-                // do not check distance for GO if player is the owner of it (ex. fishing bobber)
-                if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player, INTERACTION_DISTANCE))))
-                    loot = &go->loot;
+        // do not check distance for GO if player is the owner of it (ex. fishing bobber)
+        if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player, INTERACTION_DISTANCE))))
+            loot = &go->loot;

-                break;
-            }
-        case HIGHGUID_CORPSE:                               // remove insignia ONLY in BG
-            {
-                Corpse* bones = ObjectAccessor::GetCorpse(*player, guid);
+        break;
+    }
+    case HIGHGUID_CORPSE:                               // remove insignia ONLY in BG
+    {
+        Corpse* bones = ObjectAccessor::GetCorpse(*player, guid);

-                if (bones && bones->IsWithinDistInMap(player, INTERACTION_DISTANCE))
-                {
-                    loot = &bones->loot;
-                    shareMoney = false;
-                }
+        if (bones && bones->IsWithinDistInMap(player, INTERACTION_DISTANCE))
+        {
+            loot = &bones->loot;
+            shareMoney = false;
+        }

-                break;
-            }
-        case HIGHGUID_ITEM:
+        break;
+    }
+    case HIGHGUID_ITEM:
+    {
+        if (Item* item = player->GetItemByGuid(guid))
+        {
+            loot = &item->loot;
+            shareMoney = false;
+        }
+        break;
+    }
+    case HIGHGUID_UNIT:
+    case HIGHGUID_VEHICLE:
+    {
+        Creature* creature = player->GetMap()->GetCreature(guid);
+        bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
+        if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE))
+        {
+            loot = &creature->loot;
+            if (creature->IsAlive())
+                shareMoney = false;
+        }
+        else
+            player->SendLootError(guid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL);
+        break;
+    }
+    default:
+        return;                                         // unlootable type
+    }
+
+    if (loot)
+    {
+        loot->NotifyMoneyRemoved();
+        if (shareMoney && player->GetGroup())      //item, pickpocket and players can be looted only single player
+        {
+            Group* group = player->GetGroup();
+
+            std::vector<Player*> playersNear;
+            for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
             {
-                if (Item* item = player->GetItemByGuid(guid))
-                {
-                    loot = &item->loot;
-                    shareMoney = false;
-                }
-                break;
+                Player* member = itr->GetSource();
+                if (!member)
+                    continue;
+
+                if (player->IsAtGroupRewardDistance(member))
+                    playersNear.push_back(member);
             }
-        case HIGHGUID_UNIT:
-        case HIGHGUID_VEHICLE:
+
+            uint32 goldPerPlayer = uint32((loot->gold) / (playersNear.size()));
+
+      
+
+            for (std::vector<Player*>::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i)
             {
-                Creature* creature = player->GetMap()->GetCreature(guid);
-                bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
-                if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE))
-                {
-                    loot = &creature->loot;
-                    if (creature->IsAlive())
-                        shareMoney = false;
-                }
-                else
-                    player->SendLootError(guid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL);
-                break;
+                (*i)->ModifyMoney(goldPerPlayer);
+                (*i)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, goldPerPlayer);
+
+                WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1);
+                data << uint32(goldPerPlayer);
+                data << uint8(playersNear.size() > 1 ? 0 : 1);     // Controls the text displayed in chat. 0 is "Your share is..." and 1 is "You loot..."
+                (*i)->GetSession()->SendPacket(&data);
             }
-        default:
-            return;                                         // unlootable type
+        }
+        else
+        {
+            //12????+            //sRecruit->RecruitMoneyReward(player, loot->gold);
+
+            player->ModifyMoney(loot->gold);
+            player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, loot->gold);
+
+            WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1);
+            data << uint32(loot->gold);
+            data << uint8(1);   // "You loot..."
+            SendPacket(&data);
+        }
+
+        loot->gold = 0;
+
+        // Delete the money loot record from the DB
+        if (loot->containerId > 0)
+            sLootItemStorage->RemoveStoredLootMoney(loot->containerId);
+
+        // Delete container if empty
+        if (loot->isLooted() && IS_ITEM_GUID(guid))
+            DoLootRelease(guid);
+    }
+}
+
+void WorldSession::HandleLootOpcode(WorldPacket& recvData)
+{
+    ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT");
+
+    uint64 guid;
+    recvData >> guid;
+
+    // Check possible cheat
+    if (!GetPlayer()->IsAlive() || !IS_CRE_OR_VEH_GUID(guid))
+        return;
+
+    GetPlayer()->SendLoot(guid, LOOT_CORPSE);
+
+    // interrupt cast
+    if (GetPlayer()->IsNonMeleeSpellCast(false))
+        GetPlayer()->InterruptNonMeleeSpells(false);
+

+
+void WorldSession::HandleAutostoreLootItemFarOpcode(WorldPacket& recvData, float range)
+{
+    ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_LOOT_ITEM");
+    Player* player = GetPlayer();
+    uint64 lguid = player->GetLootGUID();
+    Loot* loot = NULL;
+    uint8 lootSlot = 0;
+
+    recvData >> lootSlot;
+
+    if (IS_GAMEOBJECT_GUID(lguid))
+    {
+        GameObject* go = player->GetMap()->GetGameObject(lguid);
+        // xinef: cheating protection
+        //if (player->GetGroup() && player->GetGroup()->GetLootMethod() == MASTER_LOOT && player->GetGUID() != player->GetGroup()->GetMasterLooterGuid())
+        //    go = NULL;
+
+        // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
+        if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, range)))
+        {
+            player->SendLootRelease(lguid);
+            return;
+        }
+
+        loot = &go->loot;
+    }
+    else if (IS_ITEM_GUID(lguid))
+    {
+        Item* pItem = player->GetItemByGuid(lguid);
+
+        if (!pItem)
+        {
+            player->SendLootRelease(lguid);
+            return;
+        }
+
+        loot = &pItem->loot;
+    }
+    else if (IS_CORPSE_GUID(lguid))
+    {
+        Corpse* bones = ObjectAccessor::GetCorpse(*player, lguid);
+        if (!bones)
+        {
+            player->SendLootRelease(lguid);
+            return;
+        }
+
+        loot = &bones->loot;
+    }
+    else
+    {
+        Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);
+
+        bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
+        if (!lootAllowed || !creature->IsWithinDistInMap(_player, range))
+        {
+            player->SendLootError(lguid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL);
+            return;
+        }
+
+        loot = &creature->loot;
+    }
+
+    player->StoreLootItem(lootSlot, loot);
+
+    // If player is removing the last LootItem, delete the empty container.
+    if (loot->isLooted() && IS_ITEM_GUID(lguid))
+        DoLootRelease(lguid, range);
+}
+
+void WorldSession::HandleLootMoneyFarOpcode(WorldPacket& /*recvData*/, float range)
+{
+    ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT_MONEY");
+
+    Player* player = GetPlayer();
+    uint64 guid = player->GetLootGUID();
+    if (!guid)
+        return;
+
+    Loot* loot = NULL;
+    bool shareMoney = true;
+
+    switch (GUID_HIPART(guid))
+    {
+    case HIGHGUID_GAMEOBJECT:
+    {
+        GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid);
+
+        // do not check distance for GO if player is the owner of it (ex. fishing bobber)
+        if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player, range))))
+            loot = &go->loot;
+
+        break;
+    }
+    case HIGHGUID_CORPSE:                               // remove insignia ONLY in BG
+    {
+        Corpse* bones = ObjectAccessor::GetCorpse(*player, guid);
+
+        if (bones && bones->IsWithinDistInMap(player, range))
+        {
+            loot = &bones->loot;
+            shareMoney = false;
+        }
+
+        break;
+    }
+    case HIGHGUID_ITEM:
+    {
+        if (Item* item = player->GetItemByGuid(guid))
+        {
+            loot = &item->loot;
+            shareMoney = false;
+        }
+        break;
+    }
+    case HIGHGUID_UNIT:
+    case HIGHGUID_VEHICLE:
+    {
+        Creature* creature = player->GetMap()->GetCreature(guid);
+        bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
+        if (lootAllowed && creature->IsWithinDistInMap(player, range))
+        {
+            loot = &creature->loot;
+            if (creature->IsAlive())
+                shareMoney = false;
+        }
+        else
+            player->SendLootError(guid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL);
+        break;
+    }
+    default:
+        return;                                         // unlootable type
     }

     if (loot)
@@ -171,7 +371,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
             Group* group = player->GetGroup();

             std::vector<Player*> playersNear;
-            for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
+            for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
             {
                 Player* member = itr->GetSource();
                 if (!member)


@@ -204,26 +410,22 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
             data << uint8(1);   // "You loot..."
             SendPacket(&data);
         }
-#ifdef ELUNA
-        sEluna->OnLootMoney(player, loot->gold);
-#endif
+
         loot->gold = 0;

         // Delete the money loot record from the DB
         if (loot->containerId > 0)
-            sLootItemStorage->RemoveStoredLootMoney(loot->containerId, loot);
+            sLootItemStorage->RemoveStoredLootMoney(loot->containerId);

         // Delete container if empty
         if (loot->isLooted() && IS_ITEM_GUID(guid))
-            DoLootRelease(guid);
+            DoLootRelease(guid, range);
     }
}

-void WorldSession::HandleLootOpcode(WorldPacket& recvData)
+void WorldSession::HandleLootFarOpcode(WorldPacket& recvData, float range)
{
-#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
-    sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT");
-#endif
+    ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT");

     uint64 guid;
     recvData >> guid;
@@ -232,7 +434,7 @@ void WorldSession::HandleLootOpcode(WorldPacket& recvData)
     if (!GetPlayer()->IsAlive() || !IS_CRE_OR_VEH_GUID(guid))
         return;

-    GetPlayer()->SendLoot(guid, LOOT_CORPSE);
+    GetPlayer()->SendLoot(guid, LOOT_CORPSE, range);

     // interrupt cast
     if (GetPlayer()->IsNonMeleeSpellCast(false))
@@ -241,9 +443,7 @@ void WorldSession::HandleLootOpcode(WorldPacket& recvData)

void WorldSession::HandleLootReleaseOpcode(WorldPacket& recvData)
{
-#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
-    sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT_RELEASE");
-#endif


     // cheaters can modify lguid to prevent correct apply loot release code and re-loot
     // use internal stored guid
@@ -255,10 +455,10 @@ void WorldSession::HandleLootReleaseOpcode(WorldPacket& recvData)
             DoLootRelease(lguid);
}

-void WorldSession::DoLootRelease(uint64 lguid)
+void WorldSession::DoLootRelease(uint64 lguid, float range)
{
-    Player*  player = GetPlayer();
-    Loot*    loot;
+    Player* player = GetPlayer();
+    Loot* loot;

     player->SetLootGUID(0);
     player->SendLootRelease(lguid);
@@ -273,7 +473,7 @@ void WorldSession::DoLootRelease(uint64 lguid)
         GameObject* go = GetPlayer()->GetMap()->GetGameObject(lguid);

         // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
-        if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE)))
+        if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, range)))
             return;

         loot = &go->loot;



     else if (IS_CORPSE_GUID(lguid))        // ONLY remove insignia at BG
     {
         Corpse* corpse = ObjectAccessor::GetCorpse(*player, lguid);
-        if (!corpse || !corpse->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
+        if (!corpse || !corpse->IsWithinDistInMap(_player, range))
             return;

         loot = &corpse->loot;
@@ -371,7 +568,7 @@ void WorldSession::DoLootRelease(uint64 lguid)
         Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid);

         bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING);
-        if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
+        if (!lootAllowed || !creature->IsWithinDistInMap(_player, range))
             return;

         loot = &creature->loot;
@@ -393,7 +590,7 @@ void WorldSession::DoLootRelease(uint64 lguid)

                 if (Group* group = player->GetGroup())
                 {
-                    group->SendLooter(creature, nullptr);
+                    group->SendLooter(creature, NULL);

                     // force update of dynamic flags, otherwise other group's players still not able to loot.
                     creature->ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS);
@@ -426,9 +623,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData)
         return;
     }

-#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
-    sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName().c_str());
-#endif
+    ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName().c_str());

     if (_player->GetLootGUID() != lootguid)
     {
@@ -443,7 +638,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData)
         return;
     }

-    Loot* loot = nullptr;
+    Loot* loot = NULL;

     if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID()))
     {
@@ -467,9 +662,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData)

     if (slotid >= loot->items.size() + loot->quest_items.size())
     {
-#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
-        sLog->outDebug(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName().c_str(), slotid, (unsigned long)loot->items.size());
-#endif
+        ;//sLog->outDebug(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName().c_str(), slotid, (unsigned long)loot->items.size());
         return;
     }

@@ -488,7 +681,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData)
         else
             _player->SendLootError(lootguid, LOOT_ERROR_MASTER_OTHER);

-        target->SendEquipError(msg, nullptr, nullptr, item.itemid);
+        target->SendEquipError(msg, NULL, NULL, item.itemid);
         return;
     }

@@ -500,10 +693,6 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData)
     target->SendNewItem(newitem, uint32(item.count), false, false, true);
     target->UpdateLootAchievements(&item, loot);

-#ifdef ELUNA
-    sEluna->OnLootItem(target, newitem, item.count, lootguid);
-#endif
-
     // mark as looted
     item.count = 0;
     item.is_looted = true;
diff --git a/src/server/game/Loot/LootItemStorage.cpp b/src/server/game/Loot/LootItemStorage.cpp
index 3e4f67d..e41ff67 100644
--- a/src/server/game/Loot/LootItemStorage.cpp
+++ b/src/server/game/Loot/LootItemStorage.cpp
@@ -178,7 +178,7 @@ void LootItemStorage::RemoveStoredLootItem(uint32 containerId, uint32 itemid, ui
         lootItemStore.erase(itr);
}

-void LootItemStorage::RemoveStoredLootMoney(uint32 containerId, Loot* loot)
+void LootItemStorage::RemoveStoredLootMoney(uint32 containerId)
{
     LootItemContainer::iterator itr = lootItemStore.find(containerId);
     if (itr == lootItemStore.end())
@@ -195,7 +195,7 @@ void LootItemStorage::RemoveStoredLootMoney(uint32 containerId, Loot* loot)

     // loot with empty itemList but unlootedCount > 0
     // must be deleted manually by the player or traded
-    if (!loot->unlootedCount)
+    if (itemList.empty())
         lootItemStore.erase(itr);
}

diff --git a/src/server/game/Loot/LootItemStorage.h b/src/server/game/Loot/LootItemStorage.h
index d708a1b..f724c44 100644
--- a/src/server/game/Loot/LootItemStorage.h
+++ b/src/server/game/Loot/LootItemStorage.h
@@ -42,7 +42,7 @@ public:
     bool LoadStoredLoot(Item* item);

     void RemoveStoredLootItem(uint32 containerId, uint32 itemid, uint32 count, Loot* loot);
-    void RemoveStoredLootMoney(uint32 containerId, Loot* loot);
+    void RemoveStoredLootMoney(uint32 containerId);
     void RemoveStoredLoot(uint32 containerId);

private:
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index 24bffb3..b4dace8 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -297,6 +297,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv);

struct Loot
{
+    unordered_map<uint32, uint32> LootExtraItems;
     friend ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv);

     QuestItemMap const& GetPlayerQuestItems() const { return PlayerQuestItems; }
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 7f1f4fc..46d50ef 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -354,7 +354,7 @@ public:

     void BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data);

-    void DoLootRelease(uint64 lguid);
+    void DoLootRelease(uint64 lguid,float range = INTERACTION_DISTANCE);

     // Account mute time
     time_t m_muteTime;
@@ -452,6 +452,11 @@ public:                                                 // opcodes handlers
     void HandleLootMoneyOpcode(WorldPacket& recvPacket);
     void HandleLootOpcode(WorldPacket& recvPacket);
     void HandleLootReleaseOpcode(WorldPacket& recvPacket);
+
+    void HandleAutostoreLootItemFarOpcode(WorldPacket& recvPacket, float range);
+    void HandleLootMoneyFarOpcode(WorldPacket& recvPacket, float range);
+    void HandleLootFarOpcode(WorldPacket& recvPacket, float range);
+
     void HandleLootMasterGiveOpcode(WorldPacket& recvPacket);
     void HandleWhoOpcode(WorldPacket& recvPacket);
     void HandleLogoutRequestOpcode(WorldPacket& recvPacket);
--
2.16.2.windows.1

回复

使用道具 举报

1309

时沙

0

精华

13

主题

声望: 3256   虚弱: 0

Lv.5(无冕者)

不正常人类游戏中心

灵蛇献瑞(尚美制作)祥龙贺岁(尚美制作)金兔迎春(尚美制作)炉石时沙之瓶信仰战假死猎人今天也只能打恢复的增强萨吟游牧师潜行者金鼠(ytfirefox制作) 福虎贺岁(尚美制作)

发表于 2021-7-5 22:08:34 | 显示全部楼层
wbsnake 发表于 2021-7-5 22:05
---
modules/WackyCore/WackyCoreScripts.cpp           |  63 +++
src/server/game/Entities/GameObje ...

大佬这是改源码?
回复

使用道具 举报

发表于 2021-7-5 22:10:34 | 显示全部楼层
yashino100 发表于 2021-7-5 22:08
大佬这是改源码?

花了50DKP ,楼主发出来的东西不全,无法使用。
就把他的贴上了,你们研究吧。
[发帖际遇]: wbsnake组队时加错团队,为别人团队拿了全服首杀,失去6 声望. 幸运榜 / 衰神榜
回复

使用道具 举报

48

时沙

0

精华

0

主题

声望: 64   虚弱: 0

Lv.2(潜行者)

假死猎人

发表于 2021-8-7 11:13:09 | 显示全部楼层
想要  但也只能看看!!
回复

使用道具 举报

18

时沙

0

精华

0

主题

声望: 162   虚弱: 0

Lv.2(潜行者)

发表于 2021-12-2 18:24:49 | 显示全部楼层
好贵啊...
回复

使用道具 举报

18

时沙

0

精华

0

主题

声望: 162   虚弱: 0

Lv.2(潜行者)

发表于 2021-12-2 18:27:39 | 显示全部楼层
285334976 发表于 2021-2-7 13:15
有BUG的,开服别用。

发现了。。。。
回复

使用道具 举报

117

时沙

0

精华

1

主题

声望: 133   虚弱: 0

Lv.2(潜行者)

发表于 2021-12-10 18:34:24 发表自手机触屏版 | 显示全部楼层
wcf19920531 发表于 2021-12-2 18:27
发现了。。。。

啥bug..大佬
回复

使用道具 举报

1262

时沙

0

精华

2

主题

声望: 434   虚弱: 0

Lv.4(锻造者)

炉石今天也只能打恢复的增强萨

发表于 2022-1-4 14:35:30 | 显示全部楼层
这个也不舍得。。
回复

使用道具 举报

206

时沙

0

精华

2

主题

声望: 165   虚弱: 0

Lv.3(忠诚者)

发表于 2022-1-13 17:51:21 | 显示全部楼层
楼主 萌新问一下这个1.12的能用吗
回复

使用道具 举报

567

时沙

0

精华

3

主题

声望: 1174   虚弱: 2

Lv.4(锻造者)

假死猎人今天也只能打恢复的增强萨

发表于 2022-1-14 21:33:18 | 显示全部楼层
看看学习下
回复

使用道具 举报

快速回复 返回顶部 返回列表