Silver-Pexer 2

XP automatique sur le jeu Silver-World

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Silver-Pexer 2
// @namespace    https://silver-world.net/?silver-pexer
// @version      1.3
// @description  XP automatique sur le jeu Silver-World
// @author       Goodq
// @match        https://silver-world.net/*
// @icon         https://www.google.com/s2/favicons?domain=silver-world.net
// @grant        none
// @license      GNU GPLv3
// ==/UserScript==

"use strict";

// src/utils/doThenWait.ts
function doThenWait(action, until) {
  return new Promise((resolve, reject) => {
    try {
      action();
    } catch (e) {
      reject(e);
    }
    const interval = setInterval(() => {
      if (until()) {
        clearInterval(interval);
        resolve();
      }
    }, config.waitInterval);
    setTimeout(() => {
      clearInterval(interval);
      reject(new Error("waitUntilTextUpdated timeout"));
    }, config.waitTimeout);
  });
}

// src/utils/silverPexerSettings.ts
var Skills = /* @__PURE__ */ ((Skills2) => {
  Skills2["constitution"] = "constitution";
  Skills2["force"] = "force";
  Skills2["agilite"] = "agilite";
  Skills2["intelligence"] = "intelligence";
  return Skills2;
})(Skills || {});
var Shortcuts = {
  first: "0",
  second: "1",
  third: "2"
};
var SILVER_PEXER_SETTINGS_KEY = "silver-pexer-settings";
function setItem(key, value) {
  const settings = JSON.parse(localStorage.getItem(SILVER_PEXER_SETTINGS_KEY) ?? "{}");
  const newSettings = { ...settings };
  newSettings[key] = value;
  localStorage.setItem(SILVER_PEXER_SETTINGS_KEY, JSON.stringify(newSettings));
}
function getItem(key) {
  const existingSettings = JSON.parse(localStorage.getItem("silver-pexer-settings") ?? "{}");
  return existingSettings[key];
}
function setLevelUp(skill, value) {
  const levelUp = getItem("levelUp");
  const newLevelUp = { ...levelUp };
  newLevelUp[skill] = value;
  const sum = Object.values(newLevelUp).reduce((partialSum, s) => partialSum + +s, 0);
  if (sum > 5) {
    throw new Error("sum cannot be over 5");
  }
  setItem("levelUp", newLevelUp);
}
function getLevelUp(skill) {
  const levelUp = getItem("levelUp");
  return levelUp?.[skill];
}
function addMonsterOption(monsterOption) {
  const monsterOptions = getItem("monsterOptions") ?? [];
  const newMonsterOptions = [...monsterOptions.filter((mo) => mo.name !== monsterOption.name), monsterOption];
  setItem("monsterOptions", newMonsterOptions);
}
var SilverPexerSettings = {
  setItem,
  getItem,
  setLevelUp,
  getLevelUp,
  addMonsterOption
};

// src/plugins/autoAttack.ts
async function apply() {
  const monsterToAttack = SilverPexerSettings.getItem("monster");
  const attackWith = SilverPexerSettings.getItem("attack");
  if (!monsterToAttack || !attackWith) {
    return;
  }
  const paElement = document.querySelector(".label-pa");
  const paMatches = paElement.innerText.match(/[0-9]+/);
  if (paMatches) {
    const minPa = SilverPexerSettings.getItem("minPa") ?? config.minPa;
    if (+paMatches[0] <= +minPa) {
      return;
    }
  }
  const monsters = Array.from(document.querySelectorAll(".monster-card") ?? []);
  const monster = monsters.find((m) => m.innerHTML.includes(monsterToAttack));
  if (monster) {
    const rapidAttackButton = monster.querySelector(`img[src$="${attackWith}"]`);
    const initialHtml = monster.innerHTML;
    const monsterKilledOrInjured = () => !document.body.contains(monster) || initialHtml !== monster.innerHTML;
    monster.style.opacity = "0.8";
    await doThenWait(() => rapidAttackButton.click(), () => monsterKilledOrInjured());
    monster.style.opacity = "1";
  }
}
var autoAttack = {
  name: "auto-attack",
  apply,
  loop: true
};

// src/utils/sleep.ts
function sleep(milliseconds) {
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
}

