'use strict'; const {sleep} = require('../../utils'); const botSlots = [0, 1, 2, 3, 9, 10, 11, 12, 18, 19, 20, 21]; const customerSlots = [5, 6, 7, 8, 14, 15, 16, 17, 23, 24, 25, 26]; function findChestBySign(bot, text){ let sign = bot.bot.findBlock({ useExtraInfo: true, // maxDistance: 1, matching: (block)=> { if(block.name.includes('sign') && block.signText.includes(text)){ return true; } } }); return bot.bot.findBlock({ point: sign.position, // maxDistance: 1, useExtraInfo: true, matching: block => block.name === 'chest' }); } module.exports = { '.trade': { desc: 'Bot will take trade requests', async function(from){ /* todo * Do... something if the users chest is full */ // Make the user has a chest then can add too. let chestBlock = findChestBySign(this, from); if(!chestBlock) return this.whisper(from, `You aren't allowed to trade with me...`); await this.say('/trade accept'); let window = await this.once('windowOpen'); // If the process is taking to long, just stop let timeoutCheck = setTimeout(()=>{ this.bot.closeWindow('window'); this.bot.removeAllListeners('windowOpen'); this.whisper(from, `I have things to do, I cant wait on you all day!`) }, 30000); // Check to see if the remote user has agreed to the trade. let confirmationCheck = setInterval(async ()=>{ if(window.containerItems().filter(item => item?.slot == 53)[0].name == 'lime_dye'){ this.bot.moveSlotItem(37, 37); } }, 500); // Clean up when the trade is done await this.once('windowClose'); clearInterval(confirmationCheck); // If the trade took so long it timed out, just kill the whole thing. if(timeoutCheck._destroyed) return; clearTimeout(timeoutCheck) // Give MC a moment await sleep(1000); let isPutAway = await this.dumpToChest(chestBlock) await this.whisper(from, `I put ${isPutAway ? 'all' : 'some'} items in your chest.`); } } } /* const { countCustomerPayment } = require('../parts/countCustomerPayment.js'); const { getCustomerItems } = require('../parts/getCustomerItems.js'); const { findContainerItem } = require('../parts/findContainerItem.js'); const { minecraftBot } = require('../../../modules/minecraftBot.js'); const mcData = require('minecraft-data')(minecraftBot.version); const { once } = require('../../../functions/once.js'); const { timeOut } = require('../../../functions/timeOut.js'); const { toMinecraftChat } = require('../../../functions/toMinecraftChat.js'); const { findOrCreateBankItemWithRelation } = require('../../bank/parts/findOrCreateBankItemWithRelations.js'); const { toDiscordChat } = require('../../../functions/toDiscordChat.js'); let checkCustomerFirstConfirmInterval; let checkCustomerSecondConfirmInterval; let putItemInterval; let firstTimeout; let secondTimeout; let windowOpened; let timedOut; let isFinished; const firstTimeoutDelay = 30000; const secondTimeoutDelay = 20000; function CJTradeRequest(targetPlayer, itemToGive, itemToGiveAmount, itemToReceive, itemToReceiveAmount) { windowOpened = false; isFinished = false; timedOut = false; // Item that is not the currency. let fullItemName = itemToGive.nameWithTradeName ?? itemToReceive.nameWithTradeName; let itemAmount = itemToGive.nameWithTradeName ? itemToGiveAmount : itemToReceiveAmount; let tradePromise = new Promise((resolve, reject) => { console.log("trade request started"); minecraftBot.chat(`/trade ${targetPlayer}`); minecraftBot.once('windowOpen', async (window) => { windowOpened = true; if (timedOut == true) { return; } console.log("trade window opened"); // List of items in inventory let windowInventoryItems = window.items(); function windowInventoryItemsCount() { let inventoryItemCount = 0; for (let item of windowInventoryItems) { if (item.name == itemToGive.item_name) { inventoryItemCount += parseInt(item.count); } } return inventoryItemCount; } console.log("inventory item count: " + windowInventoryItemsCount()); // If itemToGive is diamond round down to whole number and pay difference in diamondBank let roundingDifference = 0; if (itemToGive.item_name == "diamond" && itemToGive.isToken == false) { let itemToGiveAmountUnrounded = itemToGiveAmount; itemToGiveAmount = Math.floor(itemToGiveAmount); roundingDifference = itemToGiveAmountUnrounded - itemToGiveAmount; } let takeItemDelay = 50; let i = 0; let currentSlotAmount = 0; let movedAmount = 0; let itemToMove; let amountLeft; let putItemInTrade = async () => { itemToMove = await findContainerItem(window.items(), itemToGive, itemToGive.itemEnchants); // amountLeft is the amount of items left to move amountLeft = itemToGiveAmount - movedAmount; if (itemToMove !== null) { // Move entire slot if is less than whats left if (amountLeft >= itemToMove.count) { amountToMove = itemToMove.count console.log("amount to move is all items in inv slot, amount: ", amountToMove); } // Move only specific amount of slot if slot itemToMove count is more than whats left else if (amountLeft < itemToMove.count) { amountToMove = amountLeft; console.log("amount to move is less than in the slot, amount: ", amountToMove); } // Move stack size if amountToMove is bigger than a stack if (currentSlotAmount + amountToMove > itemToGive.stackSize) { amountToMove = itemToGive.stackSize - currentSlotAmount; console.log("total amount of slot will be more than stack size, updated amount: ", amountToMove); } } if (itemToGiveAmount > movedAmount) { itemSlot = itemToMove.slot; let options = { itemType: itemToGive.mcId, destStart: botSlots[i], // destEnd is until (excluding itself) destEnd: botSlots[i] + 1, sourceStart: itemSlot, sourceEnd: itemSlot + 1, count: amountToMove, } currentSlotAmount += amountToMove; minecraftBot.transfer(options) movedAmount = parseInt(movedAmount + amountToMove); console.log(" amountToMove / movedAmount / total needed amount", amountToMove, movedAmount, amount); console.log("current slot amount / stack size", currentSlotAmount, itemToGive.stackSize); if (currentSlotAmount >= itemToGive.stackSize) { console.log("1 slot up!"); i++; currentSlotAmount = 0; } } if (itemToGiveAmount == movedAmount) { clearInterval(putItemInterval); //do first confirm setTimeout(() => { minecraftBot.moveSlotItem(37, 37); }, 70); } } // Start putting items in trade window. console.log("give token: ", itemToGive.isToken) if (itemToGive.isToken == false) { putItemInterval = setInterval(putItemInTrade, takeItemDelay); } // If token transaction do not put item in trade window and press first confirm. else if (itemToGive.isToken == true) { setTimeout(() => { minecraftBot.moveSlotItem(37, 37); }, 70); } let missingDiamonds = null; let missingDiamondsRounded = null; let windowItems; let paymentCount; let bankItem; let validateTrade = async () => { windowItems = window.containerItems(); paymentCount = await countCustomerPayment(windowItems, itemToReceive, itemToReceive.itemEnchants); // Check if payment amount is less than required amount if (paymentCount < itemToReceiveAmount) { if (itemToReceive.item_name == "diamond") { missingDiamonds = itemToReceiveAmount - paymentCount; missingDiamondsRounded = Math.round(missingDiamonds * 100) / 100; // Check if it has the missing diamonds in bank bankItem = await findOrCreateBankItemWithRelation(targetPlayer) if (bankItem.balance < missingDiamonds) { toMinecraftChat(targetPlayer, "You did not pay enough, and not enough in bank!"); minecraftBot.closeWindow(window); return reject("Not enough paid and not enough in bank."); } } else { toMinecraftChat(targetPlayer, "You did not pay enough of the item!"); minecraftBot.closeWindow(window); return reject("not enough paid"); } } // Check for illegal items for (let windowItem of windowItems) { // Item is named with anvil and bigger stack size than 1 let itemNickJson = windowItem?.nbt?.value?.display?.value?.Name?.value let itemNick = itemNickJson ? JSON.parse(itemNickJson).text : null; if (itemNick) { let itemStackSize = mcData.itemsByName[windowItem.name].stackSize; if (itemStackSize > 1) { toMinecraftChat(targetPlayer, "Only items with stack size of 1 may be named!"); minecraftBot.closeWindow(window); return reject("named item"); } } // Item is is a map if (windowItem.name == "filled_map") { toMinecraftChat(targetPlayer, "You put an illegal piece of junk in trade window."); minecraftBot.closeWindow(window); return reject(`Illegal item "filled_map" in trade window.`); } } } let customerConfirmItem; let checkCustomerFirstConfirm = async () => { customerConfirmItem = window.containerItems().filter(item => item?.slot == 53); if (window.findContainerItem("magenta_dye") !== null && customerConfirmItem[0]?.name == "magenta_dye") { clearInterval(checkCustomerFirstConfirmInterval); await validateTrade(); checkCustomerSecondConfirmInterval = setInterval(checkCustomerSecondConfirm, secondConfirmIntervalDelay); } } let checkCustomerSecondConfirm = async () => { console.log("checkCustomerSecondConfirm"); // Check if item in slot 54 is lime dye customerConfirmItem = window.containerItems().filter(item => item?.slot == 53); if (window.findContainerItem("lime_dye") != null && customerConfirmItem[0]?.name == "lime_dye") { console.log("customer did second confirm"); clearInterval(checkCustomerSecondConfirmInterval); await validateTrade(); bankItem = await findOrCreateBankItemWithRelation(targetPlayer) // Buy: if (itemToReceive.item_name == "diamond") { if (bankItem.balance >= missingDiamonds && missingDiamonds != null) { bankItem.balance -= missingDiamonds; bankItem.save(); toMinecraftChat(targetPlayer, `You paid ${missingDiamondsRounded} diamonds from your bulba bank account!`); toDiscordChat(`Paid ${missingDiamondsRounded} diamond token and ${itemToReceiveAmount - missingDiamonds} diamond.`); } // Add overpaid diamonds to bank else if (paymentCount > itemToReceiveAmount) { let overpaidDiamonds = paymentCount - itemToReceiveAmount; let overpaidDiamondsRounded = Math.round(overpaidDiamonds * 100) / 100; bankItem.balance += overpaidDiamonds; bankItem.save(); toMinecraftChat(targetPlayer, `You overpaid ${overpaidDiamondsRounded} diamond. It has been added to your bulba bank account!`); toDiscordChat(`Overpaid ${overpaidDiamondsRounded} diamond.`); } } // Sell: Give all diamonds in tokens to customer else if (itemToGive.item_name == "diamond" && itemToGive.isToken == true) { console.log("Gave all currency/item in tokens to customer."); bankItem.balance += itemToGiveAmount; bankItem.save(); } // Sell: Give rounding difference to customer else if (itemToGive.item_name == "diamond" && roundingDifference > 0) { console.log("Gave rounding difference to customer."); bankItem.balance += roundingDifference; bankItem.save(); } console.log("payment: ", paymentCount); let customerItems = getCustomerItems(windowItems); minecraftBot.moveSlotItem(37, 37); once('windowClose').then(() => { return resolve(customerItems); }); } }; // Check for secondConfirm every 0.05 seconds until trade closes let secondConfirmIntervalDelay = 50; checkCustomerFirstConfirmInterval = setInterval(checkCustomerFirstConfirm, secondConfirmIntervalDelay); // Delay because when trade succesfull it closes too await once('windowClose'); await timeOut(1000); return reject("Trade window closed."); }); // 30 seconds timeout add 20 seconds if in trade window firstTimeout = setTimeout(() => { console.log("timeout!!"); if (isFinished == true) { return; } else if (windowOpened == false) { toMinecraftChat(targetPlayer, `Trade request timed out. If you only want to check the price please use "price ${fullItemName} ${itemAmount}" instead.`); minecraftBot.removeAllListeners('windowOpen'); timedOut = true; return reject("timed out"); } else { //if in trade window secondTimeout = setTimeout(() => { console.log("second timeout!!"); if (windowOpened == true && timedOut == false) { toMinecraftChat(targetPlayer, "Trade request timed out."); minecraftBot.removeAllListeners('windowOpen'); return reject("timed out in trade window"); } }, secondTimeoutDelay); } }, firstTimeoutDelay); }); tradePromise .then(() => { clearInterval(checkCustomerFirstConfirmInterval); clearInterval(checkCustomerSecondConfirmInterval); clearInterval(putItemInterval); clearTimeout(firstTimeout); clearTimeout(secondTimeout); isFinished = true; }) .catch((err) => { clearInterval(checkCustomerFirstConfirmInterval); clearInterval(checkCustomerSecondConfirmInterval); clearInterval(putItemInterval); clearTimeout(firstTimeout); clearTimeout(secondTimeout); isFinished = true; }); return tradePromise; } module.exports = { CJTradeRequest };*/