Item quality checker for Orna.RPG

Let you easily calculate item quality in official Orna Codex page.

目前为 2022-09-04 提交的版本。查看 最新版本

// ==UserScript==
// @name         Item quality checker for Orna.RPG
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Let you easily calculate item quality in official Orna Codex page.
// @author       You
// @match        https://playorna.com/codex/items/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=playorna.com
// @require      https://cdn.jsdelivr.net/npm/[email protected]
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// @license MIT
// ==/UserScript==

window.addEventListener('load', async function() {
  'use strict';
  let autoInit = GM_getValue('autoInit') || false;

  let t = (autoInit ? 'Disable ' : 'Enable ') + 'auto init.';
  GM_registerMenuCommand(t, toggleAutoInit, 'A');
  function toggleAutoInit() {
    autoInit = !autoInit;
    t = 'xxx'
    GM_setValue('autoInit', autoInit);
  }

  if (autoInit) {
    init();
  } else {
    document.querySelector('.codex-page-icon')?.addEventListener('dblclick', init, { once: true, });
  }

  async function init() {
    var s = document.createElement('script');
    s.setAttribute('src', 'https://cdn.jsdelivr.net/npm/[email protected]');
    document.body.appendChild(s);
    s.onload = scriptOnload;
  }
}, false);

async function scriptOnload() {
  let GUI = window.lil.GUI;
  let urlPath = location.href.match(/items\/([^/]+)/);
  let assessUrl = `https://orna.guide/search?searchstr=${urlPath?.[1].replace(/\W/g, ' ')}`;
  let gid = '';
  let data = {
    '%': 100,
    'assess_guide': () => { window.open(assessUrl, 'guide'); },
    'assess_api': () => { initAssess(gid); },
  }

  let div = document.createElement('div');
  div.id = 'gui-div';
  document.querySelector('.codex-stats').after(div);
  div.style = `display:flex;justify-content:center;flex-wrap:wrap;`;
  var gui = new GUI({
    autoPlace: false,
    container: div,
  });
  let stats = document.querySelectorAll('.codex-stat');
  stats.forEach(stat => {
    let info = stat.textContent.trim().match(/(\D+)(\d+)/);
    let p = info?.[1];
    let v = info?.[2];
    if (p) {
      data[p] = +v;
      gui.add(data, p, ~~(v * 0.7), v * 2, 1).onChange(_v => {
        quality.setValue(~~(100 * _v / +v))
      });
    }
  });
  let quality = gui.add(data, '%', 70, 200);

  let assessFolder = gui.addFolder( 'assess' );
  assessFolder.close();

  let assessOnGuide = assessFolder.add(data, 'assess_guide').name('Assess on Guide 🔍');

  gid = await getItemGID();
  if (gid) {
    assessUrl = `https://orna.guide/items?show=${gid}`;
    assessOnGuide.name('Assess on Guide ✔️');

    let assessByAPI = assessFolder.add(data, 'assess_api').name('Assess by myself!');
  }
}

function initAssess(gid) {
  if (window.assessInited) {
    return;
  }
  window.assessInited = true;

  let divForm = document.createElement('div');
  let resultBox = document.createElement('details');
  resultBox.style = 'width:100%';
  let optionsHtml = ['level', 'attack', 'defense', 'magic', 'resistance', 'hp', 'mana', 'dexterity', 'ward', 'crit', ]
    .map(i => genLabel(i)).join('');


  divForm.innerHTML = `
    <details open>
      <form id="assess-form" class="lil-gui">
        ${genLabel('id', gid, 'readonly')}
        ${optionsHtml}
        <div class="controller">
          <div class="widget"><input type="submit"></div>
          <div class="widget"></div>
          <div class="widget"><input type="reset"></div>
        </div>
      </form>
    </details>`;

  document.querySelector('#gui-div').appendChild(divForm);
  document.querySelector('#gui-div').appendChild(resultBox);

  let form = divForm.querySelector('#assess-form');
  form.addEventListener('submit', (e) => {
    e.preventDefault();
    const formData = {};
    for (const pair of new FormData(form)) {
      if (pair[1]) {
        formData[pair[0]] = +pair[1];
      }
    }

    fetch('https://orna.guide/api/v1/assess', {
      method: 'post',
      body: JSON.stringify(formData),
    }).then(r => r.json())
      .then(d => {
        console.log(111, d);
        resultBox.innerHTML = genAssessTable(d);
        resultBox.open = true;
      });
  });
}

function genAssessTable(data) {
  let stats = data.stats;
  let props = Object.keys(stats);

  let ths = props.map(prop => genTd(prop, 'th')).join('');

  let tbody = stats[props[0]].values.map((_i, index) => {
    let tds = props.map(prop => {
      return genTd(stats[prop].values[index]);
    }).join('');
    return `<tr>
      ${genTd(index + 1)}
      ${tds}
    </tr>`
  }).join('');

  props.map(prop => {
    stats[prop].values
  });

  return `
    <table style="margin:auto;text-transform:capitalize;">
      <caption>${data.quality * 100}%</caption>
      <style>details th {border-bottom:1px dotted #fff6;}</style>
      <tr>
        <th>Lv</th>
        ${ths}
      </tr>
      ${data.quality * 1 ? tbody : ''}
    </table>
  `;
}

function genTd(str, tag = 'td') {
  return `<${tag}>${str}</${tag}>`;
}

function genLabel(prop = '', value = '', attr) {
  return `
    <label class="controller number">
      <div class="name">${prop}</div>
      <div class="widget">
        <input type="number" value="${value}" name="${prop}" ${attr} />
      </div>
    </label>`;
}

async function getItemGID() {
  let name = await getTitle();
  if (!name) {
    return false;
  }
  let itemData = await postData('https://orna.guide/api/v1/item', {name});
  if (itemData?.length !== 1) {
    return false;
  }
  return itemData[0]?.id;
}

function postData(url, data) {
  return fetch(url, {
    method: 'POST',
    body: JSON.stringify(data)
  }).then(res => res.json());
}

function getEnURL() {
  let a = document.createElement('a');
  a.href = location.href;
  a.search = 'lang=en';
  a.href = 'https://api.codetabs.com/v1/proxy?quest=' + a.href;
  return a.href;
}

async function getTitle() {
  let html = await fetch(getEnURL()).then(res => res.text());
  let doc = document.implementation.createHTMLDocument();
  doc.body.innerHTML = html;
  let h1 = doc.querySelector('h1.herotext');
  return h1.textContent.trim();
}