int TradeAcceptHandler::protected_helper_query_trade_accept(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { int selfID = creatureInstance->CreatureID; int tradeID = creatureInstance->activeLootID; ActiveInstance *actInst = creatureInstance->actInst; TradeTransaction *tradeData = actInst->tradesys.GetExistingTransaction( tradeID); if (tradeData == NULL) return QueryErrorMsg::TRADENOTFOUND; TradePlayerData *pData = tradeData->GetPlayerData(selfID); if (pData == NULL) return actInst->tradesys.CancelTransaction(selfID, tradeID, sim->SendBuf); CreatureInstance *cInst = pData->otherPlayerData->cInst; pData->SetAccepted(true); int wpos = 0; wpos += PutByte(&sim->SendBuf[wpos], 51); //_handleTradeMsg wpos += PutShort(&sim->SendBuf[wpos], 0); //Placeholder for size wpos += PutInteger(&sim->SendBuf[wpos], creatureInstance->CreatureID); //traderID wpos += PutByte(&sim->SendBuf[wpos], TradeEventTypes::OFFER_ACCEPTED); //eventType PutShort(&sim->SendBuf[1], wpos - 3); //Set message size SendToOneSimulator(sim->SendBuf, wpos, cInst->simulatorPtr); //actInst->LSendToOneSimulator(SendBuf, wpos, cInst->SimulatorIndex); CreatureInstance *origin = tradeData->player[0].cInst; CreatureInstance *target = tradeData->player[1].cInst; if (origin == NULL || target == NULL) return QueryErrorMsg::INVALIDOBJ; if (tradeData->MutualAccept() == true) { //Process the trade. int wpos = 0; //When counting slots, get the currently free slots. //Then add the number of items that would be traded (given away). //This allows a currently full inventory to potentially receive items //after the transaction is processed. int oslots = origin->charPtr->inventory.CountFreeSlots(INV_CONTAINER); oslots += tradeData->player[0].itemList.size(); int tslots = target->charPtr->inventory.CountFreeSlots(INV_CONTAINER); tslots += tradeData->player[1].itemList.size(); if (oslots < (int) tradeData->player[1].itemList.size()) { //Origin player does not have enough space to receive items. wpos = 0; wpos += PutByte(&sim->SendBuf[wpos], 51); //_handleTradeMsg wpos += PutShort(&sim->SendBuf[wpos], 0); //Placeholder for size wpos += PutInteger(&sim->SendBuf[wpos], origin->CreatureID); //traderID wpos += PutByte(&sim->SendBuf[wpos], TradeEventTypes::REQUEST_CLOSED); //eventType wpos += PutByte(&sim->SendBuf[wpos], CloseReasons::INSUFFICIENT_SPACE); //eventType PutShort(&sim->SendBuf[1], wpos - 3); //Set message size SendToOneSimulator(sim->SendBuf, wpos, origin->simulatorPtr); SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); //origin->actInst->LSendToOneSimulator(SendBuf, wpos, origin->SimulatorIndex); //target->actInst->LSendToOneSimulator(SendBuf, wpos, target->SimulatorIndex); g_Logs.simulator->debug("[%v] Origin lacks space", sim->InternalID); goto exit; } if (tslots < (int) tradeData->player[0].itemList.size()) { //Target player does not have enough space to receive items. wpos = 0; wpos += PutByte(&sim->SendBuf[wpos], 51); //_handleTradeMsg wpos += PutShort(&sim->SendBuf[wpos], 0); //Placeholder for size wpos += PutInteger(&sim->SendBuf[wpos], target->CreatureID); //traderID wpos += PutByte(&sim->SendBuf[wpos], TradeEventTypes::REQUEST_CLOSED); //eventType wpos += PutByte(&sim->SendBuf[wpos], CloseReasons::INSUFFICIENT_SPACE); //eventType PutShort(&sim->SendBuf[1], wpos - 3); //Set message size SendToOneSimulator(sim->SendBuf, wpos, origin->simulatorPtr); SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); //origin->actInst->LSendToOneSimulator(SendBuf, wpos, origin->SimulatorIndex); //target->actInst->LSendToOneSimulator(SendBuf, wpos, target->SimulatorIndex); g_Logs.simulator->debug("[%v] Target lacks space", sim->InternalID); goto exit; } //Check that each player has the required currencies. if (tradeData->player[0].coin > origin->css.copper) { wpos = 0; wpos += PutByte(&sim->SendBuf[wpos], 51); //_handleTradeMsg wpos += PutShort(&sim->SendBuf[wpos], 0); //Placeholder for size wpos += PutInteger(&sim->SendBuf[wpos], origin->CreatureID); //traderID wpos += PutByte(&sim->SendBuf[wpos], TradeEventTypes::REQUEST_CLOSED); //eventType wpos += PutByte(&sim->SendBuf[wpos], CloseReasons::INSUFFICIENT_FUNDS); //eventType PutShort(&sim->SendBuf[1], wpos - 3); //Set message size SendToOneSimulator(sim->SendBuf, wpos, origin->simulatorPtr); SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); //origin->actInst->LSendToOneSimulator(SendBuf, wpos, origin->SimulatorIndex); //target->actInst->LSendToOneSimulator(SendBuf, wpos, target->SimulatorIndex); g_Logs.simulator->debug("[%v] Origin lacks copper", sim->InternalID); goto exit; } if (tradeData->player[1].coin > target->css.copper) { wpos = 0; wpos += PutByte(&sim->SendBuf[wpos], 51); //_handleTradeMsg wpos += PutShort(&sim->SendBuf[wpos], 0); //Placeholder for size wpos += PutInteger(&sim->SendBuf[wpos], target->CreatureID); //traderID wpos += PutByte(&sim->SendBuf[wpos], TradeEventTypes::REQUEST_CLOSED); //eventType wpos += PutByte(&sim->SendBuf[wpos], CloseReasons::INSUFFICIENT_FUNDS); //eventType PutShort(&sim->SendBuf[1], wpos - 3); //Set message size SendToOneSimulator(sim->SendBuf, wpos, origin->simulatorPtr); SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); //origin->actInst->LSendToOneSimulator(SendBuf, wpos, origin->SimulatorIndex); //target->actInst->LSendToOneSimulator(SendBuf, wpos, target->SimulatorIndex); g_Logs.simulator->debug("[%v] Target lacks copper", sim->InternalID); goto exit; } //Ready to trade. g_Logs.simulator->debug("[%v] Trade requirements passed", sim->InternalID); //Adjust and send coin transfer to both players. origin->css.copper -= tradeData->player[0].coin; target->css.copper -= tradeData->player[1].coin; origin->css.copper += tradeData->player[1].coin; target->css.copper += tradeData->player[0].coin; static const short statSend = STAT::COPPER; wpos = PrepExt_SendSpecificStats(sim->SendBuf, origin, &statSend, 1); SendToOneSimulator(sim->SendBuf, wpos, origin->simulatorPtr); //origin->actInst->LSendToOneSimulator(SendBuf, wpos, origin->SimulatorIndex); wpos = PrepExt_SendSpecificStats(sim->SendBuf, target, &statSend, 1); SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); //origin->actInst->LSendToOneSimulator(SendBuf, wpos, target->SimulatorIndex); //Adjust and send items for first player. //Remove items from first player. wpos = 0; CharacterData *p1 = origin->charPtr; CharacterData *p2 = target->charPtr; g_Logs.simulator->debug("[%v] Trade betweeen [%v] and [%v]", sim->InternalID, p1->cdef.css.display_name, p2->cdef.css.display_name); for (size_t a = 0; a < tradeData->player[0].itemList.size(); a++) { unsigned long CCSID = tradeData->player[0].itemList[a].CCSID; InventorySlot *item = p1->inventory.GetItemPtrByCCSID(CCSID); if (item == NULL) { g_Logs.simulator->error( "[%v] Failed to remove item from first player.", sim->InternalID); } else { wpos += p1->inventory.RemoveItemUpdate(&sim->SendBuf[wpos], sim->Aux3, item); p1->inventory.RemItem(CCSID); p1->pendingChanges++; } } SendToOneSimulator(sim->SendBuf, wpos, origin->simulatorPtr); //origin->actInst->LSendToOneSimulator(SendBuf, wpos, origin->SimulatorIndex); g_Logs.simulator->debug("[%v] Removed %v items from first player.", sim->InternalID, tradeData->player[0].itemList.size()); //Remove items from second player. wpos = 0; for (size_t a = 0; a < tradeData->player[1].itemList.size(); a++) { unsigned long CCSID = tradeData->player[1].itemList[a].CCSID; InventorySlot *item = p2->inventory.GetItemPtrByCCSID(CCSID); if (item == NULL) { g_Logs.simulator->error( "[%v] Failed to remove item from first player.", sim->InternalID); } else { wpos += p2->inventory.RemoveItemUpdate(&sim->SendBuf[wpos], sim->Aux3, item); p2->inventory.RemItem(CCSID); p2->pendingChanges++; } } SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); //target->actInst->LSendToOneSimulator(SendBuf, wpos, target->SimulatorIndex); g_Logs.simulator->debug("[%v] Removed %v items from second player.", sim->InternalID, tradeData->player[1].itemList.size()); //Give items to first player wpos = 0; for (size_t a = 0; a < tradeData->player[1].itemList.size(); a++) { int itemID = tradeData->player[1].itemList[a].IID; int count = tradeData->player[1].itemList[a].count + 1; InventorySlot *item = p1->inventory.AddItem_Ex(INV_CONTAINER, itemID, count); if (item == NULL) g_Logs.simulator->error("[%v] Failed to add item to first player.", sim->InternalID); else { p1->pendingChanges++; g_Logs.event->info("[TRADE] From %v to %v (%v)", tradeData->player[1].cInst->css.display_name, tradeData->player[0].cInst->css.display_name, item->IID); item->CopyWithoutCount(tradeData->player[1].itemList[a], false); sim->ActivateActionAbilities(item); wpos += AddItemUpdate(&sim->SendBuf[wpos], sim->Aux3, item); } } SendToOneSimulator(sim->SendBuf, wpos, origin->simulatorPtr); //origin->actInst->LSendToOneSimulator(SendBuf, wpos, origin->SimulatorIndex); g_Logs.simulator->debug("[%v] Gave %v items to first player.", sim->InternalID, tradeData->player[1].itemList.size()); //Give items to second player wpos = 0; for (size_t a = 0; a < tradeData->player[0].itemList.size(); a++) { int itemID = tradeData->player[0].itemList[a].IID; int count = tradeData->player[0].itemList[a].count + 1; InventorySlot *item = p2->inventory.AddItem_Ex(INV_CONTAINER, itemID, count); if (item == NULL) g_Logs.simulator->error("[%v] Failed to add item to second player.", sim->InternalID); else { p2->pendingChanges++; g_Logs.event->info("[TRADE] From %v to %v (%v)", tradeData->player[0].cInst->css.display_name, tradeData->player[1].cInst->css.display_name, item->IID); item->CopyWithoutCount(tradeData->player[0].itemList[a], false); sim->ActivateActionAbilities(item); wpos += AddItemUpdate(&sim->SendBuf[wpos], sim->Aux3, item); } } SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); //target->actInst->LSendToOneSimulator(SendBuf, wpos, target->SimulatorIndex); g_Logs.simulator->debug("[%v] Gave %v items to second player.", sim->InternalID, tradeData->player[0].itemList.size()); //Send trade completion message. wpos = 0; wpos += PutByte(&sim->SendBuf[wpos], 51); //_handleTradeMsg wpos += PutShort(&sim->SendBuf[wpos], 0); //Placeholder for size wpos += PutInteger(&sim->SendBuf[wpos], origin->CreatureID); //traderID wpos += PutByte(&sim->SendBuf[wpos], TradeEventTypes::REQUEST_CLOSED); //eventType wpos += PutByte(&sim->SendBuf[wpos], CloseReasons::COMPLETE); //eventType PutShort(&sim->SendBuf[1], wpos - 3); //Set message size SendToOneSimulator(sim->SendBuf, wpos, origin->simulatorPtr); //origin->actInst->LSendToOneSimulator(SendBuf, wpos, origin->SimulatorIndex); PutInteger(&sim->SendBuf[3], target->CreatureID); //traderID SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); //target->actInst->LSendToOneSimulator(SendBuf, wpos, target->SimulatorIndex); //Clear trade IDs. origin->activeLootID = 0; target->activeLootID = 0; g_Logs.simulator->debug("[%v] Trade complete", sim->InternalID); actInst->tradesys.RemoveTransaction(tradeID); } //Yes, I'm using goto. //Yes, I know this whole thing is badly programmed. //Deal with it. exit: return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK"); }