bool Game::playerRequestTrade(Player* player, const Position& pos, uint8_t stackPos,
uint32_t playerId, uint16_t spriteId)
{
OTSYS_THREAD_LOCK_CLASS lockClass(gameLock, "Game::playerRequestTrade()");
if(player->isRemoved())
return false;
Player* tradePartner = getPlayerByID(playerId);
if(!tradePartner || tradePartner == player) {
player->sendTextMessage(MSG_INFO_DESCR, "Sorry, not possible.");
return false;
}
if(!Position::areInRange<2,2,0>(tradePartner->getPosition(), player->getPosition())){
std::stringstream ss;
ss << tradePartner->getName() << " tells you to move closer.";
player->sendTextMessage(MSG_INFO_DESCR, ss.str());
return false;
}
Item* tradeItem = dynamic_cast<Item*>(internalGetThing(player, pos, stackPos, spriteId, STACKPOS_USE));
if(!tradeItem || tradeItem->getClientID() != spriteId || !tradeItem->isPickupable()) {
player->sendCancelMessage(RET_NOTPOSSIBLE);
return false;
}
else if(player->getPosition().z > tradeItem->getPosition().z){
player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
return false;
}
else if(player->getPosition().z < tradeItem->getPosition().z){
player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
return false;
}
else if(!Position::areInRange<1,1,0>(tradeItem->getPosition(), player->getPosition())){
player->sendCancelMessage(RET_TOOFARAWAY);
return false;
}
std::map<Item*, unsigned long>::const_iterator it;
const Container* container = NULL;
for(it = tradeItems.begin(); it != tradeItems.end(); it++) {
if(tradeItem == it->first ||
((container = dynamic_cast<const Container*>(tradeItem)) && container->isHoldingItem(it->first)) ||
((container = dynamic_cast<const Container*>(it->first)) && container->isHoldingItem(tradeItem)))
{
player->sendTextMessage(MSG_INFO_DESCR, "This item is already being traded.");
return false;
}
}
Container* tradeContainer = tradeItem->getContainer();
if(tradeContainer && tradeContainer->getItemHoldingCount() + 1 > 100){
player->sendTextMessage(MSG_INFO_DESCR, "You can not trade more than 100 items.");
return false;
}
return internalStartTrade(player, tradePartner, tradeItem);
}
bool Game::internalStartTrade(Player* player, Player* tradePartner, Item* tradeItem)
{
if(player->tradeState != TRADE_NONE && !(player->tradeState == TRADE_ACKNOWLEDGE && player->tradePartner == tradePartner)) {
player->sendCancelMessage(RET_YOUAREALREADYTRADING);
return false;
}
else if(tradePartner->tradeState != TRADE_NONE && tradePartner->tradePartner != player) {
player->sendCancelMessage(RET_THISPLAYERISALREADYTRADING);
return false;
}
player->tradePartner = tradePartner;
player->tradeItem = tradeItem;
player->tradeState = TRADE_INITIATED;
tradeItem->useThing2();
tradeItems[tradeItem] = player->getID();
player->sendTradeItemRequest(player, tradeItem, true);
if(tradePartner->tradeState == TRADE_NONE){
std::stringstream trademsg;
trademsg << player->getName() <<" wants to trade with you.";
tradePartner->sendTextMessage(MSG_INFO_DESCR, trademsg.str());
tradePartner->tradeState = TRADE_ACKNOWLEDGE;
tradePartner->tradePartner = player;
}
else{
Item* counterOfferItem = tradePartner->tradeItem;
player->sendTradeItemRequest(tradePartner, counterOfferItem, false);
tradePartner->sendTradeItemRequest(player, tradeItem, false);
}
return true;
}
bool Game::playerAcceptTrade(Player* player)
{
player->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
}
bool Game::playerLookInTrade(Player* player, bool lookAtCounterOffer, int index)
{
OTSYS_THREAD_LOCK_CLASS lockClass(gameLock, "Game::playerLookInTrade()");
if(player->isRemoved())
return false;
Player* tradePartner = player->tradePartner;
if(!tradePartner)
return false;
Item* tradeItem = NULL;
if(lookAtCounterOffer)
tradeItem = tradePartner->getTradeItem();
else
tradeItem = player->getTradeItem();
if(!tradeItem)
return false;
int32_t lookDistance = std::max(std::abs(player->getPosition().x - tradeItem->getPosition().x),
std::abs(player->getPosition().y - tradeItem->getPosition().y));
if(index == 0){
std::stringstream ss;
ss << "You see " << tradeItem->getDescription(lookDistance);
player->sendTextMessage(MSG_INFO_DESCR, ss.str());
return false;
}
Container* tradeContainer = tradeItem->getContainer();
if(!tradeContainer || index > (int)tradeContainer->getItemHoldingCount())
return false;
bool foundItem = false;
std::list<const Container*> listContainer;
ItemList::const_iterator it;
Container* tmpContainer = NULL;
listContainer.push_back(tradeContainer);
while(!foundItem && listContainer.size() > 0){
const Container* container = listContainer.front();
listContainer.pop_front();
for(it = container->getItems(); it != container->getEnd(); ++it){
if(tmpContainer = (*it)->getContainer()){
listContainer.push_back(tmpContainer);
}
--index;
if(index == 0){
tradeItem = *it;
foundItem = true;
break;
}
}
}
if(foundItem){
std::stringstream ss;
ss << "You see " << tradeItem->getDescription(lookDistance);
player->sendTextMessage(MSG_INFO_DESCR, ss.str());
}
return foundItem;
}
bool Game::playerCloseTrade(Player* player)
{
OTSYS_THREAD_LOCK_CLASS lockClass(gameLock, "Game::playerCloseTrade()");
if(player->isRemoved())
return false;
Player* tradePartner = player->tradePartner;
if((tradePartner && tradePartner->getTradeState() == TRADE_TRANSFER) ||
player->getTradeState() == TRADE_TRANSFER){
std::cout << "Warning: [Game::playerCloseTrade] TradeState == TRADE_TRANSFER. " <<
player->getName() << " " << player->getTradeState() << " , " <<
tradePartner->getName() << " " << tradePartner->getTradeState() << std::endl;
return true;
}
std::vector<Item*>::iterator it;
if(player->getTradeItem()){
std::map<Item*, unsigned long>::iterator it = tradeItems.find(player->getTradeItem());
if(it != tradeItems.end()) {
FreeThing(it->first);
tradeItems.erase(it);
}
player->tradeItem->onTradeEvent(ON_TRADE_CANCEL, player);
player->tradeItem = NULL;
}
player->setTradeState(TRADE_NONE);
player->tradePartner = NULL;
player->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
player->sendTradeClose();
if(tradePartner){
if(tradePartner->getTradeItem()){
std::map<Item*, unsigned long>::iterator it = tradeItems.find(tradePartner->getTradeItem());
if(it != tradeItems.end()) {
FreeThing(it->first);
tradeItems.erase(it);
}
tradePartner->tradeItem->onTradeEvent(ON_TRADE_CANCEL, tradePartner);
tradePartner->tradeItem = NULL;
}
tradePartner->setTradeState(TRADE_NONE);
tradePartner->tradePartner = NULL;
tradePartner->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
tradePartner->sendTradeClose();
}
return true;
}