#include "StdAfx.h" #include "TradeManager.h" #include "World.h" TradeManager* TradeManager::RegisterTrade(std::shared_ptr initiator, std::shared_ptr partner) { return new TradeManager(initiator, partner); } TradeManager::TradeManager(std::shared_ptr initiator, std::shared_ptr partner) { _initiator = initiator; _partner = partner; BinaryWriter openTrade; openTrade.Write(0x1FD); openTrade.Write(initiator->GetID()); openTrade.Write(partner->GetID()); openTrade.Write(0); // "some kind of stamp"? initiator->SendNetMessage(&openTrade, PRIVATE_MSG, TRUE, FALSE); BinaryWriter openTradePartner; openTradePartner.Write(0x1FD); openTradePartner.Write(partner->GetID()); openTradePartner.Write(initiator->GetID()); openTradePartner.Write(0); // "some kind of stamp"? partner->SendNetMessage(&openTradePartner, PRIVATE_MSG, TRUE, FALSE); // it's possible for users to have items in the trade window before starting so clear it ResetTrade(initiator); } void TradeManager::CloseTrade(std::weak_ptr playerFrom, DWORD reason) { OnCloseTrade(_initiator, reason); OnCloseTrade(_partner, reason); Delete(); } void TradeManager::OnCloseTrade(std::weak_ptr player, DWORD reason) { std::shared_ptr pPlayer = player.lock(); if (pPlayer) { BinaryWriter closeTrade; closeTrade.Write(0x1FF); closeTrade.Write(reason); pPlayer->SendNetMessage(&closeTrade, PRIVATE_MSG, TRUE, FALSE); } } void TradeManager::AddToTrade(std::shared_ptr playerFrom, DWORD item) { if (!CheckTrade()) return; std::shared_ptr pItem = g_pWorld->FindWithinPVS(playerFrom, item); if (!pItem || pItem->GetWorldTopLevelOwner() != playerFrom || pItem->IsAttunedOrContainsAttuned() || pItem->IsWielded()) { playerFrom->SendText("You cannot trade that item!", LTT_ERROR); BinaryWriter cannotTrade; cannotTrade.Write(0x207); cannotTrade.Write(item); cannotTrade.Write(0); playerFrom->SendNetMessage(&cannotTrade, PRIVATE_MSG, TRUE, FALSE); return; } std::list *itemList; if (playerFrom == _initiator.lock()) { itemList = &m_lInitiatorItems; } else { itemList = &m_lPartnerItems; } itemList->push_back(item); m_bInitiatorAccepted = false; m_bPartnerAccepted = false; std::shared_ptr pOther = GetOtherPlayer(playerFrom); pOther->MakeAware(pItem, true); BinaryWriter addToTrade; addToTrade.Write(0x200); addToTrade.Write(item); addToTrade.Write(0x1); addToTrade.Write(0); playerFrom->SendNetMessage(&addToTrade, PRIVATE_MSG, TRUE, FALSE); BinaryWriter addToTradeOther; addToTradeOther.Write(0x200); addToTradeOther.Write(item); addToTradeOther.Write(0x2); addToTradeOther.Write(0); pOther->SendNetMessage(&addToTradeOther, PRIVATE_MSG, TRUE, FALSE); } void TradeManager::AcceptTrade(std::shared_ptr playerFrom) { if (!CheckTrade()) return; if (playerFrom == _initiator.lock()) m_bInitiatorAccepted = true; else m_bPartnerAccepted = true; if (m_bInitiatorAccepted && m_bPartnerAccepted) { OnTradeAccepted(); } else { BinaryWriter acceptTrade; acceptTrade.Write(0x202); acceptTrade.Write(playerFrom->GetID()); //playerFrom->SendNetMessage(&acceptTrade, PRIVATE_MSG, TRUE, FALSE); GetOtherPlayer(playerFrom)->SendNetMessage(&acceptTrade, PRIVATE_MSG, TRUE, FALSE); } } bool TradeManager::OnTradeAccepted() { std::shared_ptr pInitiator = _initiator.lock(); if (!pInitiator) { return false; } std::shared_ptr pPartner = _partner.lock(); if (!pPartner) { return false; } bool bError = false; if (m_lPartnerItems.size() > pInitiator->Container_GetNumFreeMainPackSlots()) { pInitiator->SendText("You do not have enough pack space to complete this trade!", LTT_ERROR); pPartner->SendText((pInitiator->GetName() = " does not have enough pack space to complete this trade!").c_str(), LTT_ERROR); bError = true; } if (m_lInitiatorItems.size() > pPartner->Container_GetNumFreeMainPackSlots()) { pPartner->SendText("You do not have enough pack space to complete this trade!", LTT_ERROR); pInitiator->SendText((pPartner->GetName() = " does not have enough pack space to complete this trade!").c_str(), LTT_ERROR); bError = true; } // TODO check if this takes player over 300% burden std::list> lpInitiatorItems; for (auto it = m_lInitiatorItems.begin(); it != m_lInitiatorItems.end(); ++it) { std::shared_ptr pItem = g_pWorld->FindWithinPVS(pInitiator, *it); lpInitiatorItems.push_back(pItem); if (!pItem) { pInitiator->SendText("Invalid item in trade!", LTT_ERROR); pPartner->SendText("Invalid item in trade!", LTT_ERROR); bError = true; break; } else if (pItem->GetWorldTopLevelOwner() != pInitiator || pItem->IsWielded() || pItem->IsAttunedOrContainsAttuned()) { pInitiator->SendText(("You cannot trade " + pItem->GetName() + "!").c_str(), LTT_ERROR); pPartner->SendText((pInitiator->GetName() + " put invalid items in the trade!").c_str(), LTT_ERROR); bError = true; break; } } std::list> lpPartnerItems; for (auto it = m_lPartnerItems.begin(); it != m_lPartnerItems.end(); ++it) { std::shared_ptr pItem = g_pWorld->FindWithinPVS(pPartner, *it); lpPartnerItems.push_back(pItem); if (!pItem) { pInitiator->SendText("Invalid item in trade!", LTT_ERROR); pPartner->SendText("Invalid item in trade!", LTT_ERROR); bError = true; break; } else if (pItem->GetWorldTopLevelOwner() != pPartner || pItem->IsWielded() || pItem->IsAttunedOrContainsAttuned()) { pPartner->SendText(("You cannot trade " + pItem->GetName() + "!").c_str(), LTT_ERROR); pInitiator->SendText((pPartner->GetName() + " put invalid items in the trade!").c_str(), LTT_ERROR); bError = true; break; } } if (!bError) { // Swap items for (auto it = lpInitiatorItems.begin(); it != lpInitiatorItems.end(); ++it) { pPartner->OnReceiveInventoryItem(pInitiator, *it, 0); BinaryWriter removeItem; removeItem.Write(0x24); removeItem.Write((*it)->GetID()); pInitiator->SendNetMessage(&removeItem, PRIVATE_MSG, TRUE, FALSE); } for (auto it = lpPartnerItems.begin(); it != lpPartnerItems.end(); ++it) { pInitiator->OnReceiveInventoryItem(pPartner, *it, 0); BinaryWriter removeItem; removeItem.Write(0x24); removeItem.Write((*it)->GetID()); pPartner->SendNetMessage(&removeItem, PRIVATE_MSG, TRUE, FALSE); } // Trade Complete! pInitiator->NotifyWeenieError(0x529); pPartner->NotifyWeenieError(0x529); // reset the trade to continue trading ResetTrade(pInitiator); return true; } // Unfortunately, you cannot un-accept a completed trade as the accepting client bugs out CloseTrade(pInitiator, 0); return false; } void TradeManager::DeclineTrade(std::shared_ptr playerFrom) { if (!CheckTrade()) return; if (playerFrom == _initiator.lock()) m_bInitiatorAccepted = false; else m_bPartnerAccepted = false; BinaryWriter declineTrade; declineTrade.Write(0x203); declineTrade.Write(playerFrom->GetID()); //playerFrom->SendNetMessage(&declineTrade, PRIVATE_MSG, TRUE, FALSE); GetOtherPlayer(playerFrom)->SendNetMessage(&declineTrade, PRIVATE_MSG, TRUE, FALSE); } void TradeManager::ResetTrade(std::shared_ptr playerFrom) { if (!CheckTrade()) return; // remove all items m_lInitiatorItems.clear(); m_lPartnerItems.clear(); std::shared_ptr other = GetOtherPlayer(playerFrom); BinaryWriter resetTrade; resetTrade.Write(0x205); resetTrade.Write(playerFrom->GetID()); playerFrom->SendNetMessage(&resetTrade, PRIVATE_MSG, TRUE, FALSE); GetOtherPlayer(playerFrom)->SendNetMessage(&resetTrade, PRIVATE_MSG, TRUE, FALSE); } std::shared_ptr TradeManager::GetOtherPlayer(std::shared_ptr player) { std::shared_ptr pInitiator = _initiator.lock(); std::shared_ptr pPartner = _partner.lock(); if (player == pInitiator) return pPartner; return pInitiator; }; // Checks whether trade is still legit. True is so. bool TradeManager::CheckTrade() { std::shared_ptr pInitiator = _initiator.lock(); std::shared_ptr pPartner = _partner.lock(); // not currently trading if (!pInitiator || !pPartner) { OnCloseTrade(_initiator); OnCloseTrade(_partner); Delete(); return false; } return true; } // Removes references and then removes this from memory void TradeManager::Delete() { std::shared_ptr pInitiator = _initiator.lock(); std::shared_ptr pPartner = _partner.lock(); // Delete all references to this if (pInitiator) { pInitiator->SetTradeManager(NULL); } if (pPartner) { pPartner->SetTradeManager(NULL); } // MUST be the final thing done in this class delete this; } void TradeManager::CheckDistance() { if (!CheckTrade()) return; std::shared_ptr pInitiator = _initiator.lock(); std::shared_ptr pPartner = _partner.lock(); if (pInitiator->DistanceTo(pPartner, true) >= 1 ) { pInitiator->SendText((pPartner->GetName() + " is too far away to trade!").c_str(), LTT_ERROR); pPartner->SendText((pInitiator->GetName() + " is too far away to trade!").c_str(), LTT_ERROR); CloseTrade(_initiator, 1); } }