// ==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();
})();