// src/plugins/autoHeal.ts
async function apply2() {
  const lifeGauge = document.querySelector(".carac-gauge > .life");
  if (!lifeGauge) {
    return;
  }
  const lifePercentText = lifeGauge.style.width;
  const groups = lifePercentText.match(/^([0-9]+)(.[0-9]+)?%$/);
  if (!groups) {
    return;
  }
  const lifePercent = +groups[1];
  if (lifePercent < 100) {
    const healIndex = +(SilverPexerSettings.getItem("heal") ?? NaN);
    if (isNaN(healIndex)) {
      return;
    }
    const quickShortcuts = document.querySelectorAll(".character-details .label-name a > img");
    const healShortcut = quickShortcuts[healIndex];
    healShortcut.click();
    await sleep(100);
  }
}
var autoHeal = {
  name: "auto-heal",
  apply: apply2,
  loop: true
};

// src/plugins/autoLevelUp.ts
var skillsMap = {
  ["constitution" /* constitution */]: "constitution" /* constitution */,
  ["force" /* force */]: "puissance",
  ["agilite" /* agilite */]: "agilite" /* agilite */,
  ["intelligence" /* intelligence */]: "intelligence" /* intelligence */
};
function apply3() {
  const levelUp = SilverPexerSettings.getItem("levelUp");
  if (!levelUp) {
    return;
  }
  let count = 0;
  for (const [key, value] of Object.entries(levelUp)) {
    const increaseButton = document.querySelector(`input.btn-success[onclick*="${skillsMap[key]}"]`);
    if (increaseButton) {
      for (let i = 0; i < +value; i++) {
        increaseButton.click();
        count++;
      }
    }
  }
  if (count === 5) {
    setTimeout(() => {
      const submitButton = document.querySelector('input[type="submit"].btn-action');
      submitButton.click();
    }, config.levelUpTimeout);
  }
}
var autoLevelUp = {
  name: "auto-levelup",
  apply: apply3
};

// src/plugins/autoLoot.ts
async function apply4() {
  const itemsOnGround = Array.from(document.querySelectorAll(".element_on_floor > img") ?? []).reverse();
  for (const item of itemsOnGround) {
    const parent = item.parentElement;
    if (!parent) {
      return;
    }
    const initialText = parent.innerText;
    const itemUpdated = () => initialText !== parent.innerText || !document.body.contains(item);
    await doThenWait(() => item.click(), itemUpdated);
  }
}
var autoLoot = {
  name: "auto-loot",
  apply: apply4,
  loop: true
};

// src/plugins/disableNotificationAnimation.ts
function apply5() {
  var style = document.createElement("style");
  style.innerHTML = `.marquee-text-text {
        -webkit-animation: none !important;
        -moz-animation: none !important;
        -o-animation: none !important;
        -ms-animation: none !important;
        animation: none !important;
    }`;
  document.head.appendChild(style);
}
var disableNotificationAnimation = {
  name: "disable-notification-animation",
  apply: apply5
};

// src/plugins/fixCharacter.ts
function apply6() {
  var style = document.createElement("style");
  style.innerHTML = `
    /* remove tabs scrolling */
    .items-container {
        overflow: visible !important;
        height: auto !important;
    }

    .item-description {
        overflow: visible !important;
        max-height: unset !important;
        min-height: 100px !important;
    }

    /* remove challenges scrolling */
    #tab-challenges > div {
        overflow: visible !important;
        height: auto !important;
    }
    `;
  document.head.appendChild(style);
}
var fixChallenges = {
  name: "fix-challenges",
  apply: apply6
};

// src/plugins/fixImagesSize.ts
function apply7() {
  var style = document.createElement("style");
  style.innerHTML = `
    img[src^="/storage/members/"] {
        max-width: 80px;
        max-height: 80px;
    }
    img[src^="/storage/items/"] {
        max-width: 70px;
        max-height: 70px;
    }
    `;
  document.head.appendChild(style);
}
var fixImagesSize = {
  name: "fix-images-size",
  apply: apply7
};

// src/plugins/fixShop.ts
function apply8() {
  var style = document.createElement("style");
  style.innerHTML = `
    #shopElements, #characterElements {
        overflow-y: visible !important;
        height: auto !important;
    }
    `;
  document.head.appendChild(style);
}
var fixShop = {
  name: "fix-shop",
  apply: apply8
};

// src/plugins/privatePlugins.ts
var privatePlugins = {
  map: [autoHeal, autoLoot, autoAttack],
  levelup: [autoLevelUp],
  guild: [],
  castle: [],
  shop: [fixImagesSize, fixShop],
  character: [fixChallenges],
  default: [disableNotificationAnimation]
};

// src/config.ts
var config = {
  minPa: "50",
  levelUpTimeout: 1500,
  loopInterval: 100,
  waitInterval: 10,
  waitTimeout: 2500,
  plugins: privatePlugins
};

