#include "../../Minecraft.World/Platform/stdafx.h" #include "../../Minecraft.World/Headers/net.minecraft.world.item.trading.h" #include "../../Minecraft.World/Headers/net.minecraft.world.inventory.h" #include "../../Minecraft.World/Headers/net.minecraft.network.packet.h" #include "../../Minecraft.Client/Minecraft.h" #include "../../Minecraft.Client/Player/MultiPlayerLocalPlayer.h" #include "../../Minecraft.Client/Network/ClientConnection.h" #include "IUIScene_TradingMenu.h" IUIScene_TradingMenu::IUIScene_TradingMenu() { m_validOffersCount = 0; m_selectedSlot = 0; m_offersStartIndex = 0; m_menu = NULL; m_bHasUpdatedOnce = false; } std::shared_ptr IUIScene_TradingMenu::getMerchant() { return m_merchant; } bool IUIScene_TradingMenu::handleKeyDown(int iPad, int iAction, bool bRepeat) { bool handled = false; // MerchantRecipeList *offers = // m_merchant->getOffers(Minecraft::GetInstance()->localplayers[getPad()]); bool changed = false; Minecraft* pMinecraft = Minecraft::GetInstance(); if (pMinecraft->localgameModes[getPad()] != NULL) { Tutorial* tutorial = pMinecraft->localgameModes[getPad()]->getTutorial(); if (tutorial != NULL) { tutorial->handleUIInput(iAction); if (ui.IsTutorialVisible(getPad()) && !tutorial->isInputAllowed(iAction)) { return S_OK; } } } switch (iAction) { case ACTION_MENU_B: ui.ShowTooltip(iPad, eToolTipButtonX, false); ui.ShowTooltip(iPad, eToolTipButtonB, false); ui.ShowTooltip(iPad, eToolTipButtonA, false); ui.ShowTooltip(iPad, eToolTipButtonRB, false); // kill the crafting xui // ui.PlayUISFX(eSFX_Back); ui.CloseUIScenes(iPad); handled = true; break; case ACTION_MENU_A: #ifdef __ORBIS__ case ACTION_MENU_TOUCHPAD_PRESS: #endif if (!m_activeOffers.empty()) { int selectedShopItem = (m_selectedSlot + m_offersStartIndex); if (selectedShopItem < m_activeOffers.size()) { MerchantRecipe* activeRecipe = m_activeOffers.at(selectedShopItem).first; if (!activeRecipe->isDeprecated()) { // Do we have the ingredients? std::shared_ptr buyAItem = activeRecipe->getBuyAItem(); std::shared_ptr buyBItem = activeRecipe->getBuyBItem(); std::shared_ptr player = Minecraft::GetInstance()->localplayers[getPad()]; int buyAMatches = player->inventory->countMatches(buyAItem); int buyBMatches = player->inventory->countMatches(buyBItem); if ((buyAItem != NULL && buyAMatches >= buyAItem->count) && (buyBItem == NULL || buyBMatches >= buyBItem->count)) { // 4J-JEV: Fix for PS4 #7111: [PATCH 1.12] Trading // Librarian villagers for multiple �Enchanted // Books� will cause the title to crash. int actualShopItem = m_activeOffers.at(selectedShopItem).second; m_merchant->notifyTrade(activeRecipe); // Remove the items we are purchasing with player->inventory->removeResources(buyAItem); player->inventory->removeResources(buyBItem); // Add the item we have purchased std::shared_ptr result = activeRecipe->getSellItem()->copy(); if (!player->inventory->add(result)) { player->drop(result); } // Send a packet to the server player->connection->send( std::shared_ptr( new TradeItemPacket(m_menu->containerId, actualShopItem))); updateDisplay(); } } } } handled = true; break; case ACTION_MENU_LEFT: handled = true; if (m_selectedSlot == 0) { if (m_offersStartIndex > 0) { --m_offersStartIndex; changed = true; } } else { --m_selectedSlot; changed = true; moveSelector(false); } break; case ACTION_MENU_RIGHT: handled = true; if (m_selectedSlot == (DISPLAY_TRADES_COUNT - 1)) { if ((m_offersStartIndex + DISPLAY_TRADES_COUNT) < m_activeOffers.size()) { ++m_offersStartIndex; changed = true; } } else { ++m_selectedSlot; changed = true; moveSelector(true); } break; } if (changed) { updateDisplay(); int selectedShopItem = (m_selectedSlot + m_offersStartIndex); if (selectedShopItem < m_activeOffers.size()) { int actualShopItem = m_activeOffers.at(selectedShopItem).second; m_menu->setSelectionHint(actualShopItem); ByteArrayOutputStream rawOutput; DataOutputStream output(&rawOutput); output.writeInt(actualShopItem); Minecraft::GetInstance()->getConnection(getPad())->send( std::shared_ptr(new CustomPayloadPacket( CustomPayloadPacket::TRADER_SELECTION_PACKET, rawOutput.toByteArray()))); } } return handled; } void IUIScene_TradingMenu::handleTick() { int offerCount = 0; MerchantRecipeList* offers = m_merchant->getOffers(Minecraft::GetInstance()->localplayers[getPad()]); if (offers != NULL) { offerCount = offers->size(); if (!m_bHasUpdatedOnce) { updateDisplay(); } } showScrollRightArrow((m_offersStartIndex + DISPLAY_TRADES_COUNT) < m_activeOffers.size()); showScrollLeftArrow(m_offersStartIndex > 0); } void IUIScene_TradingMenu::updateDisplay() { int iA = -1; MerchantRecipeList* unfilteredOffers = m_merchant->getOffers(Minecraft::GetInstance()->localplayers[getPad()]); if (unfilteredOffers != NULL) { m_activeOffers.clear(); int unfilteredIndex = 0; int firstValidTrade = INT_MAX; for (AUTO_VAR(it, unfilteredOffers->begin()); it != unfilteredOffers->end(); ++it) { MerchantRecipe* recipe = *it; if (!recipe->isDeprecated()) { m_activeOffers.push_back( std::pair(recipe, unfilteredIndex)); firstValidTrade = std::min(firstValidTrade, unfilteredIndex); } ++unfilteredIndex; } if (!m_bHasUpdatedOnce) { if (firstValidTrade != 0 && firstValidTrade < unfilteredOffers->size()) { m_menu->setSelectionHint(firstValidTrade); ByteArrayOutputStream rawOutput; DataOutputStream output(&rawOutput); output.writeInt(firstValidTrade); Minecraft::GetInstance()->getConnection(getPad())->send( std::shared_ptr( new CustomPayloadPacket( CustomPayloadPacket::TRADER_SELECTION_PACKET, rawOutput.toByteArray()))); } } if ((m_offersStartIndex + DISPLAY_TRADES_COUNT) > m_activeOffers.size()) { m_offersStartIndex = m_activeOffers.size() - DISPLAY_TRADES_COUNT; if (m_offersStartIndex < 0) m_offersStartIndex = 0; } for (unsigned int i = 0; i < DISPLAY_TRADES_COUNT; ++i) { int offerIndex = i + m_offersStartIndex; bool showRedBox = false; if (offerIndex < m_activeOffers.size()) { showRedBox = !canMake(m_activeOffers.at(offerIndex).first); setTradeItem( i, m_activeOffers.at(offerIndex).first->getSellItem()); } else { setTradeItem(i, nullptr); } setTradeRedBox(i, showRedBox); } int selectedShopItem = (m_selectedSlot + m_offersStartIndex); if (selectedShopItem < m_activeOffers.size()) { MerchantRecipe* activeRecipe = m_activeOffers.at(selectedShopItem).first; std::wstring wsTemp; // 4J-PB - need to get the villager type here wsTemp = app.GetString(IDS_VILLAGER_OFFERS_ITEM); wsTemp = replaceAll(wsTemp, L"{*VILLAGER_TYPE*}", m_merchant->getDisplayName()); int iPos = wsTemp.find(L"%s"); wsTemp.replace(iPos, 2, activeRecipe->getSellItem()->getHoverName()); setTitle(wsTemp.c_str()); std::vector* offerDescription = GetItemDescription(activeRecipe->getSellItem()); setOfferDescription(offerDescription); std::shared_ptr buyAItem = activeRecipe->getBuyAItem(); std::shared_ptr buyBItem = activeRecipe->getBuyBItem(); setRequest1Item(buyAItem); setRequest2Item(buyBItem); if (buyAItem != NULL) setRequest1Name(buyAItem->getHoverName()); else setRequest1Name(L""); if (buyBItem != NULL) setRequest2Name(buyBItem->getHoverName()); else setRequest2Name(L""); bool canMake = true; std::shared_ptr player = Minecraft::GetInstance()->localplayers[getPad()]; int buyAMatches = player->inventory->countMatches(buyAItem); if (buyAMatches > 0) { setRequest1RedBox(buyAMatches < buyAItem->count); canMake = buyAMatches > buyAItem->count; } else { setRequest1RedBox(true); canMake = false; } int buyBMatches = player->inventory->countMatches(buyBItem); if (buyBMatches > 0) { setRequest2RedBox(buyBMatches < buyBItem->count); canMake = canMake && buyBMatches > buyBItem->count; } else { if (buyBItem != NULL) { setRequest2RedBox(true); canMake = false; } else { setRequest2RedBox(buyBItem != NULL); canMake = canMake && buyBItem == NULL; } } if (canMake) iA = IDS_TOOLTIPS_TRADE; } else { setTitle(m_merchant->getDisplayName()); setRequest1Name(L""); setRequest2Name(L""); setRequest1RedBox(false); setRequest2RedBox(false); setRequest1Item(nullptr); setRequest2Item(nullptr); std::vector offerDescription; setOfferDescription(&offerDescription); } m_bHasUpdatedOnce = true; } ui.SetTooltips(getPad(), iA, IDS_TOOLTIPS_EXIT); } bool IUIScene_TradingMenu::canMake(MerchantRecipe* recipe) { bool canMake = false; if (recipe != NULL) { if (recipe->isDeprecated()) return false; std::shared_ptr buyAItem = recipe->getBuyAItem(); std::shared_ptr buyBItem = recipe->getBuyBItem(); std::shared_ptr player = Minecraft::GetInstance()->localplayers[getPad()]; int buyAMatches = player->inventory->countMatches(buyAItem); if (buyAMatches > 0) { canMake = buyAMatches >= buyAItem->count; } else { canMake = buyAItem == NULL; } int buyBMatches = player->inventory->countMatches(buyBItem); if (buyBMatches > 0) { canMake = canMake && buyBMatches >= buyBItem->count; } else { canMake = canMake && buyBItem == NULL; } } return canMake; } void IUIScene_TradingMenu::setRequest1Item(std::shared_ptr item) { } void IUIScene_TradingMenu::setRequest2Item(std::shared_ptr item) { } void IUIScene_TradingMenu::setTradeItem(int index, std::shared_ptr item) {} std::vector* IUIScene_TradingMenu::GetItemDescription( std::shared_ptr item) { std::vector* lines = item->getHoverText(nullptr, false); // Add rarity to first line if (lines->size() > 0) { lines->at(0).color = item->getRarity()->color; } return lines; } void IUIScene_TradingMenu::HandleInventoryUpdated() { updateDisplay(); }