// ==UserScript== // @name Bulk Offer Helper // @namespace http://tampermonkey.net/ // @version 1.2 // @description Oferta itens por nome/quantidade/preço para o personagem da página atual. // @author Popper para Roque // @match *://*.popmundo.com/World/Popmundo.aspx/Character/OfferItem/* // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @run-at document-idle // @downloadURL none // ==/UserScript== (function() { 'use strict'; // --- CONFIGURAÇÃO --- const ITEM_DROPDOWN_SELECTOR = '#ctl00_cphLeftColumn_ctl00_ddlItem'; const OFFER_BUTTON_SELECTOR = '#ctl00_cphLeftColumn_ctl00_btnGive'; const PRICE_INPUT_SELECTOR = '#ctl00_cphLeftColumn_ctl00_txtPriceTag'; // Seletor do campo de preço ORIGINAL da página const BASE_DELAY_MS = 2000; // Atraso principal entre ofertas const POST_PRICE_SET_DELAY_MS = 100; // Pequeno atraso após definir o preço (ms) const STORAGE_KEY_ITEMS = 'popmundo_offerItem_items_swqp'; const STORAGE_KEY_RUNNING = 'popmundo_offerItem_running_swqp'; // --- FIM DA CONFIGURAÇÃO --- let itemDropdown = document.querySelector(ITEM_DROPDOWN_SELECTOR); let offerButton = document.querySelector(OFFER_BUTTON_SELECTOR); let pagePriceInput = document.querySelector(PRICE_INPUT_SELECTOR); if (!itemDropdown) { console.warn("Script Popmundo AdvOffer: Dropdown não encontrado:", ITEM_DROPDOWN_SELECTOR); return; } if (!offerButton) { console.warn("Script Popmundo AdvOffer: Botão Ofertar não encontrado:", OFFER_BUTTON_SELECTOR); } if (!pagePriceInput) { console.warn("Script Popmundo AdvOffer: Campo de Preço da página não encontrado:", PRICE_INPUT_SELECTOR, "- O preço não será definido."); } function createUI() { if (document.getElementById('bulkOfferUIScript')) return; const scriptUIArea = document.createElement('div'); scriptUIArea.id = 'bulkOfferUIScript'; scriptUIArea.innerHTML = `