// src/silverHtml.ts
var attacks = {
  attaque: "sword3.png",
  berserk: "sword4.png",
  sort1: "magic.png",
  sort2: "magic2.png"
};

// src/options/buildSelect.ts
function buildSelect(options, settingKey) {
  const select = document.createElement("select");
  select.style.maxWidth = "120px";
  const emptyOption = document.createElement("option");
  emptyOption.innerText = "-";
  emptyOption.value = `disable-auto-${settingKey}`;
  select.appendChild(emptyOption);
  const entries = Object.entries(options).sort();
  for (const [key, value] of entries) {
    const option = document.createElement("option");
    option.innerText = key;
    option.value = `${value}`;
    option.selected = value === SilverPexerSettings.getItem(settingKey);
    select.appendChild(option);
  }
  select.addEventListener("change", () => {
    SilverPexerSettings.setItem(settingKey, select.value);
  });
  return select;
}

// src/options/pickMonster.ts
function pickMonster() {
  let picking = true;
  const previousCursor = document.body.style.cursor;
  document.body.style.cursor = "crosshair";
  const monsters = Array.from(document.querySelectorAll(".monster"));
  for (const monster of monsters) {
    const bg = monster.style.backgroundColor;
    monster.addEventListener("mouseover", () => {
      if (!picking)
        return;
      monster.style.backgroundColor = "rgba(255, 255, 255, .3)";
    });
    monster.addEventListener("mouseout", () => {
      if (!picking)
        return;
      monster.style.backgroundColor = bg;
    });
    monster.addEventListener("click", (e) => {
      if (!picking)
        return;
      monster.style.backgroundColor = bg;
      const name = monster.innerText;
      const image = monster.querySelector("a > .img_container > img")?.getAttribute("src");
      if (!image) {
        alert(`Error monster without image: ${name}`);
      } else {
        SilverPexerSettings.addMonsterOption({ name, image });
        refreshAutoAttack();
      }
      picking = false;
      document.body.style.cursor = previousCursor;
      e.preventDefault();
    });
  }
}

// src/options/autoAttack.ts
function buildAutoAttackTable() {
  const autoAttackTable = document.createElement("table");
  autoAttackTable.innerHTML = `
    <tr>
        <td><label for="swp-monster-select">Monstre XP</label>&nbsp;</td>
        <td id="swp-monster"></td>
        <td>&nbsp;<a href="javascript:void(0)" id="monsters-pick">ajouter</a></td>
    </tr>
    <tr>
        <td><label for="swp-attack-select">Attaque</label>&nbsp;</td>
        <td id="swp-attack"></td>
        <td></td>
    </tr>
    <tr>
        <td><label for="swp-heal-select">Heal</label>&nbsp;</td>
        <td id="swp-heal"></td>
        <td></td>
    </tr>
    <tr>
        <td><label for="swp-minpa-input">Min PA</label>&nbsp;</td>
        <td><input id="swp-minpa-input" type="number" style="max-width: 10ch" /></td>
        <td></td>
    </tr>
    `;
  const monsterOptions = (SilverPexerSettings.getItem("monsterOptions") ?? []).reduce((accumulator, monster) => {
    return { ...accumulator, [monster.name]: monster.image };
  }, {});
  const monsterSelect = buildSelect(monsterOptions, "monster");
  monsterSelect.id = "swp-monster-select";
  autoAttackTable.querySelector("#swp-monster")?.appendChild(monsterSelect);
  const attackSelect = buildSelect(attacks, "attack");
  attackSelect.id = "swp-attack-select";
  autoAttackTable.querySelector("#swp-attack")?.appendChild(attackSelect);
  const healSelect = buildSelect(Shortcuts, "heal");
  healSelect.id = "swp-heal-select";
  autoAttackTable.querySelector("#swp-heal")?.appendChild(healSelect);
  const monsterPick = autoAttackTable.querySelector("#monsters-pick");
  monsterPick.addEventListener("click", pickMonster);
  const minPaInput = autoAttackTable.querySelector("#swp-minpa-input");
  if (minPaInput) {
    minPaInput.value = SilverPexerSettings.getItem("minPa") ?? config.minPa;
    minPaInput?.addEventListener("change", () => {
      SilverPexerSettings.setItem("minPa", minPaInput.value);
    });
  }
  return autoAttackTable;
}
function refreshAutoAttack() {
  const autoAttackTable = buildAutoAttackTable();
  document.querySelector("#swp-autoattack")?.replaceChildren(autoAttackTable);
}

