Silver-Pexer 2

XP automatique sur le jeu Silver-World

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

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