bool CClient::Cmd_SecureTrade( CChar *pChar, CItem *pItem ) { ADDTOCALLSTACK("CClient::Cmd_SecureTrade"); // Begin secure trading with a char. (Make the initial offer) if ( !pChar || pChar == m_pChar ) return false; // Make sure both clients can see each other, because trade window is an container // and containers can be opened only after the object is already loaded on screen if ( !m_pChar->CanSee(pChar) || !pChar->CanSee(m_pChar) ) return false; if ( pItem && (IsTrigUsed(TRIGGER_DROPON_CHAR) || IsTrigUsed(TRIGGER_ITEMDROPON_CHAR)) ) { CScriptTriggerArgs Args(pChar); if ( pItem->OnTrigger(ITRIG_DROPON_CHAR, m_pChar, &Args) == TRIGRET_RET_TRUE ) return false; } if ( pChar->m_pNPC ) // NPC's can't use trade windows return pItem ? pChar->NPC_OnItemGive(m_pChar, pItem) : false; if ( !pChar->m_pClient ) // and also offline players return false; if ( pChar->GetDefNum("REFUSETRADES") ) { SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_MSG_TRADE_REFUSE), pChar->GetName()); return false; } // Check if the trade window is already open for ( CItem *pItemCont = m_pChar->GetContentHead(); pItemCont != NULL; pItemCont = pItemCont->GetNext() ) { if ( !pItemCont->IsType(IT_EQ_TRADE_WINDOW) ) continue; CItem *pItemPartner = pItemCont->m_uidLink.ItemFind(); if ( !pItemPartner ) continue; CChar *pCharPartner = dynamic_cast<CChar *>(pItemPartner->GetParent()); if ( pCharPartner != pChar ) continue; if ( pItem ) { if ( IsTrigUsed(TRIGGER_DROPON_TRADE) ) { CScriptTriggerArgs Args1(pChar); if ( pItem->OnTrigger(ITRIG_DROPON_TRADE, this, &Args1) == TRIGRET_RET_TRUE ) return false; } CItemContainer *pCont = dynamic_cast<CItemContainer *>(pItemCont); if ( pCont ) pCont->ContentAdd(pItem); } return true; } // Open new trade window if ( IsTrigUsed(TRIGGER_TRADECREATE) ) { CScriptTriggerArgs Args(pItem); if ( (m_pChar->OnTrigger(CTRIG_TradeCreate, pChar, &Args) == TRIGRET_RET_TRUE) || (pChar->OnTrigger(CTRIG_TradeCreate, m_pChar, &Args) == TRIGRET_RET_TRUE) ) return false; } if ( IsTrigUsed(TRIGGER_DROPON_TRADE) && pItem ) { CScriptTriggerArgs Args1(pChar); if ( pItem->OnTrigger(ITRIG_DROPON_TRADE, this, &Args1) == TRIGRET_RET_TRUE ) return false; } CItem *pItem1 = CItem::CreateBase(ITEMID_Bulletin1); if ( !pItem1 ) return false; CItemContainer *pCont1 = static_cast<CItemContainer *>(pItem1); if ( !pCont1 ) { DEBUG_ERR(("Item 0%x must be a container type to enable player trading.\n", ITEMID_Bulletin1)); pItem1->Delete(); return false; } CItemContainer *pCont2 = static_cast<CItemContainer *>(CItem::CreateBase(ITEMID_Bulletin1)); ASSERT(pCont2); pCont1->SetName("Trade Window"); pCont1->SetType(IT_EQ_TRADE_WINDOW); pCont1->m_itEqTradeWindow.m_iWaitTime = 0; pCont1->m_itEqTradeWindow.m_bCheck = 0; pCont1->m_uidLink = pCont2->GetUID(); m_pChar->LayerAdd(pCont1, LAYER_SPECIAL); pCont2->SetName("Trade Window"); pCont2->SetType(IT_EQ_TRADE_WINDOW); pCont2->m_itEqTradeWindow.m_iWaitTime = 0; pCont2->m_itEqTradeWindow.m_bCheck = 0; pCont2->m_uidLink = pCont1->GetUID(); pChar->LayerAdd(pCont2, LAYER_SPECIAL); PacketTradeAction cmd(SECURE_TRADE_OPEN); cmd.prepareContainerOpen(pChar, pCont1, pCont2); cmd.send(this); cmd.prepareContainerOpen(m_pChar, pCont2, pCont1); cmd.send(pChar->m_pClient); if ( g_Cfg.m_iFeatureTOL & FEATURE_TOL_VIRTUALGOLD ) { PacketTradeAction cmd2(SECURE_TRADE_UPDATELEDGER); if ( m_NetState->isClientVersion(MINCLIVER_TOL) ) { cmd2.prepareUpdateLedger(pCont1, static_cast<DWORD>(m_pChar->m_virtualGold % 1000000000), static_cast<DWORD>(m_pChar->m_virtualGold / 1000000000)); cmd2.send(this); } if ( pChar->m_pClient->m_NetState->isClientVersion(MINCLIVER_TOL) ) { cmd2.prepareUpdateLedger(pCont2, static_cast<DWORD>(pChar->m_virtualGold % 1000000000), static_cast<DWORD>(pChar->m_virtualGold / 1000000000)); cmd2.send(pChar->m_pClient); } } LogOpenedContainer(pCont2); pChar->m_pClient->LogOpenedContainer(pCont1); if ( pItem ) { if ( IsTrigUsed(TRIGGER_DROPON_TRADE) ) { CScriptTriggerArgs Args1(pChar); if ( pItem->OnTrigger(ITRIG_DROPON_TRADE, this, &Args1) == TRIGRET_RET_TRUE ) { pCont1->Delete(); pCont2->Delete(); return false; } } pCont1->ContentAdd(pItem, pCont1->GetTopPoint()); } return true; }
void CItemContainer::Trade_Status( bool bCheck ) { ADDTOCALLSTACK("CItemContainer::Trade_Status"); // Update trade status check boxes to both sides. CItemContainer *pPartner = dynamic_cast<CItemContainer*>(m_uidLink.ItemFind()); if ( !pPartner ) return; CChar *pChar1 = dynamic_cast<CChar*>(GetParent()); if ( !pChar1 ) return; CChar *pChar2 = dynamic_cast<CChar*>(pPartner->GetParent()); if ( !pChar2 ) return; m_itEqTradeWindow.m_bCheck = bCheck ? 1 : 0; if ( !bCheck ) pPartner->m_itEqTradeWindow.m_bCheck = 0; PacketTradeAction cmd(SECURE_TRADE_CHANGE); if ( pChar1->IsClient() ) { cmd.prepareReadyChange(this, pPartner); cmd.send(pChar1->GetClient()); } if ( pChar2->IsClient() ) { cmd.prepareReadyChange(pPartner, this); cmd.send(pChar2->GetClient()); } // Check if both clients had pressed the 'accept' buttom if ( pPartner->m_itEqTradeWindow.m_bCheck == 0 || m_itEqTradeWindow.m_bCheck == 0 ) return; CItem *pItem, *pItemNext; int iCont1, iCont2; unsigned short i; CScriptTriggerArgs Args1(pChar1); pItem = pPartner->GetContentHead(); for ( i = 1; pItem != NULL; pItem = pItemNext, ++i ) { pItemNext = pItem->GetNext(); Args1.m_VarObjs.Insert(i, pItem, true); } Args1.m_iN1 = iCont1 = --i; pItemNext = NULL; CScriptTriggerArgs Args2(pChar2); pItem = GetContentHead(); for ( i = 1; pItem != NULL; pItem = pItemNext, ++i ) { pItemNext = pItem->GetNext(); Args2.m_VarObjs.Insert(i, pItem, true); } Args2.m_iN1 = iCont2 = --i; pItemNext = NULL; if ( (IsTrigUsed(TRIGGER_TRADEACCEPTED)) || (IsTrigUsed(TRIGGER_CHARTRADEACCEPTED)) ) { Args1.m_iN2 = iCont2; Args2.m_iN2 = iCont1; if ( (pChar1->OnTrigger(CTRIG_TradeAccepted, pChar2, &Args1) == TRIGRET_RET_TRUE) || (pChar2->OnTrigger(CTRIG_TradeAccepted, pChar1, &Args2) == TRIGRET_RET_TRUE) ) Delete(); } // Transfer items pItem = GetContentHead(); for ( ; pItem != NULL; pItem = pItemNext ) { pItemNext = pItem->GetNext(); pChar2->ItemBounce(pItem); } pItemNext = NULL; pItem = pPartner->GetContentHead(); for ( ; pItem != NULL; pItem = pItemNext ) { pItemNext = pItem->GetNext(); pChar1->ItemBounce(pItem); } // Transfer gold/platinum if ( g_Cfg.m_iFeatureTOL & FEATURE_TOL_VIRTUALGOLD ) { INT64 iGold1 = m_itEqTradeWindow.m_iGold + (m_itEqTradeWindow.m_iPlatinum * 1000000000); INT64 iGold2 = pPartner->m_itEqTradeWindow.m_iGold + (pPartner->m_itEqTradeWindow.m_iPlatinum * 1000000000); pChar1->m_virtualGold += iGold2 - iGold1; pChar2->m_virtualGold += iGold1 - iGold2; pChar1->UpdateStatsFlag(); pChar2->UpdateStatsFlag(); } // done with trade. Delete(); }