// src/options/buildLevelUp.ts
function buildLevelUpTable() {
  const skills = Object.values(Skills);
  const table = document.createElement("table");
  for (const skill of skills) {
    const line = document.createElement("tr");
    line.innerHTML = `
        <td><label for="swp-level-up-${skill}-input">${skill}&nbsp;</label></td>
        <td id="swp-level-up-${skill}"></td>
        `;
    const input = document.createElement("input");
    input.id = `swp-level-up-${skill}-input`;
    input.type = "number";
    input.min = "0";
    input.max = "5";
    input.style.maxWidth = "10ch";
    input.value = SilverPexerSettings.getLevelUp(skill) ?? "0";
    input.addEventListener("change", () => {
      try {
        SilverPexerSettings.setLevelUp(skill, input.value);
      } catch (e) {
        input.value = (+input.value - 1).toString();
      }
    });
    line.querySelector(`td#swp-level-up-${skill}`)?.appendChild(input);
    table.appendChild(line);
  }
  return table;
}

// src/options/buildSettings.ts
function buildSettings() {
  const settingsDiv = document.createElement("div");
  settingsDiv.className = "card";
  settingsDiv.style.position = "absolute";
  settingsDiv.style.bottom = "57px";
  settingsDiv.style.right = "10px";
  settingsDiv.style.display = "none";
  settingsDiv.style.width = "270px";
  const settingsBody = document.createElement("div");
  settingsBody.className = "card-body";
  settingsBody.innerHTML = `
    <h5>SilverPexer Settings</h5>
    
    <h6 style="margin-top: 1em;">Auto Attack</h6>
    <div id="swp-autoattack"></div>
    
    <h6 style="margin-top: 1em;">Level Up</h6>
    <div id="swp-levelup"></div>

    <h6 style="margin-top: 1em;">Autres</h6>
    <ul>
        <li><a href="javascript:void(0)" id="monsters-empty">Reset liste monstres</a></li>
    </ul>
    `;
  const autoAttackTable = buildAutoAttackTable();
  settingsBody.querySelector("#swp-autoattack")?.appendChild(autoAttackTable);
  const levelUpTable = buildLevelUpTable();
  settingsBody.querySelector("#swp-levelup")?.appendChild(levelUpTable);
  settingsBody.querySelector("#monsters-empty")?.addEventListener("click", () => {
    const ok = confirm("Voulez-vous enlever tous les monstres ajout\xE9s ?");
    if (ok) {
      SilverPexerSettings.setItem("monsterOptions", void 0);
      SilverPexerSettings.setItem("monster", void 0);
      refreshAutoAttack();
    }
  });
  settingsDiv.appendChild(settingsBody);
  return settingsDiv;
}

// src/options/addOptions.ts
function addOptions() {
  const messengerFixed = document.querySelector("#MessengerFixedController");
  if (!messengerFixed) {
    return;
  }
  const settingsDiv = buildSettings();
  const settingsImage = document.createElement("img");
  settingsImage.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/39/Icons8_flat_settings.svg/32px-Icons8_flat_settings.svg.png";
  settingsImage.className = "img-fluid";
  settingsImage.style.width = "24px";
  settingsImage.style.height = "24px";
  settingsImage.alt = "SilverPexer Settings";
  settingsImage.addEventListener("click", () => {
    if (settingsDiv.style.display === "none") {
      settingsDiv.style.display = "block";
    } else {
      settingsDiv.style.display = "none";
    }
  });
  const optionsDiv = document.createElement("div");
  optionsDiv.appendChild(settingsImage);
  const optionsListItem = document.createElement("li");
  optionsListItem.appendChild(optionsDiv);
  messengerFixed?.appendChild(settingsDiv);
  messengerFixed?.querySelector("ul")?.appendChild(optionsListItem);
}

// src/utils/loop.ts
async function loop(action, interval) {
  while (true) {
    try {
      await action();
    } catch (e) {
      console.error("loop error:", e);
    }
    await sleep(interval);
  }
}

// src/index.ts
(async function() {
  "use strict";
  addOptions();
  const groups = window.location.pathname.match(/^\/([^\/]+)(?:\/)?([^\/]+)?/);
  if (!groups) {
    console.warn("Could not parse pathname: ", window.location.pathname);
    return;
  }
  const [_path, page, _subPage] = groups;
  const plugins = [...config.plugins.default ?? [], ...config.plugins[page] ?? []];
  const oncePlugins = plugins.filter((p) => !p.loop);
  for (const plugin of oncePlugins) {
    await plugin.apply();
  }
  const loopPlugins = plugins.filter((p) => p.loop);
  await loop(async () => {
    for (const plugin of loopPlugins) {
      await plugin.apply();
    }
  }, config.loopInterval);
})().catch(console.error);