- UID
- 28218
- 阅读权限
- 50
- 回帖
- 666
- 喵币
- 0
- 有爱
- 250
- DKP
- 6545
- 金币
- 128663
- 在线时间
- 2255 小时
- 注册时间
- 2021-3-18
- 最后登录
- 2026-2-17
声望: 3223   虚弱: 0

Lv.5(无冕者)
     
|
发表于 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
|
|