void Inventory::handleDragAndDrop() { if (!m_hasDraggingStarted) return; InventorySlot* selectedSlot = getSelectedSlot(); if (!(g_inputController->isMousePressedLeft())) { if (selectedSlot != nullptr) { selectedSlot->activate(); handleLevelDrop(); handleMapDrop(); } delete m_currentClone; m_currentClone = nullptr; m_hasDraggingStarted = false; m_isDragging = false; return; } sf::Vector2f mousePos = g_inputController->getDefaultViewMousePosition(); if (!m_isDragging) { if (DRAG_DISTANCE < std::sqrt( (mousePos.x - m_startMousePosition.x) * (mousePos.x - m_startMousePosition.x) + (mousePos.y - m_startMousePosition.y) * (mousePos.y - m_startMousePosition.y))) { m_isDragging = true; delete m_currentClone; m_currentClone = new SlotClone(selectedSlot); m_currentClone->setPosition(mousePos - sf::Vector2f(InventorySlot::SIZE / 2.f, InventorySlot::SIZE / 2.f)); selectedSlot->deactivate(); handleLevelDrag(); handleMapDrag(); } } else { m_currentClone->setPosition(mousePos - sf::Vector2f(InventorySlot::SIZE / 2.f, InventorySlot::SIZE / 2.f)); } }
void Inventory::handleLevelDrag() { if (m_levelInterface == nullptr) return; InventorySlot* selectedSlot = getSelectedSlot(); if (selectedSlot != nullptr && selectedSlot->getItemType() == ItemType::Consumable) { m_levelInterface->highlightQuickslots(true); } }
int TradeShopHandler::helper_trade_shop_sell(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance, const char *itemHex) { //Return the query response when selling stuff to an NPC shop. unsigned int CCSID = strtol(itemHex, NULL, 16); InventorySlot *item = pld->charPtr->inventory.GetItemPtrByCCSID(CCSID); if (item == NULL) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Item not found in inventory."); ItemDef *itemPtr = item->ResolveItemPtr(); if (itemPtr == NULL) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Item does not exist in server database."); int wpos = 0; wpos += PrepExt_QueryResponseString(&sim->SendBuf[wpos], query->ID, "OK"); int cost = itemPtr->mValue; cost *= item->GetStackCount(); wpos += pld->charPtr->inventory.AddBuyBack(item, &sim->SendBuf[wpos]); wpos += RemoveItemUpdate(&sim->SendBuf[wpos], sim->Aux3, item); pld->charPtr->inventory.RemItem(CCSID); pld->charPtr->pendingChanges++; creatureInstance->AdjustCopper(cost); return wpos; }
void Inventory::handleMapDrag() { if (m_mapInterface == nullptr) return; InventorySlot* selectedSlot = getSelectedSlot(); if (selectedSlot != nullptr && !m_isEquipmentSlotDragged) { m_equipment->highlightEquipmentSlot(selectedSlot->getItemType(), true); } }
void Inventory::handleLevelDrop() { if (m_levelInterface == nullptr || m_currentClone == nullptr) return; InventorySlot* selectedSlot = getSelectedSlot(); if (selectedSlot != nullptr && selectedSlot->getItemType() == ItemType::Consumable) { m_levelInterface->notifyConsumableDrop(m_currentClone); m_levelInterface->highlightQuickslots(false); } }
void Inventory::deselectCurrentSlot() { InventorySlot* slot = getSelectedSlot(); m_selectedSlotId.first = ""; m_selectedSlotId.second = ItemType::VOID; m_descriptionWindow->hide(); if (slot != nullptr) { slot->deselect(); } }
int TradeShopHandler::helper_trade_shop_buyback(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance,unsigned int CCSID) { InventorySlot *buybackItem = pld->charPtr->inventory.GetItemPtrByCCSID( CCSID); if (buybackItem == NULL) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Item not found in buyback list."); int freeslot = pld->charPtr->inventory.GetFreeSlot(INV_CONTAINER); if (freeslot == -1) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "No free inventory space."); ItemDef *itemPtr = buybackItem->ResolveItemPtr(); if (itemPtr == NULL) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Item does not exist in database."); int cost = itemPtr->mValue * buybackItem->GetStackCount(); if (creatureInstance->css.copper < cost) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Not enough coin."); InventorySlot newItem; newItem.CopyFrom(*buybackItem, false); newItem.CCSID = pld->charPtr->inventory.GetCCSID(INV_CONTAINER, freeslot); int r = pld->charPtr->inventory.AddItem(INV_CONTAINER, newItem); if (r == -1) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Failed to create item."); pld->charPtr->pendingChanges++; int wpos = 0; wpos = RemoveItemUpdate(sim->SendBuf, sim->Aux3, buybackItem); wpos += AddItemUpdate(&sim->SendBuf[wpos], sim->Aux3, &newItem); wpos += PrepExt_QueryResponseString(&sim->SendBuf[wpos], query->ID, "OK"); pld->charPtr->inventory.RemItem(buybackItem->CCSID); pld->charPtr->pendingChanges++; creatureInstance->AdjustCopper(-cost); return wpos; }
void Inventory::selectSlot(const std::string& selectedSlotId, ItemType type) { if (selectedSlotId.empty()) { deselectCurrentSlot(); return; } m_hasDraggingStarted = true; m_isEquipmentSlotDragged = type != ItemType::VOID; m_startMousePosition = g_inputController->getDefaultViewMousePosition(); if (selectedSlotId.compare(m_selectedSlotId.first) == 0) return; deselectCurrentSlot(); m_selectedSlotId.first = selectedSlotId; m_selectedSlotId.second = type; InventorySlot* selectedSlot = getSelectedSlot(); hideDocument(); if (selectedSlot != nullptr) { selectedSlot->select(); showDescription(selectedSlot->getItem()); } }
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"); }
void Inventory::update(const sf::Time& frameTime) { if (!m_isVisible) return; // check whether an item was selected for (auto& it : *(m_typeMap.at(m_currentTab))) { it.second.update(frameTime); if (it.second.isClicked()) { selectSlot(it.second.getItemID(), ItemType::VOID); return; } if (it.second.isRightClicked()) { handleLevelRightClick(&it.second); handleMapRightClick(&it.second); break; } } for (auto& it : m_tabs) { it.first.update(frameTime); if (it.first.isClicked() && m_currentTab != it.second) { selectTab(it.second); return; } } // update equipment part m_equipment->update(frameTime); InventorySlot* eqSlot = m_equipment->getSelectedSlot(); if (eqSlot != nullptr) { selectSlot(eqSlot->getItemID(), eqSlot->getItemType()); } handleDragAndDrop(); if (m_equipment->requiresReload()) { reload(); } }
void CGAddMouseToQuickSlotHandler::execute (CGAddMouseToQuickSlot* pPacket , Player* pPlayer) throw(ProtocolException, Error) { __BEGIN_TRY __BEGIN_DEBUG_EX #ifdef __GAME_SERVER__ Assert(pPacket != NULL); Assert(pPlayer != NULL); GamePlayer* pGamePlayer = dynamic_cast<GamePlayer*>(pPlayer); Creature* pCreature = pGamePlayer->getCreature(); bool Success = false; if (pCreature->isSlayer()) { Slayer* pSlayer = dynamic_cast<Slayer*>(pCreature); InventorySlot* pExtraSlot = pSlayer->getExtraInventorySlot(); Item* pItem = pExtraSlot->getItem(); if (pItem == NULL) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } ObjectID_t ItemObjectID = pItem->getObjectID(); SlotID_t SlotID = pPacket->getSlotID(); Item::ItemClass IClass = pItem->getItemClass(); // 아이템의 ObjectID가 일치하는지 체크한다. if (ItemObjectID != pPacket->getObjectID()) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } // 벨트를 입고 있지 않다면 벨트에다 아이템을 더할 수가 없다. if (!pSlayer->isWear(Slayer::WEAR_BELT)) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } // 포션도 아니고, 탄창도 아니라면 더할 수가 없지. if (IClass != Item::ITEM_CLASS_POTION && IClass != Item::ITEM_CLASS_MAGAZINE && IClass != Item::ITEM_CLASS_EVENT_ETC && IClass != Item::ITEM_CLASS_KEY) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } if (IClass == Item::ITEM_CLASS_EVENT_ETC && pItem->getItemType() < 14 ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } Item* pBelt = pSlayer->getWearItem(Slayer::WEAR_BELT); Inventory* pBeltInventory = ((Belt*)pBelt)->getInventory(); if (pBeltInventory->canAdding(SlotID, 0, pItem)) { // 현재 벨트에 있는 Item을 받아온다. Item* pPrevItem = pBeltInventory->getItem(SlotID, 0); // 지정한 자리에 아이템이 있다면... if (pPrevItem != NULL) { // 아이템이 완전히 같은 아이템이라면... if (isStackable(pItem) && isSameItem(pItem, pPrevItem)) { int MaxStack = ItemMaxStack[pItem->getItemClass()]; if (pItem->getNum() + pPrevItem->getNum() > MaxStack) { ItemNum_t CurrentNum = pPrevItem->getNum(); ItemNum_t AddNum = pItem->getNum(); ItemNum_t NewNum = AddNum + CurrentNum - MaxStack; pPrevItem->setNum(MaxStack); pItem->setNum(NewNum); pBeltInventory->increaseNum(MaxStack - CurrentNum); pBeltInventory->increaseWeight(pItem->getWeight()* (MaxStack - CurrentNum)); //pPrevItem->save(pSlayer->getName(), STORAGE_BELT, pBelt->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%lu, X=%d", MaxStack, STORAGE_BELT, pBelt->getItemID(), SlotID); pPrevItem->tinysave(pField); //pItem->save(pSlayer->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Num=%d, Storage=%d", NewNum, STORAGE_EXTRASLOT); pItem->tinysave(pField); Success = true; } else // 숫자가 9개를 넘지 않을 때. { pSlayer->deleteItemFromExtraInventorySlot(); pPrevItem->setNum(pPrevItem->getNum() + pItem->getNum()); pBeltInventory->increaseNum(pItem->getNum()); pBeltInventory->increaseWeight(pItem->getWeight()* pItem->getNum()); //pPrevItem->save(pSlayer->getName(), STORAGE_BELT , pBelt->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%lu, X=%d", pPrevItem->getNum(), STORAGE_BELT, pBelt->getItemID(), SlotID); pPrevItem->tinysave(pField); pItem->destroy(); SAFE_DELETE(pItem); Success = true; } } else // 클래스랑 타입이 같지 않을때 { // 마우스에 달려있는 아이템과 벨트에 있는 아이템을 제거한다. pSlayer->deleteItemFromExtraInventorySlot(); pBeltInventory->deleteItem(pPrevItem->getObjectID()); // 둘의 위치를 바꿔 준다. pSlayer->addItemToExtraInventorySlot(pPrevItem); pBeltInventory->addItem(SlotID , 0 , pItem); // DB에다가 저장을 한다. //pPrevItem->save(pSlayer->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d", STORAGE_EXTRASLOT); pPrevItem->tinysave(pField); //pItem->save(pSlayer->getName(), STORAGE_BELT , pBelt->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Storage=%d, StorageID=%lu, X=%d", STORAGE_BELT, pBelt->getItemID(), SlotID); pItem->tinysave(pField); Success = true; } } else // 슬랏에 아무런 기존의 아이템이 없을때. { // Inventory에 특정 아이템을 넣는다. pBeltInventory->addItem(SlotID, 0 , pItem); // 넣기에 성공하면 마우스에 달려있는 아이템을 없앤다. pSlayer->deleteItemFromExtraInventorySlot(); //pItem->save(pSlayer->getName(), STORAGE_BELT, pBelt->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d, StorageID=%lu, X=%d", STORAGE_BELT, pBelt->getItemID(), SlotID); pItem->tinysave(pField); Success = true; } } // end of if (pBeltInventory->canAdding(SlotID, 0, pItem)) } // if (pCreature->isSlayer()) else if (pCreature->isOusters()) { Ousters* pOusters = dynamic_cast<Ousters*>(pCreature); InventorySlot* pExtraSlot = pOusters->getExtraInventorySlot(); Item* pItem = pExtraSlot->getItem(); if (pItem == NULL) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } ObjectID_t ItemObjectID = pItem->getObjectID(); SlotID_t SlotID = pPacket->getSlotID(); Item::ItemClass IClass = pItem->getItemClass(); // 아이템의 ObjectID가 일치하는지 체크한다. if (ItemObjectID != pPacket->getObjectID()) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } Ousters::WearPart part = (SlotID > 2 ? Ousters::WEAR_ARMSBAND2 : Ousters::WEAR_ARMSBAND1); if (SlotID > 2 ) SlotID -= 3; // 해당 암스밴드가 없다 if (!pOusters->isWear(part)) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } // 푸파도 아니고, 콤포스메이도 아니라면 더할 수가 없지. if (IClass != Item::ITEM_CLASS_PUPA && IClass != Item::ITEM_CLASS_COMPOS_MEI && IClass != Item::ITEM_CLASS_EVENT_ETC ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } if (IClass == Item::ITEM_CLASS_EVENT_ETC && pItem->getItemType() < 14 ) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); return; } Item* pArmsband = pOusters->getWearItem(part); Inventory* pArmsbandInventory = ((OustersArmsband*)pArmsband)->getInventory(); if (pArmsbandInventory->canAdding(SlotID, 0, pItem)) { // 현재 벨트에 있는 Item을 받아온다. Item* pPrevItem = pArmsbandInventory->getItem(SlotID, 0); // 지정한 자리에 아이템이 있다면... if (pPrevItem != NULL) { // 아이템이 완전히 같은 아이템이라면... if (isSameItem(pItem, pPrevItem)) { int MaxStack = ItemMaxStack[pItem->getItemClass()]; if (pItem->getNum() + pPrevItem->getNum() > MaxStack) { ItemNum_t CurrentNum = pPrevItem->getNum(); ItemNum_t AddNum = pItem->getNum(); ItemNum_t NewNum = AddNum + CurrentNum - MaxStack; pPrevItem->setNum(MaxStack); pItem->setNum(NewNum); pArmsbandInventory->increaseNum(MaxStack - CurrentNum); pArmsbandInventory->increaseWeight(pItem->getWeight()* (MaxStack - CurrentNum)); //pPrevItem->save(pOusters->getName(), STORAGE_BELT, pArmsband->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%lu, X=%d", MaxStack, STORAGE_BELT, pArmsband->getItemID(), SlotID); pPrevItem->tinysave(pField); //pItem->save(pOusters->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Num=%d, Storage=%d", NewNum, STORAGE_EXTRASLOT); pItem->tinysave(pField); Success = true; } else // 숫자가 9개를 넘지 않을 때. { pOusters->deleteItemFromExtraInventorySlot(); pPrevItem->setNum(pPrevItem->getNum() + pItem->getNum()); pArmsbandInventory->increaseNum(pItem->getNum()); pArmsbandInventory->increaseWeight(pItem->getWeight()* pItem->getNum()); //pPrevItem->save(pOusters->getName(), STORAGE_BELT , pArmsband->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Num=%d, Storage=%d, StorageID=%lu, X=%d", pPrevItem->getNum(), STORAGE_BELT, pArmsband->getItemID(), SlotID); pPrevItem->tinysave(pField); pItem->destroy(); SAFE_DELETE(pItem); Success = true; } } else // 클래스랑 타입이 같지 않을때 { // 마우스에 달려있는 아이템과 벨트에 있는 아이템을 제거한다. pOusters->deleteItemFromExtraInventorySlot(); pArmsbandInventory->deleteItem(pPrevItem->getObjectID()); // 둘의 위치를 바꿔 준다. pOusters->addItemToExtraInventorySlot(pPrevItem); pArmsbandInventory->addItem(SlotID , 0 , pItem); // DB에다가 저장을 한다. //pPrevItem->save(pOusters->getName(), STORAGE_EXTRASLOT, 0, 0, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d", STORAGE_EXTRASLOT); pPrevItem->tinysave(pField); //pItem->save(pOusters->getName(), STORAGE_BELT , pArmsband->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 sprintf(pField, "Storage=%d, StorageID=%lu, X=%d", STORAGE_BELT, pArmsband->getItemID(), SlotID); pItem->tinysave(pField); Success = true; } } else // 슬랏에 아무런 기존의 아이템이 없을때. { // Inventory에 특정 아이템을 넣는다. pArmsbandInventory->addItem(SlotID, 0 , pItem); // 넣기에 성공하면 마우스에 달려있는 아이템을 없앤다. pOusters->deleteItemFromExtraInventorySlot(); //pItem->save(pOusters->getName(), STORAGE_BELT, pArmsband->getItemID(), SlotID, 0); // item저장 최적화. by sigi. 2002.5.13 char pField[80]; sprintf(pField, "Storage=%d, StorageID=%lu, X=%d", STORAGE_BELT, pArmsband->getItemID(), SlotID); pItem->tinysave(pField); Success = true; } } // end of if (pArmsbandInventory->canAdding(SlotID, 0, pItem)) } // if (pCreature->isOusters()) // QuickSlot에 넣는 것을 실패 하였을때 실패 패킷을 날린다. if (!Success) { GCCannotAdd _GCCannotAdd; _GCCannotAdd.setObjectID(pPacket->getObjectID()); pPlayer->sendPacket(&_GCCannotAdd); } #endif // __GAME_SERVER__ __END_DEBUG_EX __END_CATCH }
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"); }