Dailies By web crawler 334 installs Rating 0.0 (0) approved

Neopets - Wishing Well Auto-Wisher

Automatically makes wishes at wishing well (supports cycling through a list of items)
auto-wisher neopets wishing well
https://www.scriptneo.com/script/neopets-wishing-well-auto-wisher

Version selector


SHA256
2db2016f8f15b448f43081cd8d23be814a8cd3513dda5ac3121765bed7067220
No scan flags on this version.

Source code

// ==UserScript==
// @name         Neopets - Wishing Well Auto-Wisher
// @namespace    https://www.scriptneo.com/
// @license      GPL3
// @version      0.0.2
// @description  Automatically makes wishes at wishing well (supports cycling through a list of items)
// @author       Karla (edited)
// @match        *://*.neopets.com/wishing.phtml*
// @grant        GM_setValue
// @grant        GM_getValue
// @downloadURL  https://www.scriptneo.com/scripts/download.php?id=11
// @updateURL    https://www.scriptneo.com/scripts/download.php?id=11
// ==/UserScript==

let item = GM_getValue("item") || ""; // kept for backward compatibility
let items_text = GM_getValue("items_text") || item || "";
let item_index = parseInt(GM_getValue("item_index") || "0", 10);
let np = GM_getValue("np") || "21";
let auto = GM_getValue("auto_ww") || false;

const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));

const random_in_range = (start, end) => {
  return Math.floor(Math.random() * (end - start + 1) + start);
};

function parse_items(text) {
  const lines = (text || "")
    .split(/\r?\n/)
    .map((s) => s.trim())
    .filter(Boolean);

  const items = [];
  for (const line of lines) {
    // Support: "Item Name x3" or "Item Name * 3"
    const m = line.match(/^(.*?)(?:\s*[x\*]\s*(\d+))?\s*$/i);
    if (!m) continue;

    const name = (m[1] || "").trim();
    if (!name) continue;

    const qty = m[2] ? Math.max(1, parseInt(m[2], 10) || 1) : 1;
    for (let i = 0; i < qty; i++) items.push(name);
  }
  return items;
}

function get_current_item_and_advance() {
  const list = parse_items(items_text);

  if (list.length === 0) return { chosen: "", list_len: 0 };

  if (!Number.isFinite(item_index) || item_index < 0) item_index = 0;
  if (item_index >= list.length) item_index = 0;

  const chosen = list[item_index];

  item_index = (item_index + 1) % list.length;
  GM_setValue("item_index", String(item_index));

  return { chosen, list_len: list.length };
}

async function makeWish() {
  const match = document.body.innerHTML.match(/Wish Count:\s*(\d+)/);
  if (match) {
    const wishCount = parseInt(match[1], 10);
    console.log(`Making wish ${wishCount + 1}`);
  } else if (document.body.innerHTML.includes("Thanks for your donation")) {
    console.log("Wish done");
    return;
  } else {
    console.log("Making wish 1");
  }

  const donationInput = document.querySelector('[name="donation"]');
  const wishInput = document.querySelector('[name="wish"]');
  const wishButton = document.querySelector('[value="Make a Wish"]');

  if (!donationInput || !wishInput || !wishButton) {
    console.log("Wishing Well inputs not found on this page.");
    return;
  }

  const picked = get_current_item_and_advance();
  if (!picked.chosen) {
    console.log("No items in list. Add at least 1 item to the textarea.");
    return;
  }

  await sleep(random_in_range(500, 900));
  donationInput.value = np;

  await sleep(random_in_range(500, 900));
  wishInput.value = picked.chosen;

  console.log(`Wishing with: "${picked.chosen}" (list size: ${picked.list_len})`);

  await sleep(random_in_range(500, 900));
  wishButton.click();
}

(function () {
  "use strict";

  try {
    const div = document.createElement("div");
    div.style.marginTop = "20px";
    div.innerHTML = `
      <div>-- Wishing Well Auto Wisher --</div>
      <small>Enter one item per line. Optional: "xN" or "* N" to repeat an item.</small>
      <br/><br/>
      <label style="display:block; margin-bottom:6px;">Items list:</label>
      <textarea id="k-items" rows="6" style="width: 320px; max-width: 100%;" ${auto ? "disabled" : ""}></textarea>
      <div style="margin-top:8px; display:flex; gap:10px; align-items:center; flex-wrap:wrap;">
        <label>Np: <input id="k-np" type="number" min="21" ${auto ? "disabled" : ""} style="width: 90px;" /></label>
        <button id="k-toggle">${auto ? "Stop" : "Start"}</button>
        <button id="k-reset" type="button" ${auto ? "disabled" : ""}>Reset cycle</button>
      </div>
      <div style="margin-top:6px; font-size: 12px; opacity: 0.9;">
        <span id="k-status"></span>
      </div>
    `;

    const itemsArea = div.querySelector("#k-items");
    const npInput = div.querySelector("#k-np");
    const startButton = div.querySelector("#k-toggle");
    const resetButton = div.querySelector("#k-reset");
    const status = div.querySelector("#k-status");

    function refreshStatus() {
      const list = parse_items(items_text);
      const idx = Number.isFinite(item_index) ? item_index : 0;
      if (list.length === 0) {
        status.textContent = "Status: add items above to enable wishing.";
        return;
      }
      const nextIdx = idx >= list.length ? 0 : idx;
      status.textContent = `Status: ${list.length} item(s) in cycle. Next up: "${list[nextIdx]}" (position ${nextIdx + 1}/${list.length}).`;
    }

    itemsArea.value = items_text;
    itemsArea.addEventListener("input", function (event) {
      items_text = event.target.value || "";
      GM_setValue("items_text", items_text);

      // keep old single-item key in sync with first valid line for compatibility
      const list = parse_items(items_text);
      item = list[0] || "";
      GM_setValue("item", item);

      // if index is out of bounds after edits, clamp
      if (item_index >= list.length) {
        item_index = 0;
        GM_setValue("item_index", "0");
      }
      refreshStatus();
    });

    npInput.value = np;
    npInput.addEventListener("change", function (event) {
      np = event.target.value;
      GM_setValue("np", np);
    });

    resetButton.addEventListener("click", function () {
      item_index = 0;
      GM_setValue("item_index", "0");
      refreshStatus();
    });

    startButton.addEventListener("click", function () {
      auto = !auto;
      GM_setValue("auto_ww", auto);

      if (auto) {
        startButton.textContent = "Stop";
        itemsArea.disabled = true;
        npInput.disabled = true;
        resetButton.disabled = true;
        refreshStatus();
        makeWish();
      } else {
        startButton.textContent = "Start";
        itemsArea.removeAttribute("disabled");
        npInput.removeAttribute("disabled");
        resetButton.removeAttribute("disabled");
        refreshStatus();
      }
    });

    const anchorImg = document.querySelector('[src="//images.neopets.com/images/wishingwell.gif"]');
    const anchor = anchorImg ? anchorImg.parentNode : null;
    if (anchor) {
      anchor.append(div);
    } else {
      // fallback if Neopets changes the page
      document.body.append(div);
    }

    refreshStatus();

    if (auto) {
      makeWish();
    }
  } catch (e) {
    console.log(e);
  }
})();