Status: Pronto.
`; itemDropdown.parentNode.insertBefore(scriptUIArea, itemDropdown); document.getElementById('startOfferByNameQtyPriceBtnScript').addEventListener('click', startOfferByNameQuantityPrice); document.getElementById('stopBulkOfferBtnScript').addEventListener('click', stopOffer); GM_addStyle(`#itemNameInputScript, #itemQuantityInputScript, #itemPriceInputScript { border: 1px solid #ccc; border-radius: 3px; box-sizing: border-box; }`); } async function startOfferByNameQuantityPrice() { const itemNameInput = document.getElementById('itemNameInputScript'); const quantityInput = document.getElementById('itemQuantityInputScript'); const priceInput = document.getElementById('itemPriceInputScript'); const statusDiv = document.getElementById('bulkOfferStatusScript'); const inputText = itemNameInput.value.trim(); const requestedQuantity = parseInt(quantityInput.value, 10); const requestedPrice = parseInt(priceInput.value, 10); itemDropdown = document.querySelector(ITEM_DROPDOWN_SELECTOR); offerButton = document.querySelector(OFFER_BUTTON_SELECTOR); pagePriceInput = document.querySelector(PRICE_INPUT_SELECTOR); if (!itemDropdown || !offerButton) { statusDiv.textContent = "Erro Crítico: Elementos não encontrados."; console.error("StartOfferSWQP: Elementos não encontrados."); return; } if (!inputText) { statusDiv.textContent = "Erro: Digite o início do nome."; itemNameInput.focus(); return; } if (isNaN(requestedQuantity) || requestedQuantity < 1) { statusDiv.textContent = "Erro: Quantidade inválida."; quantityInput.focus(); return; } if (isNaN(requestedPrice) || requestedPrice < 0) { statusDiv.textContent = "Erro: Preço inválido."; priceInput.focus(); return; } if (!pagePriceInput && requestedPrice > 0) { statusDiv.textContent = "Aviso: Campo de preço da página não encontrado."; console.warn("Campo de preço da página não encontrado."); } const allItemsFound = []; const inputTextLower = inputText.toLowerCase(); console.log(`Buscando itens começando com "${inputText}" para ofertar ${requestedQuantity} por ${requestedPrice} M$ cada.`); for (let option of itemDropdown.options) { if (option.value && option.value !== "-1" && option.textContent.trim().toLowerCase().startsWith(inputTextLower)) { allItemsFound.push({ value: option.value, text: option.textContent.trim() }); } } if (allItemsFound.length === 0) { statusDiv.textContent = `Status: Nenhum item encontrado começando com "${inputText}".`; console.log("Nenhum item correspondente."); return; } const actualQuantityToTransfer = Math.min(allItemsFound.length, requestedQuantity); const itemsToOfferThisRun = allItemsFound.slice(0, actualQuantityToTransfer); let startMessage = `Encontrado(s) ${allItemsFound.length}. `; startMessage += `Ofertando ${itemsToOfferThisRun.length} por ${requestedPrice} M$...`; statusDiv.textContent = startMessage; console.log(`Itens para esta execução (${itemsToOfferThisRun.length}):`, itemsToOfferThisRun); // Salvar também o preço alvo para que seja consistente entre reloads await GM_setValue('popmundo_offerItem_targetPrice', requestedPrice); await GM_setValue(STORAGE_KEY_ITEMS, JSON.stringify(itemsToOfferThisRun)); await GM_setValue(STORAGE_KEY_RUNNING, true); disableButtons(true); await processNextOffer(); } async function stopOffer() { console.log("StopOffer (SWQP) chamada!"); const statusDiv = document.getElementById('bulkOfferStatusScript'); await GM_deleteValue(STORAGE_KEY_ITEMS); await GM_deleteValue(STORAGE_KEY_RUNNING); await GM_deleteValue('popmundo_offerItem_targetPrice'); // Limpa preço alvo também if (statusDiv) { statusDiv.textContent = "Status: Oferta interrompida pelo usuário."; } console.log("Oferta em massa (SWQP) interrompida. Flags, lista e preço limpos."); disableButtons(false); } function disableButtons(disabled) { const startBtn = document.getElementById('startOfferByNameQtyPriceBtnScript'); const stopBtn = document.getElementById('stopBulkOfferBtnScript'); const nameInput = document.getElementById('itemNameInputScript'); const quantityInput = document.getElementById('itemQuantityInputScript'); const priceInput = document.getElementById('itemPriceInputScript'); if(startBtn) startBtn.disabled = disabled; if(stopBtn) stopBtn.disabled = !disabled; if(nameInput) nameInput.disabled = disabled; if(quantityInput) quantityInput.disabled = disabled; if(priceInput) priceInput.disabled = disabled; } async function processNextOffer() { const isRunning = await GM_getValue(STORAGE_KEY_RUNNING, false); if (!isRunning) { /* ... código de parada ... */ return; } const itemsJson = await GM_getValue(STORAGE_KEY_ITEMS, '[]'); let itemsToOffer = JSON.parse(itemsJson); const statusDiv = document.getElementById('bulkOfferStatusScript'); const targetPrice = await GM_getValue('popmundo_offerItem_targetPrice', 0); // Pega preço alvo do storage if (itemsToOffer.length === 0) { /* ... código de conclusão/parada ... */ await stopOffer(); return; } if (!statusDiv) { console.error("Status UI não encontrado."); await stopOffer(); return; } itemDropdown = document.querySelector(ITEM_DROPDOWN_SELECTOR); offerButton = document.querySelector(OFFER_BUTTON_SELECTOR); pagePriceInput = document.querySelector(PRICE_INPUT_SELECTOR); // Re-seleciona if (!itemDropdown || !offerButton) { /* ... código de erro ... */ await stopOffer(); return; } const itemToOffer = itemsToOffer.shift(); // *** LÓGICA DE PREÇO ATUALIZADA *** if (pagePriceInput) { const targetPriceString = String(targetPrice); // Garante que é string para comparação e atribuição if (pagePriceInput.value !== targetPriceString) { console.log(`(SWQP) Definindo preço na página para: ${targetPriceString}`); pagePriceInput.value = targetPriceString; // Disparar eventos para tentar simular interação do usuário console.log("(SWQP) Disparando eventos 'input' e 'change' no campo de preço."); pagePriceInput.dispatchEvent(new Event('input', { bubbles: true })); pagePriceInput.dispatchEvent(new Event('change', { bubbles: true })); } } else { console.warn("(SWQP) Campo de preço da página não encontrado neste ciclo."); if (targetPrice > 0) { statusDiv.textContent = `Aviso: Não foi possível definir o preço ${targetPrice}M$.`; } } // *** FIM DA LÓGICA DE PREÇO ATUALIZADA *** // Seleciona o item (depois de tentar definir o preço) const initialListJsonForCount = await GM_getValue(STORAGE_KEY_ITEMS, '[]'); const initialTotalCount = JSON.parse(initialListJsonForCount).length + itemsToOffer.length + 1; const currentItemNumber = initialTotalCount - itemsToOffer.length; statusDiv.textContent = `Ofertando ${currentItemNumber}/${initialTotalCount}: '${itemToOffer.text}' por ${targetPrice} M$...`; console.log(`(SWQP) Preparando oferta: ${itemToOffer.text} (ID: ${itemToOffer.value}) por ${targetPrice} M$`); itemDropdown.value = itemToOffer.value; // Valida seleção do item const selectedOptionText = itemDropdown.options[itemDropdown.selectedIndex]?.textContent; if (itemDropdown.value !== itemToOffer.value || (selectedOptionText && selectedOptionText.trim() !== itemToOffer.text)) { statusDiv.textContent = `Erro: Não selecionou '${itemToOffer.text}' corretamente. Pulando...`; console.warn(`(SWQP) Falha ao selecionar item ${itemToOffer.value}. Pulando.`); await GM_setValue(STORAGE_KEY_ITEMS, JSON.stringify(itemsToOffer)); setTimeout(processNextOffer, BASE_DELAY_MS / 2); return; } // Salva lista restante await GM_setValue(STORAGE_KEY_ITEMS, JSON.stringify(itemsToOffer)); // *** ATRASO ANTES DO CLIQUE *** console.log(`(SWQP) Aguardando ${POST_PRICE_SET_DELAY_MS}ms após definir campos...`); await new Promise(resolve => setTimeout(resolve, POST_PRICE_SET_DELAY_MS)); // Atraso principal (opcional aqui, pode ser combinado com o acima ou removido se POST_PRICE_SET_DELAY_MS for suficiente) console.log(`(SWQP) Aguardando ${BASE_DELAY_MS}ms antes do clique final...`); await new Promise(resolve => setTimeout(resolve, BASE_DELAY_MS)); console.log("(SWQP) Clicando 'Ofertar item'..."); offerButton.click(); } async function checkOfferStateOnLoad() { createUI(); const statusDiv = document.getElementById('bulkOfferStatusScript'); const isRunning = await GM_getValue(STORAGE_KEY_RUNNING, false); const itemsPendingJson = await GM_getValue(STORAGE_KEY_ITEMS, '[]'); if (isRunning && itemsPendingJson !== '[]' && statusDiv) { console.log("(SWQP) Script recarregado, continuando oferta."); disableButtons(true); await processNextOffer(); } else { console.log("(SWQP) Nenhuma oferta em andamento ou lista vazia."); if (isRunning) { console.log("(SWQP) Flag 'running' encontrada, mas lista vazia. Limpando."); await stopOffer(); } else if (statusDiv) { disableButtons(false); statusDiv.textContent = "Status: Pronto."; } } } checkOfferStateOnLoad(); })();