Ejemplo n.º 1
0
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");
}