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