int TradeCurrencyHandler::protected_helper_query_trade_currency(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { if (query->argCount < 2) return QueryErrorMsg::GENERIC; //Ignore currency type for now, assume always copper. Just get the amount. // Note: I found no evidence that the credit currency could actually be used // in trades. //args[0] is usually COPPER int amount = strtol(query->args[1].c_str(), NULL, 10); 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->SetCoin(amount); if (tradeData->player->otherPlayerData->tradeWindowOpen == true) { int wpos = PrepExt_TradeCurrencyOffer(sim->SendBuf, selfID, amount); SendToOneSimulator(sim->SendBuf, wpos, cInst->simulatorPtr); } return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK"); }
int TradeOfferHandler::protected_helper_query_trade_offer(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; 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_MADE); //eventType PutShort(&sim->SendBuf[1], wpos - 3); //Set message size SendToOneSimulator(sim->SendBuf, wpos, cInst->simulatorPtr); //actInst->LSendToOneSimulator(SendBuf, wpos, cInst->SimulatorIndex); return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK"); }
int TradeManager :: CancelTransaction(int playerID, int tradeID, char *buffer) { //Removes a transaction from the list. Prepares and sends a close message //to the players involved. //The return value needs to be a generic error, so the calling function can //easily exit by do something like "return CancelTransaction()"; TradeTransaction *tradeData = GetExistingTransaction(tradeID); if(tradeData == NULL) return -1; if(playerID == tradeData->player[1].selfPlayerID) playerID = tradeData->player[0].selfPlayerID; int wpos = 0; wpos += PutByte(&buffer[wpos], 51); //_handleTradeMsg wpos += PutShort(&buffer[wpos], 0); //Placeholder for size wpos += PutInteger(&buffer[wpos], playerID); //traderID wpos += PutByte(&buffer[wpos], TradeEventTypes::REQUEST_CLOSED); //eventType wpos += PutByte(&buffer[wpos], CloseReasons::CANCELED); //eventType PutShort(&buffer[1], wpos - 3); //Set message size //Send to both players. SendToOneSimulator(buffer, wpos, tradeData->player[0].cInst->simulatorPtr); SendToOneSimulator(buffer, wpos, tradeData->player[1].cInst->simulatorPtr); //tradeData->player[0].cInst->actInst->LSendToOneSimulator(buffer, wpos, tradeData->player[0].cInst->SimulatorIndex); //tradeData->player[1].cInst->actInst->LSendToOneSimulator(buffer, wpos, tradeData->player[1].cInst->SimulatorIndex); //Remove trade data tradeData->player[0].cInst->activeLootID = 0; tradeData->player[1].cInst->activeLootID = 0; //Remove this trade object entirely. RemoveTransaction(tradeID); return -1; }
int TradeItemsHandler::protected_helper_query_trade_items(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); if (pData->otherPlayerData->tradeWindowOpen == false) return QueryErrorMsg::TRADENOTOPENED; InventorySlot item; pData->itemList.clear(); for (unsigned int a = 0; a < query->argCount; a++) { unsigned long CCSID = strtol(query->args[a].c_str(), NULL, 16); InventorySlot *itemPtr = pld->charPtr->inventory.GetItemPtrByCCSID( CCSID); if (itemPtr == NULL) return QueryErrorMsg::INVALIDITEM; item.CopyFrom(*itemPtr, false); item.CCSID = CCSID; pData->itemList.push_back(item); } CreatureInstance *cInst = pData->otherPlayerData->cInst; int wpos = PrepExt_TradeItemOffer(sim->SendBuf, sim->Aux3, selfID, pData->itemList); SendToOneSimulator(sim->SendBuf, wpos, cInst->simulatorPtr); return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK"); }
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"); }
int TradeStartHandler::protected_helper_query_trade_start(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { // Note: query errors don't seem to do anything in the client. // Note: The trade starter has an argument for the target player. // When the target player accepts, there is no argument to this // query. int selfPlayerID = creatureInstance->CreatureID; int otherPlayerID = 0; if (query->argCount > 0) otherPlayerID = query->GetInteger(0); ActiveInstance *actInst = creatureInstance->actInst; if (actInst == NULL) { g_Logs.simulator->error( "[%v] trade.start active instance is NULL", sim->InternalID); return QueryErrorMsg::INVALIDOBJ; } CreatureInstance *target = NULL; if (otherPlayerID != 0) { //Make sure we're not busy. if (sim->CanMoveItems() == false) return QueryErrorMsg::SELFBUSYSKILL; //Make sure the other player exists target = actInst->GetPlayerByID(otherPlayerID); if (target == NULL) return QueryErrorMsg::INVALIDOBJ; //Make sure the other player isn't busy if (actInst->tradesys.GetExistingTradeForPlayer(otherPlayerID) != NULL) return QueryErrorMsg::TRADEBUSY; if (target->simulatorPtr->CanMoveItems() == false) return QueryErrorMsg::OTHERBUSYSKILL; } //It only takes one player to start the trade for both, so initialize a //transaction for both players. int CheckID = creatureInstance->activeLootID; if (CheckID == 0) CheckID = selfPlayerID; TradeTransaction *tradeData = actInst->tradesys.GetNewTransaction(CheckID); //tradeData->Clear(); bool initiator = false; if (otherPlayerID != 0) { initiator = true; tradeData->SetPlayers(creatureInstance, target); creatureInstance->activeLootID = CheckID; target->activeLootID = CheckID; tradeData->init = true; } else { //This is the accepting player, so the target must be the origin. otherPlayerID = tradeData->player[0].selfPlayerID; target = tradeData->player[0].cInst; } if (target == NULL || otherPlayerID == 0) return QueryErrorMsg::INVALIDOBJ; tradeData->GetPlayerData(selfPlayerID)->tradeWindowOpen = true; if (initiator == true) { // Send trade request message to the other player. int wpos = 0; wpos += PutByte(&sim->SendBuf[wpos], 51); //_handleTradeMsg wpos += PutShort(&sim->SendBuf[wpos], 0); wpos += PutInteger(&sim->SendBuf[wpos], selfPlayerID); //traderID wpos += PutByte(&sim->SendBuf[wpos], TradeEventTypes::REQUEST); //eventType PutShort(&sim->SendBuf[1], wpos - 3); SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); } else { int wpos = 0; wpos += PutByte(&sim->SendBuf[wpos], 51); //_handleTradeMsg wpos += PutShort(&sim->SendBuf[wpos], 0); wpos += PutInteger(&sim->SendBuf[wpos], selfPlayerID); //traderID wpos += PutByte(&sim->SendBuf[wpos], TradeEventTypes::REQUEST_ACCEPTED); //eventType PutShort(&sim->SendBuf[1], wpos - 3); SendToOneSimulator(sim->SendBuf, wpos, target->simulatorPtr); } return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK"); }